//
//  ChargeInsightsModel.swift
//  USB Meter
//
//  Created by Codex on 10/04/2026.
//

import Foundation

enum ChargedDeviceKind: String, Identifiable {
    case device
    case charger

    var id: String { rawValue }

    var title: String {
        switch self {
        case .device:
            return "Device"
        case .charger:
            return "Charger"
        }
    }

    var pluralTitle: String {
        switch self {
        case .device:
            return "Devices"
        case .charger:
            return "Chargers"
        }
    }

    var symbolName: String {
        switch self {
        case .device:
            return "iphone"
        case .charger:
            return "bolt.horizontal.circle"
        }
    }
}

enum ChargedDeviceClass: String, CaseIterable, Identifiable {
    case iphone
    case watch
    case powerbank
    case charger
    case other

    var id: String { rawValue }

    static var deviceCases: [ChargedDeviceClass] {
        allCases.filter { $0 != .charger }
    }

    var kind: ChargedDeviceKind {
        self == .charger ? .charger : .device
    }

    var title: String {
        switch self {
        case .iphone:
            return "iPhone"
        case .watch:
            return "Watch"
        case .powerbank:
            return "Powerbank"
        case .charger:
            return "Charger"
        case .other:
            return "Other"
        }
    }

    var symbolName: String {
        switch self {
        case .iphone:
            return "iphone"
        case .watch:
            return "applewatch"
        case .powerbank:
            return "battery.100.bolt"
        case .charger:
            return "bolt.badge.clock"
        case .other:
            return "shippingbox"
        }
    }
}

enum ChargeSessionStatus: String {
    case active
    case paused
    case completed
    case abandoned

    var title: String {
        switch self {
        case .active:
            return "Active"
        case .paused:
            return "Paused"
        case .completed:
            return "Completed"
        case .abandoned:
            return "Abandoned"
        }
    }

    var isOpen: Bool {
        switch self {
        case .active, .paused:
            return true
        case .completed, .abandoned:
            return false
        }
    }
}

enum ChargeSessionSourceMode: String {
    case live
    case offline
    case blended

    var title: String {
        switch self {
        case .live:
            return "Live"
        case .offline:
            return "Offline Counters"
        case .blended:
            return "Blended"
        }
    }
}

enum ChargingTransportMode: String, CaseIterable, Identifiable, Codable {
    case wired
    case wireless

    var id: String { rawValue }

    var title: String {
        switch self {
        case .wired:
            return "Wired"
        case .wireless:
            return "Wireless"
        }
    }

    var symbolName: String {
        switch self {
        case .wired:
            return "cable.connector"
        case .wireless:
            return "dot.radiowaves.left.and.right"
        }
    }
}

enum ChargingStateMode: String, CaseIterable, Identifiable, Codable {
    case on
    case off

    var id: String { rawValue }

    var title: String {
        switch self {
        case .on:
            return "On"
        case .off:
            return "Off"
        }
    }

    var description: String {
        switch self {
        case .on:
            return "Device stays powered on while charging."
        case .off:
            return "Device is powered off while charging."
        }
    }
}

enum ChargingStateAvailability: String, CaseIterable, Identifiable, Codable {
    case onOnly
    case onOrOff
    case offOnly

    var id: String { rawValue }

    var title: String {
        switch self {
        case .onOnly:
            return "On Only"
        case .onOrOff:
            return "On or Off"
        case .offOnly:
            return "Off Only"
        }
    }

    var description: String {
        switch self {
        case .onOnly:
            return "The device can be recorded only while it is powered on."
        case .onOrOff:
            return "The session must specify whether the device is on or off."
        case .offOnly:
            return "The device can be recorded only while it is powered off."
        }
    }

    var supportedModes: [ChargingStateMode] {
        switch self {
        case .onOnly:
            return [.on]
        case .onOrOff:
            return [.on, .off]
        case .offOnly:
            return [.off]
        }
    }

    var supportsMultipleModes: Bool {
        supportedModes.count > 1
    }

    var supportsChargingWhileOff: Bool {
        self != .onOnly
    }

    static func fallback(for supportsChargingWhileOff: Bool) -> ChargingStateAvailability {
        supportsChargingWhileOff ? .onOrOff : .onOnly
    }
}

