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

import SwiftUI

struct ChargedDeviceDetailView: View {
    @EnvironmentObject private var appData: AppData
    @Environment(\.dismiss) private var dismiss
    @State private var editorVisibility = false
    @State private var checkpointEditorVisibility = false
    @State private var targetNotificationEditorVisibility = false
    @State private var pendingSessionDeletion: ChargeSessionSummary?
    @State private var pendingSessionStopRequest: DeviceSessionStopRequest?
    @State private var deleteConfirmationVisibility = false

    let chargedDeviceID: UUID

    var body: some View {
        Group {
            if let chargedDevice = appData.chargedDeviceSummary(id: chargedDeviceID) {
                ScrollView {
                    VStack(spacing: 18) {
                        headerCard(chargedDevice)
                        insightsCard(chargedDevice)

                        if let activeSession = chargedDevice.activeSession {
                            activeSessionCard(activeSession, chargedDevice: chargedDevice)
                        }

                        if let curveSession = preferredStoredCurveSession(for: chargedDevice) {
                            storedCurveCard(curveSession)
                        }

                        if !chargedDevice.capacityHistory.isEmpty {
                            capacityEvolutionCard(chargedDevice)
                        }

                        if !chargedDevice.typicalCurve.isEmpty {
                            typicalCurveCard(chargedDevice)
                        }

                        if !chargedDevice.sessions.isEmpty {
                            sessionsCard(chargedDevice)
                        }
                    }
                    .padding()
                }
                .background(
                    LinearGradient(
                        colors: [tint(for: chargedDevice).opacity(0.18), Color.clear],
                        startPoint: .topLeading,
                        endPoint: .bottomTrailing
                    )
                    .ignoresSafeArea()
                )
                .navigationTitle(chargedDevice.name)
                .toolbar {
                    ToolbarItemGroup(placement: .primaryAction) {
                        Button("Edit") {
                            editorVisibility = true
                        }
                        Button(role: .destructive) {
                            deleteConfirmationVisibility = true
                        } label: {
                            Image(systemName: "trash")
                        }
                    }
                }
            } else {
                Text("This device is no longer available.")
                    .foregroundColor(.secondary)
                    .navigationTitle("Device")
            }
        }
        .sheet(isPresented: $editorVisibility) {
            if let chargedDevice = appData.chargedDeviceSummary(id: chargedDeviceID) {
                ChargedDeviceEditorSheetView(
                    meterMACAddress: nil,
                    chargedDevice: chargedDevice
                )
                .environmentObject(appData)
            }
        }
        .sheet(isPresented: $checkpointEditorVisibility) {
            if let sessionID = appData.chargedDeviceSummary(id: chargedDeviceID)?.activeSession?.id {
                ChargedDeviceCheckpointEditorSheetView(sessionID: sessionID)
                    .environmentObject(appData)
            }
        }
        .sheet(isPresented: $targetNotificationEditorVisibility) {
            if let activeSession = appData.chargedDeviceSummary(id: chargedDeviceID)?.activeSession {
                ChargedDeviceTargetNotificationEditorSheetView(
                    sessionID: activeSession.id,
                    initialTargetPercent: activeSession.targetBatteryPercent
                )
                .environmentObject(appData)
            }
        }
        .sheet(item: $pendingSessionStopRequest) { request in
            ChargeSessionCompletionSheetView(
                sessionID: request.sessionID,
                title: request.title,
                confirmTitle: request.confirmTitle,
                explanation: request.explanation
            )
            .environmentObject(appData)
        }
        .alert(item: $pendingSessionDeletion) { session in
            Alert(
                title: Text("Delete Session?"),
                message: Text("Deleting this charging session also recalculates capacity and every derived metric that used it."),
                primaryButton: .destructive(Text("Delete")) {
                    _ = appData.deleteChargeSession(sessionID: session.id)
                },
                secondaryButton: .cancel()
            )
        }
        .confirmationDialog("Delete \(deletionTitle)?", isPresented: $deleteConfirmationVisibility, titleVisibility: .visible) {
            Button("Delete", role: .destructive) {
                if appData.deleteChargedDevice(id: chargedDeviceID) {
                    dismiss()
                }
            }
            Button("Cancel", role: .cancel) {}
        } message: {
            Text(deletionMessage)
        }
    }

