//
//  CalculatorView.swift
//  Cable
//
//  Created by Stefan Lange-Hegermann on 11.09.25.
//

import SwiftUI
import SwiftData

struct CalculatorView: View {
    @EnvironmentObject var unitSettings: UnitSystemSettings
    @StateObject private var calculator = CableCalculator()
    @Environment(\.modelContext) private var modelContext
    @Environment(\.dismiss) private var dismiss
    @Query private var savedLoads: [SavedLoad]
    @State private var showingLibrary = false
    @State private var isWattMode = false
    @State private var editingValue: EditingValue? = nil
    @State private var showingLoadEditor = false
    @State private var presentedAffiliateLink: AffiliateLinkInfo?
    @State private var completedItemIDs: Set<String>
    
    let savedLoad: SavedLoad?
    
    init(savedLoad: SavedLoad? = nil) {
        self.savedLoad = savedLoad
        _completedItemIDs = State(initialValue: Set(savedLoad?.bomCompletedItemIDs ?? []))
    }
    
    enum EditingValue {
        case voltage, current, power, length
    }

    struct AffiliateLinkInfo: Identifiable, Equatable {
        let id: String
        let affiliateURL: URL?
        let buttonTitle: String
        let regionName: String?
        let countryCode: String?
    }

    struct BOMItem: Identifiable, Equatable {
        enum Destination: Equatable {
            case affiliate(URL)
            case amazonSearch(String)
        }

        let id: String
        let title: String
        let detail: String
        let iconSystemName: String
        let destination: Destination
        let isPrimaryComponent: Bool
    }