enum ChargeSessionKind: String, CaseIterable, Identifiable, Codable, Hashable {
    case wiredOn
    case wiredOff
    case wirelessOn
    case wirelessOff

    var id: String { rawValue }

    init(chargingTransportMode: ChargingTransportMode, chargingStateMode: ChargingStateMode) {
        switch (chargingTransportMode, chargingStateMode) {
        case (.wired, .on):
            self = .wiredOn
        case (.wired, .off):
            self = .wiredOff
        case (.wireless, .on):
            self = .wirelessOn
        case (.wireless, .off):
            self = .wirelessOff
        }
    }

    var chargingTransportMode: ChargingTransportMode {
        switch self {
        case .wiredOn, .wiredOff:
            return .wired
        case .wirelessOn, .wirelessOff:
            return .wireless
        }
    }

    var chargingStateMode: ChargingStateMode {
        switch self {
        case .wiredOn, .wirelessOn:
            return .on
        case .wiredOff, .wirelessOff:
            return .off
        }
    }

    var title: String {
        "\(chargingTransportMode.title) • \(chargingStateMode.title)"
    }

    var shortTitle: String {
        "\(chargingTransportMode.title) \(chargingStateMode.title)"
    }
}

enum WirelessChargingProfile: String, CaseIterable, Identifiable {
    case magsafe
    case genericQi

    var id: String { rawValue }

    var title: String {
        switch self {
        case .magsafe:
            return "MagSafe"
        case .genericQi:
            return "Generic Qi"
        }
    }

    var description: String {
        switch self {
        case .magsafe:
            return "Use separate wireless-efficiency calibration from devices that also have reliable wired capacity."
        case .genericQi:
            return "Use only automatic efficiency estimates and show a low-efficiency warning when needed."
        }
    }
}

struct ChargeCheckpointSummary: Identifiable, Hashable {
    let id: UUID
    let sessionID: UUID
    let chargedDeviceID: UUID
    let timestamp: Date
    let batteryPercent: Double
    let measuredEnergyWh: Double
    let measuredChargeAh: Double
    let currentAmps: Double
    let voltageVolts: Double?
    let label: String?

    var flag: ChargeCheckpointFlag {
        ChargeCheckpointFlag.fromStoredLabel(label)
    }
}

enum ChargeCheckpointFlag: String, CaseIterable {
    case initial
    case intermediate
    case final

    var title: String {
        switch self {
        case .initial:
            return "Initial"
        case .intermediate:
            return "Intermediate"
        case .final:
            return "Final"
        }
    }

    var anchorDescription: String {
        switch self {
        case .initial:
            return "initial checkpoint"
        case .intermediate:
            return "intermediate checkpoint"
        case .final:
            return "final checkpoint"
        }
    }

    static func fromStoredLabel(_ label: String?) -> ChargeCheckpointFlag {
        let normalized = label?
            .trimmingCharacters(in: .whitespacesAndNewlines)
            .lowercased()

        switch normalized {
        case "initial", "start":
            return .initial
        case "final", "end":
            return .final
        case "intermediate", nil, "":
            return .intermediate
        default:
            return .intermediate
        }
    }
}

struct ChargeSessionSampleSummary: Identifiable, Hashable {
    let sessionID: UUID
    let chargedDeviceID: UUID
    let bucketIndex: Int
    let timestamp: Date
    let averageCurrentAmps: Double
    let averageVoltageVolts: Double?
    let averagePowerWatts: Double
    let measuredEnergyWh: Double
    let measuredChargeAh: Double
    let sampleCount: Int

    var id: String {
        "\(sessionID.uuidString)-\(bucketIndex)"
    }
}