    private func headerCard(_ chargedDevice: ChargedDeviceSummary) -> some View {
        HStack(alignment: .top, spacing: 18) {
            ChargedDeviceQRCodeView(qrIdentifier: chargedDevice.qrIdentifier, side: 118)

            VStack(alignment: .leading, spacing: 10) {
                Label(chargedDevice.name, systemImage: chargedDevice.deviceClass.symbolName)
                    .font(.title3.weight(.bold))

                Text(chargedDevice.deviceClass.title)
                    .font(.subheadline.weight(.semibold))
                    .foregroundColor(.secondary)

                if let meterMAC = chargedDevice.lastAssociatedMeterMAC {
                    Text("Default meter: \(meterMAC)")
                        .font(.caption)
                        .foregroundColor(.secondary)
                }

                Text(chargedDevice.qrIdentifier)
                    .font(.caption2.monospaced())
                    .foregroundColor(.secondary)
                    .textSelection(.enabled)
            }

            Spacer(minLength: 0)
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .padding(18)
        .meterCard(tint: tint(for: chargedDevice), fillOpacity: 0.20, strokeOpacity: 0.26, cornerRadius: 20)
    }

    private func insightsCard(_ chargedDevice: ChargedDeviceSummary) -> some View {
        MeterInfoCardView(title: "Insights", tint: tint(for: chargedDevice)) {
            MeterInfoRowView(
                label: "Charge Modes",
                value: chargedDevice.chargingStateAvailability.title
            )
            MeterInfoRowView(
                label: "Charging Support",
                value: chargedDevice.supportedChargingModes.map(\.title).joined(separator: " + ")
            )
            MeterInfoRowView(
                label: "Preferred Session Type",
                value: chargedDevice.preferredChargingTransportMode.title
            )
            if chargedDevice.supportsWirelessCharging {
                MeterInfoRowView(
                    label: "Wireless Profile",
                    value: chargedDevice.wirelessChargingProfile.title
                )
            }

            ForEach(completionSessionKinds(for: chargedDevice), id: \.rawValue) { sessionKind in
                MeterInfoRowView(
                    label: "\(sessionKind.shortTitle) Stop Current",
                    value: completionCurrentDescription(for: chargedDevice, sessionKind: sessionKind)
                )
            }
            MeterInfoRowView(
                label: "Estimated Capacity",
                value: chargedDevice.estimatedBatteryCapacityWh.map { "\($0.format(decimalDigits: 2)) Wh" } ?? "Not enough data"
            )
            if let wiredCapacity = chargedDevice.wiredEstimatedBatteryCapacityWh {
                MeterInfoRowView(
                    label: "Wired Capacity",
                    value: "\(wiredCapacity.format(decimalDigits: 2)) Wh"
                )
            }
            if let wirelessCapacity = chargedDevice.wirelessEstimatedBatteryCapacityWh {
                MeterInfoRowView(
                    label: "Wireless Capacity",
                    value: "\(wirelessCapacity.format(decimalDigits: 2)) Wh"
                )
            }
            if let wirelessEfficiencyFactor = chargedDevice.wirelessChargerEfficiencyFactor {
                MeterInfoRowView(
                    label: "Wireless Efficiency",
                    value: "\(Int((wirelessEfficiencyFactor * 100).rounded()))%"
                )
            }
            if chargedDevice.isCharger {
                Divider()
                if !chargedDevice.chargerObservedVoltageSelections.isEmpty {
                    MeterInfoRowView(
                        label: "Observed Voltages",
                        value: chargedDevice.chargerObservedVoltageSelections
                            .map { "\($0.format(decimalDigits: 1)) V" }
                            .joined(separator: ", ")
                    )
                }
                if let chargerIdleCurrentAmps = chargedDevice.chargerIdleCurrentAmps {
                    MeterInfoRowView(
                        label: "Idle Current",
                        value: "\(chargerIdleCurrentAmps.format(decimalDigits: 2)) A"
                    )
                }
                if let chargerEfficiencyFactor = chargedDevice.chargerEfficiencyFactor {
                    MeterInfoRowView(
                        label: "Efficiency",
                        value: "\(Int((chargerEfficiencyFactor * 100).rounded()))%"
                    )
                }
                if let chargerMaximumPowerWatts = chargedDevice.chargerMaximumPowerWatts {
                    MeterInfoRowView(
                        label: "Max Power",
                        value: "\(chargerMaximumPowerWatts.format(decimalDigits: 2)) W"
                    )
                }
                if chargedDevice.chargerIdleCurrentAmps == nil {
                    Text("Idle current is missing. Wireless sessions that use this charger can still be recorded, but they cannot learn or auto-apply the wireless stop threshold yet.")
                        .font(.caption2)
                        .foregroundColor(.orange)
                }
            }
            MeterInfoRowView(
                label: "End-of-Charge Current",
                value: chargedDevice.minimumCurrentAmps.map { "\($0.format(decimalDigits: 2)) A" } ?? "Learning"
            )
            MeterInfoRowView(
                label: "Charge Sessions",
                value: "\(chargedDevice.sessionCount)"
            )

            if let notes = chargedDevice.notes, !notes.isEmpty {
                Divider()
                Text(notes)
                    .font(.footnote)
                    .foregroundColor(.secondary)
                    .frame(maxWidth: .infinity, alignment: .leading)
            }
        }
    }

    private func activeSessionCard(
        _ activeSession: ChargeSessionSummary,
        chargedDevice: ChargedDeviceSummary
    ) -> some View {
        MeterInfoCardView(title: "Open Session", tint: .green) {
            MeterInfoRowView(label: "Started", value: activeSession.startedAt.format())
            MeterInfoRowView(label: "Status", value: activeSession.status.title)
            MeterInfoRowView(label: "Charging Type", value: activeSession.chargingTransportMode.title)
            MeterInfoRowView(label: "Charging Mode", value: activeSession.chargingStateMode.title)
            MeterInfoRowView(label: "Battery Energy", value: "\(activeSession.effectiveOrMeasuredEnergyWh.format(decimalDigits: 3)) Wh")
            if activeSession.chargingTransportMode == .wireless,
               let effectiveBatteryEnergyWh = activeSession.effectiveBatteryEnergyWh,
               abs(effectiveBatteryEnergyWh - activeSession.measuredEnergyWh) > 0.01 {
                MeterInfoRowView(label: "Charger Energy", value: "\(activeSession.measuredEnergyWh.format(decimalDigits: 3)) Wh")
            }
            MeterInfoRowView(label: "Charge", value: "\(activeSession.measuredChargeAh.format(decimalDigits: 3)) Ah")
            MeterInfoRowView(label: "Auto Stop", value: autoStopDescription(for: activeSession))
            MeterInfoRowView(label: "Source", value: activeSession.sourceMode.title)
            if chargedDevice.isCharger == false,
               let chargerID = activeSession.chargerID,
               let charger = appData.chargedDeviceSummary(id: chargerID) {
                MeterInfoRowView(label: "Wireless Charger", value: charger.name)
            }
            if let maximumObservedCurrentAmps = activeSession.maximumObservedCurrentAmps {
                MeterInfoRowView(label: "Max Current", value: "\(maximumObservedCurrentAmps.format(decimalDigits: 2)) A")
            }
            if let maximumObservedPowerWatts = activeSession.maximumObservedPowerWatts {
                MeterInfoRowView(label: "Max Power", value: "\(maximumObservedPowerWatts.format(decimalDigits: 2)) W")
            }
            if activeSession.chargingTransportMode == .wired,
               let maximumObservedVoltageVolts = activeSession.maximumObservedVoltageVolts {
                MeterInfoRowView(label: "Max Voltage", value: "\(maximumObservedVoltageVolts.format(decimalDigits: 2)) V")
            }
            if chargedDevice.isCharger, let selectedSourceVoltageVolts = activeSession.selectedSourceVoltageVolts {
                MeterInfoRowView(label: "Selected Voltage", value: "\(selectedSourceVoltageVolts.format(decimalDigits: 2)) V")
            }
            if let targetBatteryPercent = activeSession.targetBatteryPercent {
                MeterInfoRowView(
                    label: "Target Notification",
                    value: "\(targetBatteryPercent.format(decimalDigits: 0))%"
                )
            }
            if let sessionWarning = sessionWarning(for: activeSession) {
                Text(sessionWarning)
                    .font(.caption2)
                    .foregroundColor(.orange)
            }
            if let wirelessSessionHint = wirelessSessionHint(for: activeSession) {
                Text(wirelessSessionHint)
                    .font(.caption2)
                    .foregroundColor(activeSession.shouldWarnAboutLowWirelessEfficiency ? .orange : .secondary)
            }
            if let batteryPrediction = chargedDevice.batteryLevelPrediction(for: activeSession) {
                MeterInfoRowView(
                    label: "Predicted Battery",
                    value: "\(batteryPrediction.predictedPercent.format(decimalDigits: 0))%"
                )
                Text(
                    "Anchored to \(batteryPrediction.anchorDescription) at \(batteryPrediction.anchorPercent.format(decimalDigits: 0))% using \(batteryPrediction.estimatedCapacityWh.format(decimalDigits: 2)) Wh estimated capacity."
                )
                .font(.caption2)
                .foregroundColor(.secondary)
            }

            Button("Add Battery Checkpoint") {
                checkpointEditorVisibility = true
            }
            .frame(maxWidth: .infinity)
            .padding(.vertical, 10)
            .meterCard(tint: .green, fillOpacity: 0.16, strokeOpacity: 0.22, cornerRadius: 14)
            .buttonStyle(.plain)

            Button(activeSession.targetBatteryPercent == nil ? "Set Target Notification" : "Change Target Notification") {
                targetNotificationEditorVisibility = true
            }
            .frame(maxWidth: .infinity)
            .padding(.vertical, 10)
            .meterCard(tint: .indigo, fillOpacity: 0.16, strokeOpacity: 0.22, cornerRadius: 14)
            .buttonStyle(.plain)

            if activeSession.targetBatteryPercent != nil {
                Button("Clear Target Notification") {
                    _ = appData.setTargetBatteryPercent(nil, for: activeSession.id)
                }
                .frame(maxWidth: .infinity)
                .padding(.vertical, 10)
                .meterCard(tint: .secondary, fillOpacity: 0.12, strokeOpacity: 0.18, cornerRadius: 14)
                .buttonStyle(.plain)
            }

            if activeSession.status == .active {
                Button("Pause Session") {
                    _ = appData.pauseChargeSession(sessionID: activeSession.id)
                }
                .frame(maxWidth: .infinity)
                .padding(.vertical, 10)
                .meterCard(tint: .orange, fillOpacity: 0.16, strokeOpacity: 0.22, cornerRadius: 14)
                .buttonStyle(.plain)
            } else if activeSession.status == .paused {
                Button("Resume Session") {
                    _ = appData.resumeChargeSession(sessionID: activeSession.id)
                }
                .frame(maxWidth: .infinity)
                .padding(.vertical, 10)
                .meterCard(tint: .blue, fillOpacity: 0.16, strokeOpacity: 0.22, cornerRadius: 14)
                .buttonStyle(.plain)

                Text("Paused sessions close automatically after 10 minutes.")
                    .font(.caption2)
                    .foregroundColor(.secondary)
            }

            Button(activeSession.requiresCompletionConfirmation ? "Finish Session With Checkpoint" : "Stop Session") {
                pendingSessionStopRequest = DeviceSessionStopRequest(
                    sessionID: activeSession.id,
                    title: activeSession.requiresCompletionConfirmation ? "Finish Session" : "Stop Session",
                    confirmTitle: activeSession.requiresCompletionConfirmation ? "Finish" : "Stop",
                    explanation: "Add the final battery checkpoint before closing this session."
                )
            }
            .frame(maxWidth: .infinity)
            .padding(.vertical, 10)
            .meterCard(tint: .red, fillOpacity: 0.16, strokeOpacity: 0.22, cornerRadius: 14)
            .buttonStyle(.plain)

            if activeSession.requiresCompletionConfirmation {
                Divider()
                if let contradictionPercent = activeSession.completionContradictionPercent {
                    Text("Current says charging may have stopped, but the estimated battery level is only \(contradictionPercent.format(decimalDigits: 0))%.")
                        .font(.caption2)
                        .foregroundColor(.secondary)
                }

                Button("Keep Monitoring") {
                    _ = appData.continueChargeSessionMonitoring(sessionID: activeSession.id)
                }
                .frame(maxWidth: .infinity)
                .padding(.vertical, 10)
                .meterCard(tint: .blue, fillOpacity: 0.16, strokeOpacity: 0.22, cornerRadius: 14)
                .buttonStyle(.plain)
            }
        }
    }

    private func capacityEvolutionCard(_ chargedDevice: ChargedDeviceSummary) -> some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Capacity Evolution")
                .font(.headline)

            ForEach(chargedDevice.capacityHistory.suffix(6)) { point in
                HStack {
                    Text(point.timestamp.format())
                        .font(.caption)
                        .foregroundColor(.secondary)
                    Spacer()
                    Text(point.chargingTransportMode.title)
                        .font(.caption2)
                        .foregroundColor(.secondary)
                    Text("•")
                        .foregroundColor(.secondary)
                    Text("\(point.capacityWh.format(decimalDigits: 2)) Wh")
                        .font(.footnote.weight(.semibold))
                }
            }
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .padding(18)
        .meterCard(tint: .orange, fillOpacity: 0.14, strokeOpacity: 0.20, cornerRadius: 18)
    }