    var body: some View {
        VStack(spacing: 0) {
            badgesSection
            circuitDiagram
            resultsSection
            mainContent
        }
        .navigationBarTitleDisplayMode(.inline)
        .navigationTitle("")
        .toolbar {
            ToolbarItem(placement: .principal) {
                navigationTitle
            }
            
            if savedLoad == nil {
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button("Save") {
                        saveCurrentLoad()
                    }
                }
            }
        }
        .sheet(isPresented: $showingLibrary) {
            LoadLibraryView(calculator: calculator)
        }
        .sheet(isPresented: $showingLoadEditor) {
            LoadEditorView(
                loadName: Binding(
                    get: { calculator.loadName },
                    set: { 
                        calculator.loadName = $0
                        autoUpdateSavedLoad()
                    }
                ),
                iconName: Binding(
                    get: { savedLoad?.iconName ?? "lightbulb" },
                    set: { newValue in
                        guard let savedLoad else { return }
                        savedLoad.iconName = newValue
                        savedLoad.remoteIconURLString = nil
                        autoUpdateSavedLoad()
                    }
                ),
                colorName: Binding(
                    get: { savedLoad?.colorName ?? "blue" },
                    set: { 
                        savedLoad?.colorName = $0
                        autoUpdateSavedLoad()
                    }
                ),
                remoteIconURLString: Binding(
                    get: { savedLoad?.remoteIconURLString },
                    set: { newValue in
                        guard let savedLoad else { return }
                        savedLoad.remoteIconURLString = newValue
                        autoUpdateSavedLoad()
                    }
                )
            )
        }
        .sheet(item: $presentedAffiliateLink) { info in
            BillOfMaterialsView(
                info: info,
                items: buildBillOfMaterialsItems(deviceLink: info.affiliateURL),
                completedItemIDs: $completedItemIDs
            )
        }
        .alert("Edit Length", isPresented: Binding(
            get: { editingValue == .length },
            set: { if !$0 { editingValue = nil } }
        )) {
            TextField("Length", value: $calculator.length, format: .number)
                .keyboardType(.decimalPad)
            Button("Cancel", role: .cancel) { editingValue = nil }
            Button("Save") {
                editingValue = nil
                calculator.objectWillChange.send()
                autoUpdateSavedLoad()
            }
        } message: {
            Text("Enter length in \(unitSettings.unitSystem.lengthUnit)")
        }
        .alert("Edit Voltage", isPresented: Binding(
            get: { editingValue == .voltage },
            set: { if !$0 { editingValue = nil } }
        )) {
            TextField("Voltage", value: $calculator.voltage, format: .number)
                .keyboardType(.decimalPad)
            Button("Cancel", role: .cancel) { editingValue = nil }
            Button("Save") {
                editingValue = nil
                if isWattMode {
                    calculator.updateFromPower()
                } else {
                    calculator.updateFromCurrent()
                }
                calculator.objectWillChange.send()
                autoUpdateSavedLoad()
            }
        } message: {
            Text("Enter voltage in volts (V)")
        }
        .alert("Edit Current", isPresented: Binding(
            get: { editingValue == .current },
            set: { if !$0 { editingValue = nil } }
        )) {
            TextField("Current", value: $calculator.current, format: .number)
                .keyboardType(.decimalPad)
            Button("Cancel", role: .cancel) { editingValue = nil }
            Button("Save") {
                editingValue = nil
                calculator.updateFromCurrent()
                calculator.objectWillChange.send()
                autoUpdateSavedLoad()
            }
        } message: {
            Text("Enter current in amperes (A)")
        }
        .alert("Edit Power", isPresented: Binding(
            get: { editingValue == .power },
            set: { if !$0 { editingValue = nil } }
        )) {
            TextField("Power", value: $calculator.power, format: .number)
                .keyboardType(.decimalPad)
            Button("Cancel", role: .cancel) { editingValue = nil }
            Button("Save") {
                editingValue = nil
                calculator.updateFromPower()
                calculator.objectWillChange.send()
                autoUpdateSavedLoad()
            }
        } message: {
            Text("Enter power in watts (W)")
        }
        .onAppear {
            if let savedLoad = savedLoad {
                loadConfiguration(from: savedLoad)
            }
        }
        .onChange(of: completedItemIDs) { _, _ in
            persistCompletedItems()
        }
    }
    
    private var loadIcon: String {
        savedLoad?.iconName ?? "lightbulb"
    }

    private var loadColor: Color {
        let colorName = savedLoad?.colorName ?? "blue"
        switch colorName {
        case "blue": return .blue
        case "green": return .green
        case "orange": return .orange
        case "red": return .red
        case "purple": return .purple
        case "yellow": return .yellow
        case "pink": return .pink
        case "teal": return .teal
        case "indigo": return .indigo
        case "mint": return .mint
        case "cyan": return .cyan
        case "brown": return .brown
        case "gray": return .gray
        default: return .blue
        }
    }

    private var loadRemoteIconURLString: String? {
        savedLoad?.remoteIconURLString
    }

    private var affiliateLinkInfo: AffiliateLinkInfo? {
        guard let savedLoad else { return nil }

        let affiliateURL: URL?
        if let urlString = savedLoad.affiliateURLString,
           let parsedURL = URL(string: urlString) {
            affiliateURL = parsedURL
        } else {
            affiliateURL = nil
        }

        let rawCountryCode = savedLoad.affiliateCountryCode ?? Locale.current.region?.identifier
        let countryCode = rawCountryCode?.uppercased()
        let regionName = countryCode.flatMap { Locale.current.localizedString(forRegionCode: $0) ?? $0 }

        let buttonTitle = String(localized: "affiliate.button.review_parts", comment: "Button title to review a bill of materials before shopping")
        let identifier = "bom-\(savedLoad.name)-\(savedLoad.timestamp.timeIntervalSince1970)"

        return AffiliateLinkInfo(
            id: identifier,
            affiliateURL: affiliateURL,
            buttonTitle: buttonTitle,
            regionName: regionName,
            countryCode: countryCode
        )
    }
    
    private var navigationTitle: some View {
        Button(action: {
            showingLoadEditor = true
        }) {
            HStack(spacing: 8) {
                LoadIconView(
                    remoteIconURLString: loadRemoteIconURLString,
                    fallbackSystemName: loadIcon,
                    fallbackColor: loadColor,
                    size: 24)
                
                Text(calculator.loadName)
                    .font(.headline)
                    .fontWeight(.semibold)
                    .foregroundColor(.primary)
            }
        }
        .buttonStyle(.plain)
    }
    
    private var badgesSection: some View {
        HStack(spacing: 12) {
            HStack(spacing: 4) {
                Text("FUSE")
                    .font(.caption2)
                    .fontWeight(.medium)
                    .foregroundColor(.secondary)
                Text("\(calculator.recommendedFuse)A")
                    .font(.subheadline)
                    .fontWeight(.bold)
                    .foregroundColor(.orange)
            }
            .padding(.horizontal, 8)
            .padding(.vertical, 4)
            .background(Color.orange.opacity(0.1))
            .cornerRadius(6)
            
            HStack(spacing: 4) {
                Text("WIRE")
                    .font(.caption2)
                    .fontWeight(.medium)
                    .foregroundColor(.secondary)
                Text(String(format: unitSettings.unitSystem == .imperial ? 
                    "%.1fft @ %.0f AWG" : 
                    "%.1fm @ %.1fmm²", 
                    unitSettings.unitSystem == .imperial ? calculator.length * 3.28084 : calculator.length,
                    calculator.crossSection(for: unitSettings.unitSystem)))
                    .font(.subheadline)
                    .fontWeight(.bold)
                    .foregroundColor(.blue)
            }
            .padding(.horizontal, 8)
            .padding(.vertical, 4)
            .background(Color.blue.opacity(0.1))
            .cornerRadius(6)
            
            Spacer()
        }
        .padding(.horizontal)
        .padding(.vertical, 8)
        .background(Color(.systemGroupedBackground))
    }
    
    private var circuitDiagram: some View {
        HStack(spacing: 0) {
            voltageSection
            wiringSection  
            loadBox
        }
        .padding()
        .background(Color(.systemGroupedBackground))
    }
    
    private var voltageSection: some View {
        VStack(spacing: 0) {
            VStack() {
                HStack {
                    Button(action: {
                        editingValue = .voltage
                    }) {
                        Text(String(format: "%.1fV", calculator.voltage))
                            .font(.caption)
                            .fontWeight(.medium)
                            .foregroundColor(.primary)
                    }
                    .buttonStyle(.plain)
                    .frame(width: 60)
                }
            }
        }
    }
    
    private var wiringSection: some View {
        VStack {
            HStack(alignment: .center, spacing: 2) {
                Circle()
                    .fill(.red)
                    .frame(width: 8, height: 8)
                Rectangle()
                    .fill(.red)
                    .frame(height: 4)
                    .frame(width: 10)
                Rectangle()
                    .fill(.green)
                    .frame(height: 30)
                    .frame(width:80)
                    .overlay(
                        Text("\(calculator.recommendedFuse)A")
                            .foregroundColor(.white)
                            .fontWeight(.bold)
                    )
                    .cornerRadius(6)
                
                Rectangle()
                    .fill(.red)
                    .frame(height: 4)
                    .frame(maxWidth: .infinity)
            }.offset(x: 0, y: -11)
            
            HStack(alignment: .center, spacing: 2) {
                Circle()
                    .fill(Color.primary)
                    .frame(width: 8, height: 8)
                
                Rectangle()
                    .fill(Color.primary)
                    .frame(height: 4)
                    .frame(maxWidth: .infinity)
            }
        }
    }
    
    private var loadBox: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 8)
                .fill(Color.gray.opacity(0.2))
                .frame(width: 120, height: 90)
                .overlay(loadContent)
                .overlay(connectionPoints)
        }
    }
    
    private var loadContent: some View {
        VStack {
            Text(calculator.loadName.uppercased())
                .font(.caption2)
                .foregroundColor(.secondary)
                .lineLimit(1)
                .truncationMode(.tail)
                .frame(maxWidth: .infinity)
            
            Button(action: {
                editingValue = isWattMode ? .power : .current
            }) {
                Text(String(format: "%.1fA", calculator.current))
                    .fontWeight(.semibold)
                    .foregroundColor(.primary)
            }
            .buttonStyle(.plain)
            
            Button(action: {
                editingValue = isWattMode ? .current : .power
            }) {
                Text(String(format: "%.0fW", calculator.calculatedPower))
                    .font(.caption)
                    .foregroundColor(.primary)
            }
            .buttonStyle(.plain)
        }
    }
    
    private var connectionPoints: some View {
        VStack {
            HStack {
                Circle()
                    .fill(.red)
                    .frame(width: 8, height: 8)
                    .offset(x: -4, y: 17)
                Spacer()
            }
            Spacer()
            HStack {
                Circle()
                    .fill(Color.primary)
                    .frame(width: 8, height: 8)
                    .offset(x: -4, y: -17)
                Spacer()
            }
        }
        .frame(width: 120, height: 80)
    }
    
    private var resultsSection: some View {
        HStack {
            Group {
                Button(action: {}) {
                    Text(unitSettings.unitSystem == .imperial ? 
                        String(format: "%.0f AWG", calculator.crossSection(for: unitSettings.unitSystem)) :
                        String(format: "%.1f mm²", calculator.crossSection(for: unitSettings.unitSystem)))
                        .fontWeight(.medium)
                        .foregroundColor(.blue)
                }
                .buttonStyle(.plain)
                
                Text("•").foregroundColor(.secondary)
                
                Button(action: { editingValue = .length }) {
                    Text(String(format: "%.1f %@", calculator.length, unitSettings.unitSystem.lengthUnit))
                        .fontWeight(.medium)
                        .foregroundColor(.primary)
                }
                .buttonStyle(.plain)
                
                Text("•").foregroundColor(.secondary)
                
                Button(action: {}) {
                    Text(String(format: "%.1fV (%.1f%%)", calculator.voltageDrop(for: unitSettings.unitSystem), calculator.voltageDropPercentage(for: unitSettings.unitSystem)))
                        .fontWeight(.medium)
                        .foregroundColor(calculator.voltageDropPercentage(for: unitSettings.unitSystem) > 5 ? .orange : .primary)
                }
                .buttonStyle(.plain)
                
                Text("•").foregroundColor(.secondary)
                
                Button(action: {}) {
                    Text(String(format: "%.1fW", calculator.powerLoss(for: unitSettings.unitSystem)))
                        .fontWeight(.medium)
                        .foregroundColor(.primary)
                }
                .buttonStyle(.plain)
            }
            .font(.caption)
        }
        .padding(.horizontal)
    }
    
    private var mainContent: some View {
        ScrollView {
            VStack(spacing: 20) {
                Divider().padding(.horizontal)
                slidersSection
                if let info = affiliateLinkInfo {
                    affiliateLinkSection(info: info)
                }
            }
        }
    }

    @ViewBuilder
    private func affiliateLinkSection(info: AffiliateLinkInfo) -> some View {
        VStack(alignment: .leading, spacing: 12) {
            Button {
                presentedAffiliateLink = info
            } label: {
                Label(info.buttonTitle, systemImage: "cart")
                    .font(.callout.weight(.semibold))
                    .frame(maxWidth: .infinity)
                    .padding(.vertical, 12)
                    .padding(.horizontal, 16)
                    .foregroundColor(.accentColor)
                    .background(
                        RoundedRectangle(cornerRadius: 12, style: .continuous)
                            .fill(Color.accentColor.opacity(0.12))
                    )
            }
            .buttonStyle(.plain)

            let descriptionKey = info.affiliateURL != nil
                ? "affiliate.description.with_link"
                : "affiliate.description.without_link"
            let description = NSLocalizedString(
                descriptionKey,
                comment: "Explanation text beneath the affiliate button"
            )
            Text(description)
                .font(.caption2)
                .foregroundColor(.secondary)
        }
        .padding()
        .background(Color(.secondarySystemBackground))
        .clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
        .padding(.horizontal)
    }

    private func buildBillOfMaterialsItems(deviceLink: URL?) -> [BOMItem] {
        let unitSystem = unitSettings.unitSystem
        let lengthValue = calculator.length
        let lengthLabel = String(format: "%.1f %@", lengthValue, unitSystem.lengthUnit)

        let crossSectionValue = calculator.crossSection(for: unitSystem)
        let crossSectionLabel: String
        let unknownSizeLabel = String(localized: "bom.size.unknown", comment: "Fallback label when the cable size is unknown")
        if unitSystem == .imperial {
            if crossSectionValue > 0 {
                crossSectionLabel = String(format: "AWG %.0f", crossSectionValue)
            } else {
                crossSectionLabel = unknownSizeLabel
            }
        } else {
            if crossSectionValue > 0 {
                crossSectionLabel = String(format: "%.1f mm²", crossSectionValue)
            } else {
                crossSectionLabel = unknownSizeLabel
            }
        }

        let cableDetail = "\(lengthLabel) • \(crossSectionLabel)"
        let powerDetail = String(format: "%.0f W @ %.1f V", calculator.calculatedPower, calculator.voltage)

        let fuseRating = calculator.recommendedFuse
        let fuseDetailFormat = NSLocalizedString(
            "bom.fuse.detail",
            comment: "Description for the fuse entry in the calculator BOM"
        )
        let fuseDetail = String.localizedStringWithFormat(fuseDetailFormat, fuseRating)

        let cableShoesDetailFormat = NSLocalizedString(
            "bom.terminals.detail",
            comment: "Description for the cable terminals entry in the calculator BOM"
        )
        let cableShoesDetail = String.localizedStringWithFormat(cableShoesDetailFormat, crossSectionLabel.lowercased())

        let cableGaugeQuery: String
        if unitSystem == .imperial {
            cableGaugeQuery = String(format: "AWG %.0f", crossSectionValue)
        } else {
            cableGaugeQuery = String(format: "%.1f mm2", crossSectionValue)
        }

        let redCableQuery = "\(cableGaugeQuery) red battery cable"
        let blackCableQuery = "\(cableGaugeQuery) black battery cable"
        let fuseQuery = "inline fuse holder \(fuseRating)A"
        let terminalQuery = "\(cableGaugeQuery) cable shoes"
        let deviceQueryBase = calculator.loadName.isEmpty
            ? String(format: "DC device %.0fW %.0fV", calculator.calculatedPower, calculator.voltage)
            : calculator.loadName

        var items: [BOMItem] = []

        let fallbackComponentTitle = String(localized: "component.fallback.name", comment: "Fallback name for a component when no custom name is provided")

        items.append(
            BOMItem(
                id: "component",
                title: calculator.loadName.isEmpty ? fallbackComponentTitle : calculator.loadName,
                detail: powerDetail,
                iconSystemName: "bolt.fill",
                destination: deviceLink.map { .affiliate($0) } ?? .amazonSearch(deviceQueryBase),
                isPrimaryComponent: true
            )
        )

        items.append(
            BOMItem(
                id: "cable-red",
                title: String(localized: "bom.item.cable.red", comment: "Title for the red power cable item"),
                detail: cableDetail,
                iconSystemName: "bolt.horizontal.circle",
                destination: .amazonSearch(redCableQuery),
                isPrimaryComponent: false
            )
        )

        items.append(
            BOMItem(
                id: "cable-black",
                title: String(localized: "bom.item.cable.black", comment: "Title for the black power cable item"),
                detail: cableDetail,
                iconSystemName: "bolt.horizontal.circle",
                destination: .amazonSearch(blackCableQuery),
                isPrimaryComponent: false
            )
        )

        items.append(
            BOMItem(
                id: "fuse",
                title: String(localized: "bom.item.fuse", comment: "Title for the fuse item"),
                detail: fuseDetail,
                iconSystemName: "bolt.shield",
                destination: .amazonSearch(fuseQuery),
                isPrimaryComponent: false
            )
        )

        items.append(
            BOMItem(
                id: "terminals",
                title: String(localized: "bom.item.terminals", comment: "Title for the terminals item"),
                detail: cableShoesDetail,
                iconSystemName: "wrench.and.screwdriver",
                destination: .amazonSearch(terminalQuery),
                isPrimaryComponent: false
            )
        )

        return items
    }
    
    private var slidersSection: some View {
        VStack(spacing: 30) {
            voltageSlider
            currentPowerSlider
            lengthSlider
        }
        .padding(.horizontal)
    }
    
    private var voltageSlider: some View {
        SliderSection(title: String(localized: "slider.voltage.title", comment: "Title for the voltage slider"), 
                    value: $calculator.voltage, 
                    range: 3...48, 
                    unit: "V",
                    tapAction: { editingValue = .voltage },
                    snapValues: [3.3, 5.0, 6.0, 9.0, 12.0, 13.8, 24.0, 28.0, 48.0])
        .onChange(of: calculator.voltage) {
            if isWattMode {
                calculator.updateFromPower()
            } else {
                calculator.updateFromCurrent()
            }
            calculator.objectWillChange.send()
            autoUpdateSavedLoad()
        }
    }
    
    @ViewBuilder
    private var currentPowerSlider: some View {
        if isWattMode {
            SliderSection(title: String(localized: "slider.power.title", comment: "Title for the power slider"), 
                        value: $calculator.power, 
                        range: 0...2000, 
                        unit: "W",
                        buttonText: String(localized: "slider.button.watt", comment: "Button label when showing power control"),
                        buttonAction: {
                            isWattMode = false
                            calculator.updateFromPower()
                            autoUpdateSavedLoad()
                        },
                        tapAction: { editingValue = .power },
                        snapValues: [5, 10, 15, 20, 25, 30, 40, 50, 60, 75, 100, 125, 150, 200, 250, 300, 400, 500, 600, 750, 1000, 1250, 1500, 2000])
            .onChange(of: calculator.power) {
                calculator.updateFromPower()
                calculator.objectWillChange.send()
                autoUpdateSavedLoad()
            }
        } else {
            SliderSection(title: String(localized: "slider.current.title", comment: "Title for the current slider"), 
                        value: $calculator.current, 
                        range: 0...100, 
                        unit: "A",
                        buttonText: String(localized: "slider.button.ampere", comment: "Button label when showing current control"),
                        buttonAction: {
                            isWattMode = true
                            calculator.updateFromCurrent()
                            autoUpdateSavedLoad()
                        },
                        tapAction: { editingValue = .current },
                        snapValues: [0.5, 1, 2, 3, 4, 5, 7.5, 10, 12, 15, 20, 25, 30, 40, 50, 60, 75, 80, 100])
            .onChange(of: calculator.current) {
                calculator.updateFromCurrent()
                calculator.objectWillChange.send()
                autoUpdateSavedLoad()
            }
        }
    }
    
    private var lengthSlider: some View {
        let lengthTitleFormat = NSLocalizedString(
            "slider.length.title",
            comment: "Title format for the cable length slider"
        )
        return SliderSection(title: String(format: lengthTitleFormat, locale: Locale.current, unitSettings.unitSystem.lengthUnit), 
                    value: $calculator.length, 
                    range: 0...20, 
                    unit: unitSettings.unitSystem.lengthUnit,
                    tapAction: { editingValue = .length },
                    snapValues: unitSettings.unitSystem == .metric ? 
                        [0.5, 1, 1.5, 2, 2.5, 3, 4, 5, 6, 7.5, 10, 12, 15, 20] :
                        [1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 25, 30, 40, 50, 60])
        .onChange(of: calculator.length) {
            calculator.objectWillChange.send()
            autoUpdateSavedLoad()
        }
    }
    
    
    private func saveCurrentLoad() {
        let fallbackName = String(localized: "default.load.unnamed", comment: "Fallback name for a load when no name is provided")
        let savedLoad = SavedLoad(
            name: calculator.loadName.isEmpty ? fallbackName : calculator.loadName,
            voltage: calculator.voltage,
            current: calculator.current,
            power: calculator.power,
            length: calculator.length,
            crossSection: calculator.crossSection(for: .metric), // Always save in metric
            iconName: "lightbulb",
            colorName: "blue",
            isWattMode: isWattMode,
            system: nil, // For now, new loads aren't associated with a system
            remoteIconURLString: nil
        )
        modelContext.insert(savedLoad)
    }
    
    private func loadConfiguration(from savedLoad: SavedLoad) {
        calculator.loadName = savedLoad.name
        calculator.voltage = savedLoad.voltage
        calculator.current = savedLoad.current
        calculator.power = savedLoad.power
        calculator.length = savedLoad.length
        isWattMode = savedLoad.isWattMode
        completedItemIDs = Set(savedLoad.bomCompletedItemIDs)
    }
    
    private func autoUpdateSavedLoad() {
        guard let savedLoad = savedLoad else { return }
        
        let fallbackName = String(localized: "default.load.unnamed", comment: "Fallback name for a load when no name is provided")
        savedLoad.name = calculator.loadName.isEmpty ? fallbackName : calculator.loadName
        savedLoad.voltage = calculator.voltage
        savedLoad.current = calculator.current
        savedLoad.power = calculator.power
        savedLoad.length = calculator.length
        savedLoad.crossSection = calculator.crossSection(for: .metric)
        savedLoad.timestamp = Date()
        savedLoad.isWattMode = isWattMode
        savedLoad.bomCompletedItemIDs = Array(completedItemIDs).sorted()
        // Icon and color are updated directly through bindings in the editor
    }

    private func persistCompletedItems() {
        guard let savedLoad = savedLoad else { return }
        savedLoad.bomCompletedItemIDs = Array(completedItemIDs).sorted()
    }
}