struct ChargeSessionSummary: Identifiable, Hashable {
    let id: UUID
    let chargedDeviceID: UUID
    let chargerID: UUID?
    let meterMACAddress: String?
    let meterName: String?
    let meterModel: String?
    let startedAt: Date
    let endedAt: Date?
    let lastObservedAt: Date
    let pausedAt: Date?
    let status: ChargeSessionStatus
    let sourceMode: ChargeSessionSourceMode
    let chargingTransportMode: ChargingTransportMode
    let chargingStateMode: ChargingStateMode
    let autoStopEnabled: Bool
    let measuredEnergyWh: Double
    let effectiveBatteryEnergyWh: Double?
    let measuredChargeAh: Double
    let meterEnergyBaselineWh: Double?
    let meterChargeBaselineAh: Double?
    let meterDurationBaselineSeconds: Double?
    let meterLastDurationSeconds: Double?
    let minimumObservedCurrentAmps: Double?
    let maximumObservedCurrentAmps: Double?
    let maximumObservedPowerWatts: Double?
    let maximumObservedVoltageVolts: Double?
    let selectedSourceVoltageVolts: Double?
    let completionCurrentAmps: Double?
    let stopThresholdAmps: Double
    let startBatteryPercent: Double?
    let endBatteryPercent: Double?
    let capacityEstimateWh: Double?
    let wirelessEfficiencyFactor: Double?
    let usesEstimatedWirelessEfficiency: Bool
    let shouldWarnAboutLowWirelessEfficiency: Bool
    let supportsChargingWhileOff: Bool
    let usedOfflineMeterCounters: Bool
    let targetBatteryPercent: Double?
    let targetBatteryAlertTriggeredAt: Date?
    let requiresCompletionConfirmation: Bool
    let completionConfirmationRequestedAt: Date?
    let completionContradictionPercent: Double?
    let selectedDataGroup: UInt8?
    let checkpoints: [ChargeCheckpointSummary]
    let aggregatedSamples: [ChargeSessionSampleSummary]

    var sessionKind: ChargeSessionKind {
        ChargeSessionKind(
            chargingTransportMode: chargingTransportMode,
            chargingStateMode: chargingStateMode
        )
    }

    var duration: TimeInterval {
        (endedAt ?? lastObservedAt).timeIntervalSince(startedAt)
    }

    var meterObservedDuration: TimeInterval? {
        guard let meterDurationBaselineSeconds, let meterLastDurationSeconds else {
            return nil
        }
        guard meterLastDurationSeconds >= meterDurationBaselineSeconds else {
            return nil
        }
        return meterLastDurationSeconds - meterDurationBaselineSeconds
    }

    var effectiveDuration: TimeInterval {
        meterObservedDuration ?? duration
    }

    var effectiveOrMeasuredEnergyWh: Double {
        effectiveBatteryEnergyWh ?? measuredEnergyWh
    }

    var batteryDeltaPercent: Double? {
        guard let startBatteryPercent, let endBatteryPercent,
              startBatteryPercent >= 0, endBatteryPercent >= 0 else { return nil }
        return endBatteryPercent - startBatteryPercent
    }

    var canAutoStop: Bool {
        autoStopEnabled && stopThresholdAmps > 0
    }

    var isPaused: Bool {
        status == .paused
    }

    var isOpen: Bool {
        status.isOpen
    }
}

struct BatteryLevelPrediction: Hashable {
    let predictedPercent: Double
    let estimatedCapacityWh: Double
    let anchorPercent: Double
    let anchorEnergyWh: Double
    let anchorDescription: String
}

enum BatteryLevelPredictionTuning {
    static let checkpointSettleDuration: TimeInterval = 10 * 60

    static func predictedPercent(
        anchorPercent: Double,
        anchorEnergyWh: Double,
        anchorTimestamp: Date,
        anchorIsCheckpoint: Bool,
        effectiveEnergyWh: Double,
        referenceTimestamp: Date,
        estimatedCapacityWh: Double
    ) -> Double {
        let energyDeltaWh = max(effectiveEnergyWh - anchorEnergyWh, 0)
        let rawGainPercent = (energyDeltaWh / estimatedCapacityWh) * 100
        let stabilizedGainPercent: Double

        if anchorIsCheckpoint {
            let elapsedSinceAnchor = max(referenceTimestamp.timeIntervalSince(anchorTimestamp), 0)
            let settleProgress = min(max(elapsedSinceAnchor / checkpointSettleDuration, 0), 1)
            stabilizedGainPercent = rawGainPercent * settleProgress
        } else {
            stabilizedGainPercent = rawGainPercent
        }

        return min(
            100,
            max(
                0,
                anchorPercent + stabilizedGainPercent
            )
        )
    }
}

struct CapacityTrendPoint: Identifiable, Hashable {
    let sessionID: UUID
    let timestamp: Date
    let capacityWh: Double
    let chargingTransportMode: ChargingTransportMode

