import SwiftUI

struct BatteriesView: View {
    @Binding var editMode: EditMode
    let system: ElectricalSystem
    let batteries: [SavedBattery]
    let onEdit: (SavedBattery) -> Void
    let onDelete: (IndexSet) -> Void

    private enum BankStatus: Identifiable {
        case voltage(target: Double, mismatchedCount: Int)
        case capacity(target: Double, mismatchedCount: Int)

        var id: String {
            switch self {
            case .voltage: return "voltage"
            case .capacity: return "capacity"
            }
        }

        var symbol: String {
            switch self {
            case .voltage: return "exclamationmark.triangle.fill"
            case .capacity: return "exclamationmark.circle.fill"
            }
        }

        var tint: Color {
            switch self {
            case .voltage: return .red
            case .capacity: return .orange
            }
        }

        var bannerText: String {
            switch self {
            case .voltage:
                return String(
                    localized: "battery.bank.banner.voltage",
                    bundle: .main,
                    comment: "Short banner text describing a voltage mismatch"
                )
            case .capacity:
                return String(
                    localized: "battery.bank.banner.capacity",
                    bundle: .main,
                    comment: "Short banner text describing a capacity mismatch"
                )
            }
        }
    }

    private let voltageTolerance: Double = 0.05
    private let capacityTolerance: Double = 0.5
    @State private var activeStatus: BankStatus?

    private var bankTitle: String {
        String(
            localized: "battery.bank.header.title",
            bundle: .main,
            comment: "Title for the battery bank summary section"
        )
    }

    private var metricCountLabel: String {
        String(
            localized: "battery.bank.metric.count",
            bundle: .main,
            comment: "Label for number of batteries metric"
        )
    }

    private var metricCapacityLabel: String {
        String(
            localized: "battery.bank.metric.capacity",
            bundle: .main,
            comment: "Label for total capacity metric"
        )
    }

    private var metricEnergyLabel: String {
        String(
            localized: "battery.bank.metric.energy",
            bundle: .main,
            comment: "Label for total energy metric"
        )
    }

    private var metricUsableCapacityLabel: String {
        String(
            localized: "battery.bank.metric.usable_capacity",
            bundle: .main,
            comment: "Label for usable capacity metric"
        )
    }

    private var badgeVoltageLabel: String {
        String(
            localized: "battery.bank.badge.voltage",
            bundle: .main,
            comment: "Label for voltage badge"
        )
    }

    private var badgeCapacityLabel: String {
        String(
            localized: "battery.bank.badge.capacity",
            bundle: .main,
            comment: "Label for capacity badge"
        )
    }

    private var badgeEnergyLabel: String {
        String(
            localized: "battery.bank.badge.energy",
            bundle: .main,
            comment: "Label for energy badge"
        )
    }

    private var badgeUsableCapacityLabel: String {
        String(
            localized: "battery.bank.metric.usable_capacity",
            bundle: .main,
            comment: "Label for usable capacity badge"
        )
    }

    private var emptyTitle: String {
        String(
            localized: "battery.bank.empty.title",
            bundle: .main,
            comment: "Title shown when no batteries are configured"
        )
    }

    init(
        system: ElectricalSystem,
        batteries: [SavedBattery],
        editMode: Binding<EditMode> = .constant(.inactive),
        onEdit: @escaping (SavedBattery) -> Void = { _ in },
        onDelete: @escaping (IndexSet) -> Void = { _ in }
    ) {
        self.system = system
        self.batteries = batteries
        self.onEdit = onEdit
        self.onDelete = onDelete
        self._editMode = editMode
    }

    var body: some View {
        VStack(spacing: 0) {
            if batteries.isEmpty {
                emptyState
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
            } else {
                batteriesListWithHeader
            }
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color(.systemGroupedBackground))
        .alert(item: $activeStatus) { status in
            let detail = detailInfo(for: status)
            return Alert(
                title: Text(detail.title),
                message: Text(detail.message),
                dismissButton: .default(
                    Text(
                        String(
                            localized: "battery.bank.status.dismiss",
                            defaultValue: "Got it"
                        )
                    )
                )
            )
        }
    }

    private var batteryStatsHeader: some View {
        StatsHeaderContainer {
            batterySummaryContent
        }
    }