// MARK: - Supporting Views

private struct BillOfMaterialsView: View {
    let info: CalculatorView.AffiliateLinkInfo
    let items: [CalculatorView.BOMItem]
    @Binding var completedItemIDs: Set<String>

    @Environment(\.dismiss) private var dismiss
    @Environment(\.openURL) private var openURL
    @State private var suppressRowTapForID: String?

    var body: some View {
        NavigationStack {
            List {
                Section("Components") {
                    ForEach(items) { item in
                        let isCompleted = completedItemIDs.contains(item.id)
                        let destinationURL = destinationURL(for: item)
                        let accessibilityLabel: String = {
                            if isCompleted {
                                let format = NSLocalizedString(
                                    "bom.accessibility.mark.incomplete",
                                    comment: "Accessibility label to mark a BOM item incomplete"
                                )
                                return String.localizedStringWithFormat(format, item.title)
                            } else {
                                let format = NSLocalizedString(
                                    "bom.accessibility.mark.complete",
                                    comment: "Accessibility label to mark a BOM item complete"
                                )
                                return String.localizedStringWithFormat(format, item.title)
                            }
                        }()

                        HStack(spacing: 12) {
                            Image(systemName: isCompleted ? "checkmark.circle.fill" : "circle")
                                .foregroundColor(isCompleted ? .accentColor : .secondary)
                                .imageScale(.large)
                                .onTapGesture {
                                    if isCompleted {
                                        completedItemIDs.remove(item.id)
                                    } else {
                                        completedItemIDs.insert(item.id)
                                    }
                                    suppressRowTapForID = item.id
                                }
                                .accessibilityLabel(accessibilityLabel)

                            VStack(alignment: .leading, spacing: 4) {
                                Text(item.title)
                                    .font(.headline)
                                    .foregroundStyle(isCompleted ? Color.primary.opacity(0.7) : Color.primary)
                                    .strikethrough(isCompleted, color: .accentColor.opacity(0.6))

                                if item.isPrimaryComponent {
                                    Text(String(localized: "component.fallback.name", comment: "Tag label marking a BOM entry as the main component"))
                                        .font(.caption2.weight(.medium))
                                        .foregroundColor(.accentColor)
                                        .padding(.horizontal, 6)
                                        .padding(.vertical, 2)
                                        .background(Color.accentColor.opacity(0.15), in: Capsule())
                                }

                                Text(item.detail)
                                    .font(.subheadline)
                                    .foregroundColor(.secondary)
                            }

                            Spacer(minLength: 8)

                            if destinationURL != nil {
                                Image(systemName: "arrow.up.right")
                                    .font(.footnote.weight(.semibold))
                                    .foregroundColor(.secondary)
                            }
                        }
                        .padding(.vertical, 10)
                        .contentShape(Rectangle())
                        .listRowInsets(EdgeInsets(top: 6, leading: 20, bottom: 6, trailing: 16))
                        .listRowBackground(
                            Color(.secondarySystemGroupedBackground)
                        )
                        .onTapGesture {
                            if suppressRowTapForID == item.id {
                                suppressRowTapForID = nil
                                return
                            }
                            if let destinationURL {
                                openURL(destinationURL)
                            }
                            completedItemIDs.insert(item.id)
                            suppressRowTapForID = nil
                        }
                    }
                }

                Section {
                    Text(
                        String(
                            localized: "affiliate.disclaimer",
                            comment: "Footer note reminding users that affiliate purchases may support the app"
                        )
                    )
                        .font(.footnote)
                        .foregroundColor(.secondary)
                        .padding(.vertical, 4)
                }
            }
            .listStyle(.insetGrouped)
            .navigationTitle(
                String(
                    localized: "bom.navigation.title",
                    comment: "Navigation title for the bill of materials view"
                )
            )
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .cancellationAction) {
                    Button("Close") {
                        dismiss()
                    }
                }
            }
        }
    }

    private func destinationURL(for item: CalculatorView.BOMItem) -> URL? {
        switch item.destination {
        case .affiliate(let url):
            return url
        case .amazonSearch(let query):
            return AmazonAffiliate.searchURL(query: query, countryCode: info.countryCode)
        }
    }
}