    var id: UUID { sessionID }
}

struct TypicalChargeCurvePoint: Identifiable, Hashable {
    let percentBin: Int
    let averageEnergyWh: Double
    let averageChargeAh: Double
    let sampleCount: Int

    var id: Int { percentBin }
}

struct ChargerStandbyPowerSample: Identifiable, Hashable, Codable {
    let timestamp: Date
    let powerWatts: Double
    let currentAmps: Double
    let voltageVolts: Double

    var id: TimeInterval {
        timestamp.timeIntervalSince1970
    }
}

struct ChargerStandbyPowerDistributionBin: Identifiable, Hashable {
    let index: Int
    let lowerBoundWatts: Double
    let upperBoundWatts: Double
    let count: Int
    let relativeFrequency: Double

    var id: Int { index }
}

struct ChargerStandbyPowerMeasurementStatistics: Hashable {
    let sampleCount: Int
    let observedDuration: TimeInterval
    let averagePowerWatts: Double
    let recentAveragePowerWatts: Double
    let medianPowerWatts: Double
    let minimumPowerWatts: Double
    let maximumPowerWatts: Double
    let standardDeviationPowerWatts: Double
    let coefficientOfVariation: Double
    let averageCurrentAmps: Double
    let averageVoltageVolts: Double
    let stabilityDeltaWatts: Double
    let stabilityToleranceWatts: Double
    let histogram: [ChargerStandbyPowerDistributionBin]

    var projectedDailyEnergyWh: Double {
        averagePowerWatts * 24
    }

    var projectedWeeklyEnergyWh: Double {
        averagePowerWatts * 24 * 7
    }

    var projectedMonthlyEnergyWh: Double {
        averagePowerWatts * 24 * 30
    }

    var projectedYearlyEnergyWh: Double {
        averagePowerWatts * 24 * 365
    }

    var stabilityDeltaMilliwatts: Double {
        stabilityDeltaWatts * 1000
    }

    var isStable: Bool {
        sampleCount >= ChargerStandbyPowerMeasurementAnalyzer.minimumStableSampleCount
        && stabilityDeltaWatts <= stabilityToleranceWatts
    }
}

struct ChargerStandbyPowerMeasurementSummary: Identifiable, Hashable, Codable {
    let id: UUID
    let chargerID: UUID
    let meterMACAddress: String
    let meterName: String?
    let meterModel: String?
    let startedAt: Date
    let endedAt: Date
    let sampleCount: Int
    let stabilizedAt: Date?
    let averagePowerWatts: Double
    let recentAveragePowerWatts: Double
    let medianPowerWatts: Double
    let minimumPowerWatts: Double
    let maximumPowerWatts: Double
    let standardDeviationPowerWatts: Double
    let coefficientOfVariation: Double
    let averageCurrentAmps: Double
    let averageVoltageVolts: Double
    let stabilityDeltaWatts: Double
    let stabilityToleranceWatts: Double
    let powerSamplesWatts: [Double]

    var duration: TimeInterval {
        endedAt.timeIntervalSince(startedAt)
    }

    var projectedDailyEnergyWh: Double {
        averagePowerWatts * 24
    }

    var projectedWeeklyEnergyWh: Double {
        averagePowerWatts * 24 * 7
    }

    var projectedMonthlyEnergyWh: Double {
        averagePowerWatts * 24 * 30
    }

    var projectedYearlyEnergyWh: Double {
        averagePowerWatts * 24 * 365
    }

    var isStable: Bool {
        stabilizedAt != nil
    }

    var histogram: [ChargerStandbyPowerDistributionBin] {
        ChargerStandbyPowerMeasurementAnalyzer.histogram(for: powerSamplesWatts)
    }
}

enum ChargerStandbyPowerMeasurementAnalyzer {
    static let minimumStableSampleCount = 45
    static let recentSampleWindow = 20
    static let minimumStabilityToleranceWatts = 0.003
    static let relativeStabilityTolerance = 0.01