    private func preferredStoredCurveSession(for chargedDevice: ChargedDeviceSummary) -> ChargeSessionSummary? {
        if let activeSession = chargedDevice.activeSession, !activeSession.aggregatedSamples.isEmpty {
            return activeSession
        }

        return chargedDevice.sessions.first(where: { !$0.aggregatedSamples.isEmpty })
    }

    private func storedCurveCard(_ session: ChargeSessionSummary) -> some View {
        let currentSeries = storedSeriesSnapshot(
            from: session.aggregatedSamples,
            minimumYSpan: 0.15
        ) { $0.averageCurrentAmps }
        let energySeries = storedSeriesSnapshot(
            from: session.aggregatedSamples,
            minimumYSpan: 0.2
        ) { $0.measuredEnergyWh }

        return VStack(alignment: .leading, spacing: 14) {
            HStack(alignment: .firstTextBaseline) {
                VStack(alignment: .leading, spacing: 4) {
                    Text("Stored Session Curve")
                        .font(.headline)
                    Text(session.status.isOpen ? "Open session, persisted as aggregated samples." : "Most recent persisted session at aggregated resolution.")
                        .font(.caption)
                        .foregroundColor(.secondary)
                }

                Spacer()

                Text("\(session.aggregatedSamples.count) points")
                    .font(.caption.weight(.semibold))
                    .foregroundColor(.secondary)
            }

            if let currentSeries {
                storedSeriesChart(
                    title: "Current",
                    unit: "A",
                    strokeColor: .blue,
                    snapshot: currentSeries
                )
            }

            if let energySeries {
                storedSeriesChart(
                    title: "Energy",
                    unit: "Wh",
                    strokeColor: .teal,
                    areaChart: true,
                    snapshot: energySeries
                )
            }

            Text("Database storage and iCloud sync use 300 aggregated points per hour. The live recording session still keeps the original in-memory samples while charging is in progress.")
                .font(.caption)
                .foregroundColor(.secondary)
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .padding(18)
        .meterCard(tint: .indigo, fillOpacity: 0.12, strokeOpacity: 0.18, cornerRadius: 18)
    }

    private func typicalCurveCard(_ chargedDevice: ChargedDeviceSummary) -> some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Typical Charge Curve")
                .font(.headline)

            ForEach(chargedDevice.typicalCurve) { point in
                HStack {
                    Text("\(point.percentBin)%")
                        .font(.footnote.weight(.semibold))
                    Spacer()
                    Text("\(point.averageEnergyWh.format(decimalDigits: 2)) Wh")
                        .font(.caption.weight(.semibold))
                    Text("•")
                        .foregroundColor(.secondary)
                    Text("\(point.sampleCount) sample\(point.sampleCount == 1 ? "" : "s")")
                        .font(.caption2)
                        .foregroundColor(.secondary)
                }
            }
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .padding(18)
        .meterCard(tint: .blue, fillOpacity: 0.14, strokeOpacity: 0.20, cornerRadius: 18)
    }