struct SliderSection: View {
    let title: String
    @Binding var value: Double
    let range: ClosedRange<Double>
    let unit: String
    var buttonText: String?
    var buttonAction: (() -> Void)?
    var tapAction: (() -> Void)?
    var snapValues: [Double]?
    
    init(title: String, value: Binding<Double>, range: ClosedRange<Double>, unit: String, buttonText: String? = nil, buttonAction: (() -> Void)? = nil, tapAction: (() -> Void)? = nil, snapValues: [Double]? = nil) {
        self.title = title
        self._value = value
        self.range = range
        self.unit = unit
        self.buttonText = buttonText
        self.buttonAction = buttonAction
        self.tapAction = tapAction
        self.snapValues = snapValues
    }
    
    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            HStack {
                Text(title)
                    .font(.headline)
                Spacer()
                if let buttonText = buttonText {
                    Button(buttonText) {
                        buttonAction?()
                    }
                    .buttonStyle(.borderedProminent)
                }
            }
            
            Button(action: {
                tapAction?()
            }) {
                Text(String(format: "%.1f %@", value, unit))
                    .font(.title)
                    .fontWeight(.bold)
                    .foregroundColor(.primary)
            }
            .buttonStyle(.plain)
            .disabled(tapAction == nil)
            
            HStack {
                Text(String(format: "%.0f%@", range.lowerBound, unit))
                    .font(.caption)
                    .foregroundColor(.secondary)
                
                Slider(value: $value, in: range)
                    .onChange(of: value) {
                        // Always round to 1 decimal place first
                        value = round(value * 10) / 10
                        
                        if let snapValues = snapValues {
                            // Find the closest snap value
                            let closest = snapValues.min { abs($0 - value) < abs($1 - value) }
                            if let closest = closest, abs(closest - value) < 0.5 {
                                value = closest
                            }
                        }
                    }
                
                Text(String(format: "%.0f%@", range.upperBound, unit))
                    .font(.caption)
                    .foregroundColor(.secondary)
            }
        }
    }
}