    static func statistics(
        from samples: [ChargerStandbyPowerSample],
        startedAt: Date,
        referenceDate: Date = Date()
    ) -> ChargerStandbyPowerMeasurementStatistics? {
        guard !samples.isEmpty else {
            return nil
        }

        let powerValues = samples.map(\.powerWatts).filter(\.isFinite)
        let currentValues = samples.map(\.currentAmps).filter(\.isFinite)
        let voltageValues = samples.map(\.voltageVolts).filter(\.isFinite)

        guard powerValues.isEmpty == false else {
            return nil
        }

        let averagePower = mean(powerValues)
        let recentWindow = min(recentSampleWindow, max(1, powerValues.count))
        let recentAveragePower = mean(Array(powerValues.suffix(recentWindow)))
        let stabilityDelta = abs(averagePower - recentAveragePower)
        let stabilityTolerance = max(
            minimumStabilityToleranceWatts,
            abs(averagePower) * relativeStabilityTolerance
        )

        return ChargerStandbyPowerMeasurementStatistics(
            sampleCount: powerValues.count,
            observedDuration: max(referenceDate.timeIntervalSince(startedAt), 0),
            averagePowerWatts: averagePower,
            recentAveragePowerWatts: recentAveragePower,
            medianPowerWatts: median(powerValues),
            minimumPowerWatts: powerValues.min() ?? 0,
            maximumPowerWatts: powerValues.max() ?? 0,
            standardDeviationPowerWatts: standardDeviation(powerValues, mean: averagePower),
            coefficientOfVariation: coefficientOfVariation(powerValues, mean: averagePower),
            averageCurrentAmps: mean(currentValues),
            averageVoltageVolts: mean(voltageValues),
            stabilityDeltaWatts: stabilityDelta,
            stabilityToleranceWatts: stabilityTolerance,
            histogram: histogram(for: powerValues)
        )
    }

    static func measurementSummary(
        chargerID: UUID,
        meterMACAddress: String,
        meterName: String?,
        meterModel: String?,
        startedAt: Date,
        endedAt: Date,
        samples: [ChargerStandbyPowerSample],
        stabilizedAt: Date?
    ) -> ChargerStandbyPowerMeasurementSummary? {
        guard let statistics = statistics(from: samples, startedAt: startedAt, referenceDate: endedAt) else {
            return nil
        }

        return ChargerStandbyPowerMeasurementSummary(
            id: UUID(),
            chargerID: chargerID,
            meterMACAddress: meterMACAddress,
            meterName: meterName,
            meterModel: meterModel,
            startedAt: startedAt,
            endedAt: endedAt,
            sampleCount: statistics.sampleCount,
            stabilizedAt: stabilizedAt,
            averagePowerWatts: statistics.averagePowerWatts,
            recentAveragePowerWatts: statistics.recentAveragePowerWatts,
            medianPowerWatts: statistics.medianPowerWatts,
            minimumPowerWatts: statistics.minimumPowerWatts,
            maximumPowerWatts: statistics.maximumPowerWatts,
            standardDeviationPowerWatts: statistics.standardDeviationPowerWatts,
            coefficientOfVariation: statistics.coefficientOfVariation,
            averageCurrentAmps: statistics.averageCurrentAmps,
            averageVoltageVolts: statistics.averageVoltageVolts,
            stabilityDeltaWatts: statistics.stabilityDeltaWatts,
            stabilityToleranceWatts: statistics.stabilityToleranceWatts,
            powerSamplesWatts: samples.map(\.powerWatts)
        )
    }

    static func histogram(for values: [Double], preferredBinCount: Int? = nil) -> [ChargerStandbyPowerDistributionBin] {
        let finiteValues = values.filter(\.isFinite)
        guard finiteValues.isEmpty == false else {
            return []
        }

        let minimum = finiteValues.min() ?? 0
        let maximum = finiteValues.max() ?? 0
        let spread = maximum - minimum
        let binCount = preferredBinCount ?? min(18, max(8, Int(Double(finiteValues.count).squareRoot().rounded())))

        guard spread > 0 else {
            return [
                ChargerStandbyPowerDistributionBin(
                    index: 0,
                    lowerBoundWatts: minimum,
                    upperBoundWatts: maximum,
                    count: finiteValues.count,
                    relativeFrequency: 1
                )
            ]
        }

        let safeBinCount = max(1, binCount)
        let binWidth = spread / Double(safeBinCount)
        var counts = Array(repeating: 0, count: safeBinCount)

        for value in finiteValues {
            let normalizedIndex = Int(((value - minimum) / binWidth).rounded(.down))
            let safeIndex = min(max(normalizedIndex, 0), safeBinCount - 1)
            counts[safeIndex] += 1
        }

        return counts.enumerated().map { index, count in
            let lowerBound = minimum + (Double(index) * binWidth)
            let upperBound = index == safeBinCount - 1 ? maximum : lowerBound + binWidth

            return ChargerStandbyPowerDistributionBin(
                index: index,
                lowerBoundWatts: lowerBound,
                upperBoundWatts: upperBound,
                count: count,
                relativeFrequency: Double(count) / Double(finiteValues.count)
            )
        }
    }