    private var batterySummaryContent: some View {
        VStack(spacing: 0) {
            VStack(alignment: .leading, spacing: 10) {
                HStack(alignment: .firstTextBaseline) {
                    Text(bankTitle)
                        .font(.headline.weight(.semibold))
                    Spacer()
                }

                ScrollView(.horizontal, showsIndicators: false) {
                    HStack(spacing: 16) {
                        ForEach(Array(summaryMetrics.enumerated()), id: \.offset) { _, metric in
                            summaryMetric(icon: metric.icon, label: metric.label, value: metric.value, tint: metric.tint)
                        }
                    }
                    .padding(.horizontal, 2)
                }
                .scrollClipDisabled(false)

                if let status = bankStatus {
                    Button {
                        activeStatus = status
                    } label: {
                        statusBanner(for: status)
                    }
                    .buttonStyle(.plain)
                }
            }

        }
    }

    @ViewBuilder
    private var batteriesListWithHeader: some View {
        if #available(iOS 26.0, *) {
            baseBatteriesList
                .scrollEdgeEffectStyle(.soft, for: .top)
                .safeAreaInset(edge: .top, spacing: 0) {
                    batteryStatsHeader
                }
        } else {
            baseBatteriesList
                .safeAreaInset(edge: .top, spacing: 0) {
                    batteryStatsHeader
                }
        }
    }

    private var baseBatteriesList: some View {
        List {
            ForEach(batteries) { battery in
                Button {
                    onEdit(battery)
                } label: {
                    batteryRow(for: battery)
                }
                .buttonStyle(.plain)
                .disabled(editMode == .active)
                .listRowInsets(.init(top: 12, leading: 16, bottom: 12, trailing: 16))
                .listRowSeparator(.hidden)
                .listRowBackground(Color.clear)
            }
            .onDelete(perform: onDelete)
        }
        .listStyle(.plain)
        .scrollContentBackground(.hidden)
        .environment(\.editMode, $editMode)
        .accessibilityIdentifier("batteries-list")
    }

    private func batteryRow(for battery: SavedBattery) -> some View {
        VStack(alignment: .leading, spacing: 14) {
            HStack(spacing: 12) {
                batteryIcon(for: battery)

                VStack(alignment: .leading, spacing: 4) {
                    HStack(alignment: .firstTextBaseline) {
                        Text(battery.name)
                            .font(.body.weight(.medium))
                            .lineLimit(1)
                            .truncationMode(.tail)
                        Spacer()
                        Text(formattedValue(battery.nominalVoltage, unit: "V"))
                            .font(.subheadline)
                            .foregroundStyle(.secondary)
                    }

                    Text(battery.chemistry.displayName)
                        .font(.caption.weight(.medium))
                        .foregroundStyle(.secondary)
                        .padding(.horizontal, 8)
                        .padding(.vertical, 4)
                        .background(
                            Capsule(style: .continuous)
                                .fill(Color(.tertiarySystemBackground))
                        )
                }
                Spacer()
                Image(systemName: "chevron.right")
                    .font(.system(size: 14, weight: .semibold))
                    .foregroundStyle(.secondary)
            }

            batteryMetricsScroll(for: battery)
        }
        .padding(.vertical, 16)
        .padding(.horizontal, 16)
        .background(
            RoundedRectangle(cornerRadius: 18, style: .continuous)
                .fill(Color(.systemBackground))
        )
    }

    private func batteryIcon(for battery: SavedBattery) -> some View {
        ZStack {
            RoundedRectangle(cornerRadius: 12, style: .continuous)
                .fill(Color.componentColor(named: battery.colorName))
                .frame(width: 48, height: 48)
            Image(systemName: battery.iconName.isEmpty ? "battery.100.bolt" : battery.iconName)
                .font(.system(size: 22, weight: .semibold))
                .foregroundStyle(Color.white)
        }
    }

    private var totalCapacity: Double {
        batteries.reduce(0) { result, battery in
            result + battery.capacityAmpHours
        }
    }

    private var totalEnergy: Double {
        batteries.reduce(0) { result, battery in
            result + battery.energyWattHours
        }
    }

    private var totalUsableCapacity: Double {
        batteries.reduce(0) { result, battery in
            result + battery.usableCapacityAmpHours
        }
    }

    private var totalUsableCapacityShare: Double {
        guard totalCapacity > 0 else { return 0 }
        return max(0, min(1, totalUsableCapacity / totalCapacity))
    }

    private func usableFraction(for battery: SavedBattery) -> Double {
        guard battery.capacityAmpHours > 0 else { return 0 }
        return max(0, min(1, battery.usableCapacityAmpHours / battery.capacityAmpHours))
    }

    private func usableCapacityDisplay(for battery: SavedBattery) -> String {
        let fraction = usableFraction(for: battery)
        return "\(formattedValue(battery.usableCapacityAmpHours, unit: "Ah")) (\(formattedPercentage(fraction)))"
    }

    private func summaryMetric(icon: String, label: String, value: String, tint: Color) -> some View {
        ComponentSummaryMetricView(
            icon: icon,
            label: label,
            value: value,
            tint: tint
        )
    }

    private var summaryMetrics: [(icon: String, label: String, value: String, tint: Color)] {
        [
            (
                icon: "battery.100",
                label: metricCountLabel,
                value: "\(batteries.count)",
                tint: .blue
            ),
            (
                icon: "gauge.medium",
                label: metricCapacityLabel,
                value: formattedValue(totalCapacity, unit: "Ah"),
                tint: .orange
            ),
            (
                icon: "battery.100.bolt",
                label: metricUsableCapacityLabel,
                value: "\(formattedValue(totalUsableCapacity, unit: "Ah")) (\(formattedPercentage(totalUsableCapacityShare)))",
                tint: .purple
            ),
            (
                icon: "bolt.circle",
                label: metricEnergyLabel,
                value: formattedValue(totalEnergy, unit: "Wh"),
                tint: .green
            )
        ]
    }

    @ViewBuilder
    private func batteryMetricsScroll(for battery: SavedBattery) -> some View {
        let badges: [(String, String, Color)] = [
            (badgeVoltageLabel, formattedValue(battery.nominalVoltage, unit: "V"), .orange),
            (badgeCapacityLabel, formattedValue(battery.capacityAmpHours, unit: "Ah"), .blue),
            (badgeUsableCapacityLabel, usableCapacityDisplay(for: battery), .purple),
            (badgeEnergyLabel, formattedValue(battery.energyWattHours, unit: "Wh"), .green)
        ]

        ScrollView(.horizontal, showsIndicators: false) {
            HStack(spacing: 12) {
                ForEach(Array(badges.enumerated()), id: \.offset) { _, badge in
                    ComponentMetricBadgeView(label: badge.0, value: badge.1, tint: badge.2)
                }
            }
            .padding(.horizontal, 2)
        }
        .scrollClipDisabled(false)
    }

    private func metricBadge(label: String, value: String, tint: Color) -> some View {
        ComponentMetricBadgeView(
            label: label,
            value: value,
            tint: tint
        )
    }

    private func statusBanner(for status: BankStatus) -> some View {
        HStack(spacing: 10) {
            Image(systemName: status.symbol)
                .font(.system(size: 16, weight: .semibold))
                .foregroundStyle(status.tint)
            Text(status.bannerText)
                .font(.subheadline.weight(.semibold))
                .foregroundStyle(status.tint)
            Spacer()
        }
        .padding(.horizontal, 12)
        .padding(.vertical, 10)
        .background(
            RoundedRectangle(cornerRadius: 14, style: .continuous)
                .fill(status.tint.opacity(0.12))
        )
    }

    private var emptyState: some View {
        VStack(spacing: 16) {
            Image(systemName: "battery.100")
                .font(.largeTitle)
                .foregroundStyle(.secondary)

            Text(emptyTitle)
                .font(.title3)
                .fontWeight(.semibold)

            Text(emptySubtitle(for: system.name))
                .font(.subheadline)
                .foregroundStyle(.secondary)
                .multilineTextAlignment(.center)
        }
        .padding()
    }

    private static let numberFormatter: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.locale = .current
        formatter.minimumFractionDigits = 0
        formatter.maximumFractionDigits = 1
        return formatter
    }()

    private func formattedValue(_ value: Double, unit: String) -> String {
        let numberString = Self.numberFormatter.string(from: NSNumber(value: value)) ?? String(format: "%.1f", value)
        return "\(numberString) \(unit)"
    }

    private func formattedPercentage(_ fraction: Double) -> String {
        let clamped = max(0, min(1, fraction))
        let percent = clamped * 100
        let numberString = Self.numberFormatter.string(from: NSNumber(value: percent)) ?? String(format: "%.1f", percent)
        return "\(numberString) %"
    }

    private var dominantVoltage: Double? {
        guard batteries.count > 1 else { return nil }
        return dominantValue(
            from: batteries.map { $0.nominalVoltage },
            scale: 0.1
        )
    }

    private var dominantCapacity: Double? {
        guard batteries.count > 1 else { return nil }
        return dominantValue(
            from: batteries.map { $0.capacityAmpHours },
            scale: 1.0
        )
    }

    private func dominantValue(from values: [Double], scale: Double) -> Double? {
        guard !values.isEmpty else { return nil }
        var counts: [Double: Int] = [:]
        var bestKey: Double?
        var bestCount = 0
        for value in values {
            let key = (value / scale).rounded() * scale
            let newCount = (counts[key] ?? 0) + 1
            counts[key] = newCount
            if newCount > bestCount {
                bestCount = newCount
                bestKey = key
            }
        }
        return bestKey
    }

    private var bankStatus: BankStatus? {
        guard batteries.count > 1 else { return nil }

        if let targetVoltage = dominantVoltage {
            let mismatched = batteries.filter { abs($0.nominalVoltage - targetVoltage) > voltageTolerance }
            if !mismatched.isEmpty {
                return .voltage(target: targetVoltage, mismatchedCount: mismatched.count)
            }
        }

        if let targetCapacity = dominantCapacity {
            let mismatched = batteries.filter { abs($0.capacityAmpHours - targetCapacity) > capacityTolerance }
            if !mismatched.isEmpty {
                return .capacity(target: targetCapacity, mismatchedCount: mismatched.count)
            }
        }

        return nil
    }

    private func emptySubtitle(for systemName: String) -> String {
        let format = String(
            localized: "battery.bank.empty.subtitle",
            defaultValue: "Tap the plus button to configure a battery for %@."
        )
        return String(format: format, systemName)
    }

    private func detailInfo(for status: BankStatus) -> (title: String, message: String) {
        switch status {
        case let .voltage(target, mismatchedCount):
            let countText = mismatchedCount == 1
                ? String(
                    localized: "battery.bank.status.single.battery",
                    defaultValue: "One battery"
                )
                : String(
                    format: String(
                        localized: "battery.bank.status.multiple.batteries",
                        defaultValue: "%d batteries"
                    ),
                    mismatchedCount
                )
            let expected = formattedValue(target, unit: "V")
            let message = String(
                format: String(
                    localized: "battery.bank.status.voltage.message",
                    defaultValue: "%@ diverges from the bank baseline of %@. Mixing nominal voltages leads to uneven charging and can damage connected chargers or inverters."
                ),
                countText,
                expected
            )
            return (
                String(
                    localized: "battery.bank.status.voltage.title",
                    defaultValue: "Voltage mismatch"
                ),
                message
            )
        case let .capacity(target, mismatchedCount):
            let countText = mismatchedCount == 1
                ? String(
                    localized: "battery.bank.status.single.battery",
                    defaultValue: "One battery"
                )
                : String(
                    format: String(
                        localized: "battery.bank.status.multiple.batteries",
                        defaultValue: "%d batteries"
                    ),
                    mismatchedCount
                )
            let expected = formattedValue(target, unit: "Ah")
            let message = String(
                format: String(
                    localized: "battery.bank.status.capacity.message",
                    defaultValue: "%@ uses a different capacity than the dominant bank size of %@. Mismatched capacities cause uneven discharge and premature wear."
                ),
                countText,
                expected
            )
            return (
                String(
                    localized: "battery.bank.status.capacity.title",
                    defaultValue: "Capacity mismatch"
                ),
                message
            )
        }
    }
}

private enum BatteriesViewPreviewData {
    static let system = ElectricalSystem(name: "Preview System", iconName: "bolt", colorName: "green")
    static let batteries: [SavedBattery] = [
        SavedBattery(
            name: "House Bank",
            nominalVoltage: 12.8,
            capacityAmpHours: 200,
            chemistry: .lithiumIronPhosphate,
            iconName: "battery.100.bolt",
            colorName: "green",
            system: system
        ),
        SavedBattery(
            name: "Starter Battery",
            nominalVoltage: 12.0,
            capacityAmpHours: 90,
            chemistry: .agm,
            iconName: "bolt",
            colorName: "orange",
            system: system
        )
    ]
}

#Preview {
    BatteriesView(
        system: BatteriesViewPreviewData.system,
        batteries: BatteriesViewPreviewData.batteries,
        editMode: .constant(.inactive)
    )
}