struct LoadLibraryView: View {
    @Environment(\.dismiss) private var dismiss
    @Environment(\.modelContext) private var modelContext
    @Query private var savedLoads: [SavedLoad]
    let calculator: CableCalculator
    
    var body: some View {
        NavigationStack {
            List {
                ForEach(savedLoads) { load in
                    VStack(alignment: .leading, spacing: 4) {
                        Text(load.name)
                            .fontWeight(.medium)
                        HStack {
                            Text(String(format: "%.1fV", load.voltage))
                            Text("•")
                            Text(String(format: "%.1fA", load.current))
                            Text("•")
                            Text(String(format: "%.1fm", load.length))
                            Spacer()
                            Text(load.timestamp, format: .dateTime.month().day())
                                .foregroundColor(.secondary)
                                .font(.caption)
                        }
                        .font(.caption)
                        .foregroundColor(.secondary)
                    }
                    .contentShape(Rectangle())
                    .onTapGesture {
                        loadConfiguration(from: load)
                        dismiss()
                    }
                }
                .onDelete(perform: deleteLoads)
            }
            .navigationTitle("Load Library")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("Cancel") {
                        dismiss()
                    }
                }
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
            }
        }
    }
    
    private func loadConfiguration(from savedLoad: SavedLoad) {
        calculator.loadName = savedLoad.name
        calculator.voltage = savedLoad.voltage
        calculator.current = savedLoad.current
        calculator.length = savedLoad.length
    }
    
    private func deleteLoads(offsets: IndexSet) {
        for index in offsets {
            modelContext.delete(savedLoads[index])
        }
    }
}

#Preview {
    CalculatorView()
        .modelContainer(for: SavedLoad.self, inMemory: true)
        .environmentObject(UnitSystemSettings())
}