    private func sessionsCard(_ chargedDevice: ChargedDeviceSummary) -> some View {
        VStack(alignment: .leading, spacing: 12) {
            Text("Charge Sessions")
                .font(.headline)

            Text("Use these summaries to spot odd sessions quickly before they influence device estimates.")
                .font(.caption)
                .foregroundColor(.secondary)

            ForEach(chargedDevice.sessions, id: \.id) { session in
                VStack(alignment: .leading, spacing: 6) {
                    HStack(alignment: .firstTextBaseline, spacing: 10) {
                        Text(session.startedAt.format())
                            .font(.caption.weight(.semibold))
                        Text(session.status.title)
                            .font(.caption2.weight(.semibold))
                            .padding(.horizontal, 8)
                            .padding(.vertical, 4)
                            .background(
                                Capsule()
                                    .fill(statusTint(for: session).opacity(0.16))
                            )
                        Spacer()
                        Button {
                            pendingSessionDeletion = session
                        } label: {
                            Image(systemName: "trash")
                                .font(.caption.weight(.semibold))
                                .foregroundColor(.red)
                                .padding(8)
                                .background(
                                    Circle()
                                        .fill(Color.red.opacity(0.10))
                                )
                        }
                        .buttonStyle(.plain)
                    }

                    Text(sessionSummaryLine(session))
                        .font(.caption2)
                        .foregroundColor(.secondary)

                    MeterInfoRowView(
                        label: "Duration",
                        value: sessionDurationText(session)
                    )
                    MeterInfoRowView(
                        label: "Energy",
                        value: "\(session.effectiveOrMeasuredEnergyWh.format(decimalDigits: 2)) Wh"
                    )
                    if session.chargingTransportMode == .wireless,
                       let effectiveBatteryEnergyWh = session.effectiveBatteryEnergyWh,
                       abs(effectiveBatteryEnergyWh - session.measuredEnergyWh) > 0.01 {
                        MeterInfoRowView(
                            label: "Charger Energy",
                            value: "\(session.measuredEnergyWh.format(decimalDigits: 2)) Wh"
                        )
                    }
                    if let maximumObservedCurrentAmps = session.maximumObservedCurrentAmps {
                        MeterInfoRowView(
                            label: "Max Current",
                            value: "\(maximumObservedCurrentAmps.format(decimalDigits: 2)) A"
                        )
                    }
                    if let maximumObservedPowerWatts = session.maximumObservedPowerWatts {
                        MeterInfoRowView(
                            label: "Max Power",
                            value: "\(maximumObservedPowerWatts.format(decimalDigits: 2)) W"
                        )
                    }
                    if session.chargingTransportMode == .wired,
                       let maximumObservedVoltageVolts = session.maximumObservedVoltageVolts {
                        MeterInfoRowView(
                            label: "Max Voltage",
                            value: "\(maximumObservedVoltageVolts.format(decimalDigits: 2)) V"
                        )
                    }
                    if chargedDevice.isCharger, let selectedSourceVoltageVolts = session.selectedSourceVoltageVolts {
                        MeterInfoRowView(
                            label: "Selected Voltage",
                            value: "\(selectedSourceVoltageVolts.format(decimalDigits: 2)) V"
                        )
                    }
                    if let selectedDataGroup = session.selectedDataGroup {
                        MeterInfoRowView(
                            label: "Data Group",
                            value: "#\(selectedDataGroup)"
                        )
                    }
                    if chargedDevice.isCharger == false,
                       let chargerID = session.chargerID,
                       let charger = appData.chargedDeviceSummary(id: chargerID) {
                        MeterInfoRowView(
                            label: "Wireless Charger",
                            value: charger.name
                        )
                    }
                    if let wirelessSessionHint = wirelessSessionHint(for: session) {
                        Text(wirelessSessionHint)
                            .font(.caption2)
                            .foregroundColor(session.shouldWarnAboutLowWirelessEfficiency ? .orange : .secondary)
                    }
                }
                .padding(14)
                .meterCard(
                    tint: statusTint(for: session),
                    fillOpacity: 0.10,
                    strokeOpacity: 0.16,
                    cornerRadius: 16
                )
            }
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .padding(18)
        .meterCard(tint: .teal, fillOpacity: 0.14, strokeOpacity: 0.20, cornerRadius: 18)
    }

    private func sessionSummaryLine(_ session: ChargeSessionSummary) -> String {
        var components: [String] = []

        if let batteryDeltaPercent = session.batteryDeltaPercent {
            components.append("\(batteryDeltaPercent.format(decimalDigits: 0))%")
        }

        if let capacityEstimateWh = session.capacityEstimateWh {
            components.append("\(capacityEstimateWh.format(decimalDigits: 2)) Wh capacity")
        }

        components.append(session.chargingTransportMode.title)
        components.append(session.chargingStateMode.title)
        components.append(session.sourceMode.title)
        return components.joined(separator: " • ")
    }

    private func wirelessSessionHint(for session: ChargeSessionSummary) -> String? {
        guard session.chargingTransportMode == .wireless else {
            return nil
        }

        var components: [String] = []
        if let wirelessEfficiencyFactor = session.wirelessEfficiencyFactor {
            components.append("Efficiency \(Int((wirelessEfficiencyFactor * 100).rounded()))%")
        }
        if session.usesEstimatedWirelessEfficiency {
            components.append("Estimated from wired baseline and checkpoints")
        }
        if session.shouldWarnAboutLowWirelessEfficiency {
            components.append("Low wireless efficiency, so capacity confidence is reduced")
        }

        return components.isEmpty ? nil : components.joined(separator: " • ")
    }

    private func sessionDurationText(_ session: ChargeSessionSummary) -> String {
        let formatter = DateComponentsFormatter()
        formatter.allowedUnits = session.duration >= 3600 ? [.hour, .minute] : [.minute, .second]
        formatter.unitsStyle = .abbreviated
        formatter.zeroFormattingBehavior = .dropAll
        return formatter.string(from: max(session.duration, 0)) ?? "0m"
    }

    private func statusTint(for session: ChargeSessionSummary) -> Color {
        switch session.status {
        case .active:
            return .green
        case .paused:
            return .orange
        case .completed:
            return .teal
        case .abandoned:
            return .secondary
        }
    }

    private func tint(for chargedDevice: ChargedDeviceSummary) -> Color {
        switch chargedDevice.deviceClass {
        case .iphone:
            return .blue
        case .watch:
            return .green
        case .powerbank:
            return .orange
        case .charger:
            return .pink
        case .other:
            return .secondary
        }
    }

    private func completionCurrentDescription(
        for chargedDevice: ChargedDeviceSummary,
        sessionKind: ChargeSessionKind
    ) -> String {
        if let configuredCurrent = chargedDevice.configuredCompletionCurrentAmps(for: sessionKind) {
            if let learnedCurrent = chargedDevice.learnedCompletionCurrentAmps(for: sessionKind),
               abs(configuredCurrent - learnedCurrent) >= 0.01 {
                return "\(configuredCurrent.format(decimalDigits: 2)) A configured • \(learnedCurrent.format(decimalDigits: 2)) A learned"
            }
            return "\(configuredCurrent.format(decimalDigits: 2)) A configured"
        }

        if let learnedCurrent = chargedDevice.learnedCompletionCurrentAmps(for: sessionKind) {
            return "\(learnedCurrent.format(decimalDigits: 2)) A learned"
        }

        return "Learning"
    }

    private func completionSessionKinds(for chargedDevice: ChargedDeviceSummary) -> [ChargeSessionKind] {
        chargedDevice.supportedChargingModes.flatMap { chargingTransportMode in
            chargedDevice.supportedChargingStateModes.map { chargingStateMode in
                ChargeSessionKind(
                    chargingTransportMode: chargingTransportMode,
                    chargingStateMode: chargingStateMode
                )
            }
        }
    }

    private func autoStopDescription(for session: ChargeSessionSummary) -> String {
        if session.autoStopEnabled == false {
            return "Manual"
        }

        if let sessionWarning = sessionWarning(for: session),
           sessionWarning.contains("idle-current") {
            return "Blocked by charger setup"
        }

        if session.stopThresholdAmps > 0 {
            return "\(session.stopThresholdAmps.format(decimalDigits: 2)) A"
        }

        return "Learning"
    }

    private func sessionWarning(for session: ChargeSessionSummary) -> String? {
        guard session.chargingTransportMode == .wireless,
              let chargerID = session.chargerID,
              let charger = appData.chargedDeviceSummary(id: chargerID),
              charger.chargerIdleCurrentAmps == nil else {
            return nil
        }

        return "This charger has no idle-current measurement, so the wireless stop threshold cannot be learned or auto-applied for this session."
    }

    private var deletionTitle: String {
        appData.chargedDeviceSummary(id: chargedDeviceID)?.isCharger == true ? "charger" : "device"
    }

    private var deletionMessage: String {
        if appData.chargedDeviceSummary(id: chargedDeviceID)?.isCharger == true {
            return "This removes the charger from the library and unlinks it from wireless sessions that used it."
        }
        return "This removes the device and its stored charging history from the library."
    }

    private func storedSeriesSnapshot(
        from samples: [ChargeSessionSampleSummary],
        minimumYSpan: Double,
        value: (ChargeSessionSampleSummary) -> Double
    ) -> StoredSeriesSnapshot? {
        let sortedSamples = samples.sorted { lhs, rhs in
            if lhs.bucketIndex != rhs.bucketIndex {
                return lhs.bucketIndex < rhs.bucketIndex
            }
            return lhs.timestamp < rhs.timestamp
        }

        guard
            let firstSample = sortedSamples.first,
            let lastSample = sortedSamples.last
        else {
            return nil
        }

        let points = sortedSamples.enumerated().map { index, sample in
            Measurements.Measurement.Point(
                id: index,
                timestamp: sample.timestamp,
                value: value(sample),
                kind: .sample
            )
        }

        let minimumValue = points.map(\.value).min() ?? 0
        let maximumValue = points.map(\.value).max() ?? minimumValue
        let context = ChartContext()
        context.setBounds(
            xMin: CGFloat(firstSample.timestamp.timeIntervalSince1970),
            xMax: CGFloat(max(lastSample.timestamp.timeIntervalSince1970, firstSample.timestamp.timeIntervalSince1970 + 1)),
            yMin: CGFloat(minimumValue),
            yMax: CGFloat(maximumValue)
        )
        context.ensureMinimumSize(width: 1, height: CGFloat(max(maximumValue - minimumValue, minimumYSpan)))

        return StoredSeriesSnapshot(
            points: points,
            context: context,
            minimumValue: minimumValue,
            maximumValue: maximumValue
        )
    }

    private func storedSeriesChart(
        title: String,
        unit: String,
        strokeColor: Color,
        areaChart: Bool = false,
        snapshot: StoredSeriesSnapshot
    ) -> some View {
        VStack(alignment: .leading, spacing: 8) {
            HStack(alignment: .firstTextBaseline) {
                Text(title)
                    .font(.subheadline.weight(.semibold))
                Spacer()
                Text(
                    "Latest \(snapshot.lastValue.format(decimalDigits: 2)) \(unit) • \(snapshot.minimumValue.format(decimalDigits: 2))-\(snapshot.maximumValue.format(decimalDigits: 2)) \(unit)"
                )
                .font(.caption2)
                .foregroundColor(.secondary)
            }

            Chart(
                points: snapshot.points,
                context: snapshot.context,
                areaChart: areaChart,
                strokeColor: strokeColor
            )
            .frame(height: 118)
            .padding(.horizontal, 6)
            .padding(.vertical, 8)
            .background(
                RoundedRectangle(cornerRadius: 16)
                    .fill(strokeColor.opacity(areaChart ? 0.08 : 0.06))
            )

            HStack {
                Text(snapshot.startLabel)
                Spacer()
                Text(snapshot.endLabel)
            }
            .font(.caption2)
            .foregroundColor(.secondary)
        }
    }
}

private struct StoredSeriesSnapshot {
    let points: [Measurements.Measurement.Point]
    let context: ChartContext
    let minimumValue: Double
    let maximumValue: Double