    private static func mean(_ values: [Double]) -> Double {
        guard values.isEmpty == false else {
            return 0
        }
        return values.reduce(0, +) / Double(values.count)
    }

    private static func median(_ values: [Double]) -> Double {
        guard values.isEmpty == false else {
            return 0
        }

        let sorted = values.sorted()
        let middleIndex = sorted.count / 2

        if sorted.count.isMultiple(of: 2) {
            return (sorted[middleIndex - 1] + sorted[middleIndex]) / 2
        }

        return sorted[middleIndex]
    }

    private static func standardDeviation(_ values: [Double], mean: Double) -> Double {
        guard values.count > 1 else {
            return 0
        }

        let variance = values.reduce(0) { partialResult, value in
            let delta = value - mean
            return partialResult + (delta * delta)
        } / Double(values.count)

        return variance.squareRoot()
    }

    private static func coefficientOfVariation(_ values: [Double], mean: Double) -> Double {
        guard abs(mean) > 0.000_001 else {
            return 0
        }

        return standardDeviation(values, mean: mean) / abs(mean)
    }
}

struct ChargedDeviceSummary: Identifiable, Hashable {
    let id: UUID
    let qrIdentifier: String
    let name: String
    let deviceClass: ChargedDeviceClass
    let supportsChargingWhileOff: Bool
    let chargingStateAvailability: ChargingStateAvailability
    let supportsWiredCharging: Bool
    let supportsWirelessCharging: Bool
    let wirelessChargingProfile: WirelessChargingProfile
    let configuredCompletionCurrents: [ChargeSessionKind: Double]
    let learnedCompletionCurrents: [ChargeSessionKind: Double]
    let wirelessChargerEfficiencyFactor: Double?
    let wiredChargeCompletionCurrentAmps: Double?
    let wirelessChargeCompletionCurrentAmps: Double?
    let chargerObservedVoltageSelections: [Double]
    let chargerIdleCurrentAmps: Double?
    let chargerEfficiencyFactor: Double?
    let chargerMaximumPowerWatts: Double?
    let notes: String?
    let minimumCurrentAmps: Double?
    let estimatedBatteryCapacityWh: Double?
    let wiredMinimumCurrentAmps: Double?
    let wirelessMinimumCurrentAmps: Double?
    let wiredEstimatedBatteryCapacityWh: Double?
    let wirelessEstimatedBatteryCapacityWh: Double?
    let lastAssociatedMeterMAC: String?
    let createdAt: Date
    let updatedAt: Date
    let sessions: [ChargeSessionSummary]
    let capacityHistory: [CapacityTrendPoint]
    let typicalCurve: [TypicalChargeCurvePoint]
    let standbyPowerMeasurements: [ChargerStandbyPowerMeasurementSummary]

    var isCharger: Bool {
        deviceClass == .charger
    }

    var kind: ChargedDeviceKind {
        deviceClass.kind
    }

    var identityTitle: String {
        isCharger ? kind.title : deviceClass.title
    }

    var identitySymbolName: String {
        isCharger ? kind.symbolName : deviceClass.symbolName
    }

    var activeSession: ChargeSessionSummary? {
        sessions.first(where: \.isOpen)
    }

    var recentCompletedSessions: [ChargeSessionSummary] {
        sessions.filter { $0.status == .completed }
    }

    var sessionCount: Int {
        sessions.count
    }

    var latestStandbyPowerMeasurement: ChargerStandbyPowerMeasurementSummary? {
        standbyPowerMeasurements.first
    }