    var lastValue: Double {
        points.last?.value ?? 0
    }

    var startLabel: String {
        guard let firstTimestamp = points.first?.timestamp else { return "" }
        return firstTimestamp.formatted(date: .omitted, time: .shortened)
    }

    var endLabel: String {
        guard let lastTimestamp = points.last?.timestamp else { return "" }
        return lastTimestamp.formatted(date: .omitted, time: .shortened)
    }
}

private struct ChargedDeviceCheckpointEditorSheetView: View {
    @Environment(\.dismiss) private var dismiss
    @EnvironmentObject private var appData: AppData

    let sessionID: UUID

    @State private var batteryPercent = ""
    @State private var label = ""

    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("Checkpoint")) {
                    TextField("Battery %", text: $batteryPercent)
                        .keyboardType(.decimalPad)
                    TextField("Label (optional)", text: $label)
                }

                Section {
                    Text("The checkpoint is stored on the active charge session and is used for capacity estimation and charge-level prediction.")
                        .font(.footnote)
                        .foregroundColor(.secondary)
                }
            }
            .navigationTitle("Battery Checkpoint")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Cancel") {
                        dismiss()
                    }
                }

                ToolbarItem(placement: .confirmationAction) {
                    Button("Save") {
                        guard let percent = Double(batteryPercent) else {
                            return
                        }

                        if appData.addBatteryCheckpoint(percent: percent, label: label, for: sessionID) {
                            dismiss()
                        }
                    }
                    .disabled(
                        (Double(batteryPercent) ?? -1) < 0
                            || (Double(batteryPercent) ?? 101) > 100
                    )
                }
            }
        }
        .navigationViewStyle(StackNavigationViewStyle())
    }
}