    var supportedChargingModes: [ChargingTransportMode] {
        var modes: [ChargingTransportMode] = []
        if supportsWiredCharging {
            modes.append(.wired)
        }
        if supportsWirelessCharging {
            modes.append(.wireless)
        }
        return modes
    }

    var supportedChargingStateModes: [ChargingStateMode] {
        chargingStateAvailability.supportedModes
    }

    func defaultChargingStateMode(for chargingTransportMode: ChargingTransportMode) -> ChargingStateMode {
        if let matchingSession = sessions.first(where: {
            $0.status.isOpen && $0.chargingTransportMode == chargingTransportMode
        }) {
            return matchingSession.chargingStateMode
        }
        return chargingStateAvailability.supportedModes.first ?? .on
    }

    func sessionKind(
        for chargingTransportMode: ChargingTransportMode,
        chargingStateMode: ChargingStateMode? = nil
    ) -> ChargeSessionKind {
        ChargeSessionKind(
            chargingTransportMode: chargingTransportMode,
            chargingStateMode: chargingStateMode ?? defaultChargingStateMode(for: chargingTransportMode)
        )
    }

    func estimatedBatteryCapacityWh(for chargingTransportMode: ChargingTransportMode) -> Double? {
        switch chargingTransportMode {
        case .wired:
            return wiredEstimatedBatteryCapacityWh
        case .wireless:
            return wirelessEstimatedBatteryCapacityWh
        }
    }

    func minimumCurrentAmps(for chargingTransportMode: ChargingTransportMode) -> Double? {
        switch chargingTransportMode {
        case .wired:
            return wiredMinimumCurrentAmps
        case .wireless:
            return wirelessMinimumCurrentAmps
        }
    }

    func configuredCompletionCurrentAmps(for sessionKind: ChargeSessionKind) -> Double? {
        if let explicitCurrent = configuredCompletionCurrents[sessionKind] {
            return explicitCurrent
        }

        switch sessionKind.chargingTransportMode {
        case .wired:
            return wiredChargeCompletionCurrentAmps
        case .wireless:
            return wirelessChargeCompletionCurrentAmps
        }
    }

    func learnedCompletionCurrentAmps(for sessionKind: ChargeSessionKind) -> Double? {
        if let learnedCurrent = learnedCompletionCurrents[sessionKind] {
            return learnedCurrent
        }

        switch sessionKind.chargingTransportMode {
        case .wired:
            return wiredMinimumCurrentAmps ?? minimumCurrentAmps
        case .wireless:
            return wirelessMinimumCurrentAmps ?? minimumCurrentAmps
        }
    }

    func resolvedCompletionCurrentAmps(
        for chargingTransportMode: ChargingTransportMode,
        chargingStateMode: ChargingStateMode? = nil
    ) -> Double? {
        let sessionKind = sessionKind(
            for: chargingTransportMode,
            chargingStateMode: chargingStateMode
        )

        return configuredCompletionCurrentAmps(for: sessionKind)
            ?? learnedCompletionCurrentAmps(for: sessionKind)
            ?? minimumCurrentAmps(for: chargingTransportMode)
            ?? minimumCurrentAmps
    }