private struct ChargedDeviceTargetNotificationEditorSheetView: View {
    @Environment(\.dismiss) private var dismiss
    @EnvironmentObject private var appData: AppData

    let sessionID: UUID
    let initialTargetPercent: Double?

    @State private var targetPercent: Double

    init(sessionID: UUID, initialTargetPercent: Double?) {
        self.sessionID = sessionID
        self.initialTargetPercent = initialTargetPercent
        _targetPercent = State(initialValue: initialTargetPercent ?? 80)
    }

    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("Target Level")) {
                    VStack(alignment: .leading, spacing: 12) {
                        Text("\(targetPercent.format(decimalDigits: 0))%")
                            .font(.title3.weight(.bold))
                        Slider(value: $targetPercent, in: 20...100, step: 1)
                        Text("A local notification will be generated on synced devices when the estimated battery level reaches this target.")
                            .font(.footnote)
                            .foregroundColor(.secondary)
                    }
                }
            }
            .navigationTitle("Battery Target")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Cancel") {
                        dismiss()
                    }
                }

                ToolbarItem(placement: .confirmationAction) {
                    Button("Save") {
                        if appData.setTargetBatteryPercent(targetPercent, for: sessionID) {
                            dismiss()
                        }
                    }
                }
            }
        }
        .navigationViewStyle(StackNavigationViewStyle())
    }
}

private struct DeviceSessionStopRequest: Identifiable {
    let sessionID: UUID
    let title: String
    let confirmTitle: String
    let explanation: String

    var id: UUID {
        sessionID
    }
}