    func batteryLevelPrediction(
        for session: ChargeSessionSummary,
        effectiveEnergyWhOverride: Double? = nil
    ) -> BatteryLevelPrediction? {
        let estimatedCapacityWh = session.capacityEstimateWh
            ?? estimatedBatteryCapacityWh(for: session.chargingTransportMode)
            ?? estimatedBatteryCapacityWh

        guard let estimatedCapacityWh, estimatedCapacityWh > 0 else {
            return nil
        }

        let effectiveEnergyWh = effectiveEnergyWhOverride
            ?? session.effectiveBatteryEnergyWh
            ?? session.measuredEnergyWh

        struct Anchor {
            let percent: Double
            let energyWh: Double
            let timestamp: Date
            let description: String
            let isCheckpoint: Bool
        }

        var anchors: [Anchor] = []

        if let startBatteryPercent = session.startBatteryPercent, startBatteryPercent >= 0 {
            anchors.append(
                Anchor(
                    percent: startBatteryPercent,
                    energyWh: 0,
                    timestamp: session.startedAt,
                    description: "session start",
                    isCheckpoint: false
                )
            )
        }

        anchors.append(
            contentsOf: session.checkpoints
                .sorted { lhs, rhs in
                    if lhs.measuredEnergyWh != rhs.measuredEnergyWh {
                        return lhs.measuredEnergyWh < rhs.measuredEnergyWh
                    }
                    return lhs.timestamp < rhs.timestamp
                }
                .filter { checkpoint in
                    checkpoint.batteryPercent >= 0
                }
                .map { checkpoint in
                    return Anchor(
                        percent: checkpoint.batteryPercent,
                        energyWh: checkpoint.measuredEnergyWh,
                        timestamp: checkpoint.timestamp,
                        description: checkpoint.flag.anchorDescription,
                        isCheckpoint: true
                    )
                }
        )

        guard !anchors.isEmpty else {
            return nil
        }

        let eligibleAnchors = anchors.filter { $0.energyWh <= effectiveEnergyWh + 0.05 }
        let anchor = eligibleAnchors.last ?? anchors.first!
        let predictedPercent = BatteryLevelPredictionTuning.predictedPercent(
            anchorPercent: anchor.percent,
            anchorEnergyWh: anchor.energyWh,
            anchorTimestamp: anchor.timestamp,
            anchorIsCheckpoint: anchor.isCheckpoint,
            effectiveEnergyWh: effectiveEnergyWh,
            referenceTimestamp: session.lastObservedAt,
            estimatedCapacityWh: estimatedCapacityWh
        )

        return BatteryLevelPrediction(
            predictedPercent: predictedPercent,
            estimatedCapacityWh: estimatedCapacityWh,
            anchorPercent: anchor.percent,
            anchorEnergyWh: anchor.energyWh,
            anchorDescription: anchor.description
        )
    }

    func withStandbyPowerMeasurements(_ measurements: [ChargerStandbyPowerMeasurementSummary]) -> ChargedDeviceSummary {
        ChargedDeviceSummary(
            id: id,
            qrIdentifier: qrIdentifier,
            name: name,
            deviceClass: deviceClass,
            supportsChargingWhileOff: supportsChargingWhileOff,
            chargingStateAvailability: chargingStateAvailability,
            supportsWiredCharging: supportsWiredCharging,
            supportsWirelessCharging: supportsWirelessCharging,
            wirelessChargingProfile: wirelessChargingProfile,
            configuredCompletionCurrents: configuredCompletionCurrents,
            learnedCompletionCurrents: learnedCompletionCurrents,
            wirelessChargerEfficiencyFactor: wirelessChargerEfficiencyFactor,
            wiredChargeCompletionCurrentAmps: wiredChargeCompletionCurrentAmps,
            wirelessChargeCompletionCurrentAmps: wirelessChargeCompletionCurrentAmps,
            chargerObservedVoltageSelections: chargerObservedVoltageSelections,
            chargerIdleCurrentAmps: chargerIdleCurrentAmps,
            chargerEfficiencyFactor: chargerEfficiencyFactor,
            chargerMaximumPowerWatts: chargerMaximumPowerWatts,
            notes: notes,
            minimumCurrentAmps: minimumCurrentAmps,
            estimatedBatteryCapacityWh: estimatedBatteryCapacityWh,
            wiredMinimumCurrentAmps: wiredMinimumCurrentAmps,
            wirelessMinimumCurrentAmps: wirelessMinimumCurrentAmps,
            wiredEstimatedBatteryCapacityWh: wiredEstimatedBatteryCapacityWh,
            wirelessEstimatedBatteryCapacityWh: wirelessEstimatedBatteryCapacityWh,
            lastAssociatedMeterMAC: lastAssociatedMeterMAC,
            createdAt: createdAt,
            updatedAt: updatedAt,
            sessions: sessions,
            capacityHistory: capacityHistory,
            typicalCurve: typicalCurve,
            standbyPowerMeasurements: measurements
        )
    }
}

struct ChargingMonitorSnapshot {
    let meterMACAddress: String
    let meterName: String
    let meterModel: String
    let observedAt: Date
    let voltageVolts: Double
    let currentAmps: Double
    let powerWatts: Double
    let selectedDataGroup: UInt8?
    let meterChargeCounterAh: Double?
    let meterEnergyCounterWh: Double?
    let meterRecordingDurationSeconds: TimeInterval?
    let fallbackStopThresholdAmps: Double
}
