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

import SwiftUI
import SwiftData
import Foundation

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 voltageInput: String = ""
    @State private var currentInput: String = ""
    @State private var powerInput: String = ""
    @State private var lengthInput: String = ""
    @State private var dutyCycleInput: String = ""
    @State private var usageHoursInput: String = ""
    @State private var showingLoadEditor = false
    @State private var presentedAffiliateLink: AffiliateLinkInfo?
    @State private var completedItemIDs: Set<String>
    @State private var isAdvancedExpanded = false
    
    let savedLoad: SavedLoad?
    
    init(savedLoad: SavedLoad? = nil) {
        self.savedLoad = savedLoad
        _completedItemIDs = State(initialValue: Set(savedLoad?.bomCompletedItemIDs ?? []))
    }
    
    enum EditingValue {
        case voltage, current, power, length, dutyCycle, usageHours
    }

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

    struct AffiliateLinkInfo: Identifiable, Equatable {
        let id: String
        let componentID: String?
        let buttonTitle: String
    }

    struct BOMItem: Identifiable, Equatable {
        enum Destination: Equatable {
            case component(String)
            case search(String)
        }

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

    var body: some View {
        attachAlerts(
            attachSheets(
                navigationWrapped(mainLayout)
            )
        )
    }

    private func attachAlerts<V: View>(_ view: V) -> some View {
        let withLength = addLengthAlert(to: view)
        let withVoltage = addVoltageAlert(to: withLength)
        let withCurrent = addCurrentAlert(to: withVoltage)
        let withPower = addPowerAlert(to: withCurrent)
        let withDutyCycle = addDutyCycleAlert(to: withPower)
        return addUsageHoursAlert(to: withDutyCycle)
    }

    private func addLengthAlert<V: View>(to view: V) -> some View {
        view
        .alert("Edit Length", isPresented: Binding(
            get: { editingValue == .length },
            set: { isPresented in
                if !isPresented {
                    editingValue = nil
                    lengthInput = ""
                }
            }
        )) {
            TextField("Length", text: $lengthInput)
                .keyboardType(.decimalPad)
                .onAppear {
                    if lengthInput.isEmpty {
                        lengthInput = formattedValue(displayLength)
                    }
                }
                .onChange(of: lengthInput) { _, newValue in
                    guard editingValue == .length, let parsed = parseInput(newValue) else { return }
                    calculator.length = metersFromDisplayLength(roundToTenth(parsed))
                }
            Button("Cancel", role: .cancel) {
                editingValue = nil
                lengthInput = ""
            }
            Button("Save") {
                if let parsed = parseInput(lengthInput) {
                    calculator.length = metersFromDisplayLength(roundToTenth(parsed))
                }
                editingValue = nil
                lengthInput = ""
                calculator.objectWillChange.send()
                autoUpdateSavedLoad()
            }
        } message: {
            Text("Enter length in \(unitSettings.unitSystem.lengthUnit)")
        }
    }

    private func addVoltageAlert<V: View>(to view: V) -> some View {
        view
        .alert("Edit Voltage", isPresented: Binding(
            get: { editingValue == .voltage },
            set: { isPresented in
                if !isPresented {
                    editingValue = nil
                    voltageInput = ""
                }
            }
        )) {
            TextField("Voltage", text: $voltageInput)
                .keyboardType(.decimalPad)
                .onAppear {
                    if voltageInput.isEmpty {
                        voltageInput = formattedValue(calculator.voltage)
                    }
                }
                .onChange(of: voltageInput) { _, newValue in
                    guard editingValue == .voltage, let parsed = parseInput(newValue) else { return }
                    calculator.voltage = roundToTenth(parsed)
                }
            Button("Cancel", role: .cancel) {
                editingValue = nil
                voltageInput = ""
            }
            Button("Save") {
                if let parsed = parseInput(voltageInput) {
                    calculator.voltage = roundToTenth(parsed)
                }
                editingValue = nil
                if isWattMode {
                    calculator.updateFromPower()
                } else {
                    calculator.updateFromCurrent()
                }
                voltageInput = ""
                calculator.objectWillChange.send()
                autoUpdateSavedLoad()
            }
        } message: {
            Text("Enter voltage in volts (V)")
        }
    }

    private func addCurrentAlert<V: View>(to view: V) -> some View {
        view
        .alert("Edit Current", isPresented: Binding(
            get: { editingValue == .current },
            set: { isPresented in
                if !isPresented {
                    editingValue = nil
                    currentInput = ""
                }
            }
        )) {
            TextField("Current", text: $currentInput)
                .keyboardType(.decimalPad)
                .onAppear {
                    if currentInput.isEmpty {
                        currentInput = formattedValue(calculator.current)
                    }
                }
                .onChange(of: currentInput) { _, newValue in
                    guard editingValue == .current, let parsed = parseInput(newValue) else { return }
                    calculator.current = roundToTenth(parsed)
                }
            Button("Cancel", role: .cancel) {
                editingValue = nil
                currentInput = ""
            }
            Button("Save") {
                if let parsed = parseInput(currentInput) {
                    calculator.current = roundToTenth(parsed)
                }
                editingValue = nil
                calculator.updateFromCurrent()
                currentInput = ""
                calculator.objectWillChange.send()
                autoUpdateSavedLoad()
            }
        } message: {
            Text("Enter current in amperes (A)")
        }
    }

    private func addPowerAlert<V: View>(to view: V) -> some View {
        view
        .alert("Edit Power", isPresented: Binding(
            get: { editingValue == .power },
            set: { isPresented in
                if !isPresented {
                    editingValue = nil
                    powerInput = ""
                }
            }
        )) {
            TextField("Power", text: $powerInput)
                .keyboardType(.decimalPad)
                .onAppear {
                    if powerInput.isEmpty {
                        powerInput = formattedValue(calculator.power)
                    }
                }
                .onChange(of: powerInput) { _, newValue in
                    guard editingValue == .power, let parsed = parseInput(newValue) else { return }
                    calculator.power = roundToNearestFive(parsed)
                }
            Button("Cancel", role: .cancel) {
                editingValue = nil
                powerInput = ""
            }
            Button("Save") {
                if let parsed = parseInput(powerInput) {
                    calculator.power = roundToNearestFive(parsed)
                }
                editingValue = nil
                calculator.updateFromPower()
                powerInput = ""
                calculator.objectWillChange.send()
                autoUpdateSavedLoad()
            }
        } message: {
            Text("Enter power in watts (W)")
        }
    }

    private func addDutyCycleAlert<V: View>(to view: V) -> some View {
        view
        .alert(
            dutyCycleAlertTitle,
            isPresented: Binding(
                get: { editingValue == .dutyCycle },
                set: { isPresented in
                    if !isPresented {
                        editingValue = nil
                        dutyCycleInput = ""
                    }
                }
            )
        ) {
            TextField(dutyCycleAlertPlaceholder, text: $dutyCycleInput)
                .keyboardType(.decimalPad)
                .onAppear {
                    if dutyCycleInput.isEmpty {
                        dutyCycleInput = formattedValue(calculator.dutyCyclePercent)
                    }
                }
                .onChange(of: dutyCycleInput) { _, newValue in
                    guard editingValue == .dutyCycle, let parsed = parseInput(newValue) else { return }
                    calculator.dutyCyclePercent = clampDutyCyclePercent(parsed)
                }
            Button("Cancel", role: .cancel) {
                editingValue = nil
                dutyCycleInput = ""
            }
            Button("Save") {
                if let parsed = parseInput(dutyCycleInput) {
                    calculator.dutyCyclePercent = clampDutyCyclePercent(parsed)
                }
                editingValue = nil
                dutyCycleInput = ""
                calculator.objectWillChange.send()
                autoUpdateSavedLoad()
            }
        } message: {
            Text(dutyCycleAlertMessage)
        }
    }

    private func addUsageHoursAlert<V: View>(to view: V) -> some View {
        view
        .alert(
            usageHoursAlertTitle,
            isPresented: Binding(
                get: { editingValue == .usageHours },
                set: { isPresented in
                    if !isPresented {
                        editingValue = nil
                        usageHoursInput = ""
                    }
                }
            )
        ) {
            TextField(usageHoursAlertPlaceholder, text: $usageHoursInput)
                .keyboardType(.decimalPad)
                .onAppear {
                    if usageHoursInput.isEmpty {
                        usageHoursInput = formattedValue(calculator.dailyUsageHours)
                    }
                }
                .onChange(of: usageHoursInput) { _, newValue in
                    guard editingValue == .usageHours, let parsed = parseInput(newValue) else { return }
                    calculator.dailyUsageHours = clampUsageHours(parsed)
                }
            Button("Cancel", role: .cancel) {
                editingValue = nil
                usageHoursInput = ""
            }
            Button("Save") {
                if let parsed = parseInput(usageHoursInput) {
                    calculator.dailyUsageHours = clampUsageHours(parsed)
                }
                editingValue = nil
                usageHoursInput = ""
                calculator.objectWillChange.send()
                autoUpdateSavedLoad()
            }
        } message: {
            Text(usageHoursAlertMessage)
        }
    }

    private func attachSheets<V: View>(_ view: V) -> some View {
        view
            .sheet(isPresented: $showingLibrary, content: librarySheet)
            .sheet(isPresented: $showingLoadEditor, content: loadEditorSheet)
            .sheet(item: $presentedAffiliateLink, content: billOfMaterialsSheet(info:))
            .onAppear {
                if let savedLoad = savedLoad {
                    loadConfiguration(from: savedLoad)
                }
            }
            .onChange(of: completedItemIDs) { _, _ in
                persistCompletedItems()
            }
    }

    private func navigationWrapped<V: View>(_ view: V) -> some View {
        view
            .navigationBarTitleDisplayMode(.inline)
            .navigationTitle("")
            .toolbar { toolbarContent }
    }

    private var mainLayout: some View {
        VStack(spacing: 0) {
            badgesSection
            circuitDiagram
            resultsSection
            mainContent
        }
    }

    @ToolbarContentBuilder
    private var toolbarContent: some ToolbarContent {
        ToolbarItem(placement: .principal) {
            navigationTitle
        }

        if savedLoad == nil {
            ToolbarItem(placement: .navigationBarTrailing) {
                Button("Save") {
                    saveCurrentLoad()
                }
            }
        }
    }

    @ViewBuilder
    private func billOfMaterialsSheet(info: AffiliateLinkInfo) -> some View {
        BillOfMaterialsView(
            info: info,
            items: buildBillOfMaterialsItems(componentID: info.componentID),
            completedItemIDs: $completedItemIDs
        )
    }

    @ViewBuilder
    private func librarySheet() -> some View {
        LoadLibraryView(calculator: calculator)
    }

    @ViewBuilder
    private func loadEditorSheet() -> some View {
        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()
                }
            )
        )
    }
    
    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 {
        let buttonTitle = String(localized: "affiliate.button.review_parts", comment: "Button title to review a bill of materials before shopping")
        let name = savedLoad?.name ?? calculator.loadName
        let timestamp = savedLoad?.timestamp ?? Date(timeIntervalSince1970: 0)
        let identifier = "bom-\(name)-\(timestamp.timeIntervalSince1970)"

        return AffiliateLinkInfo(
            id: identifier,
            componentID: savedLoad?.componentID,
            buttonTitle: buttonTitle
        )
    }
    
    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.recommendedFuseFormatted)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(unitSettings.unitSystem == .imperial ?
                    String(format: "%.1fft @ %@ AWG", displayLength, ElectricalCalculations.formatAWG(calculator.crossSection(for: unitSettings.unitSystem))) :
                    String(format: "%.1fm @ %.1fmm²", displayLength, 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: {
                        beginVoltageEditing()
                    }) {
                        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.recommendedFuseFormatted)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: {
                if isWattMode {
                    beginPowerEditing()
                } else {
                    beginCurrentEditing()
                }
            }) {
                Text(String(format: "%.1fA", calculator.current))
                    .fontWeight(.semibold)
                    .foregroundColor(.primary)
            }
            .buttonStyle(.plain)
            
            Button(action: {
                if isWattMode {
                    beginCurrentEditing()
                } else {
                    beginPowerEditing()
                }
            }) {
                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 ? 
                        "\(ElectricalCalculations.formatAWG(calculator.crossSection(for: unitSettings.unitSystem))) AWG" :
                        String(format: "%.1f mm²", calculator.crossSection(for: unitSettings.unitSystem)))
                        .fontWeight(.medium)
                        .foregroundColor(.blue)
                }
                .buttonStyle(.plain)
                
                Text("•").foregroundColor(.secondary)
                
                Button(action: { beginLengthEditing() }) {
                    Text(String(format: "%.1f %@", displayLength, 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 {
        List {
            slidersSection
            advancedSettingsSection
            affiliateLinkSection(info: affiliateLinkInfo)
                .listRowBackground(Color.clear)
                .listRowSeparator(.hidden)
                .listRowInsets(EdgeInsets(top: 12, leading: 18, bottom: 12, trailing: 18))
        }
        .listStyle(.plain)
        .scrollIndicators(.hidden)
        .scrollContentBackground(.hidden)
        .background(Color(.systemGroupedBackground))
    }

    @ViewBuilder
    private func affiliateLinkSection(info: AffiliateLinkInfo) -> some View {
        VStack(alignment: .leading, spacing: 12) {
            Button {
                AnalyticsTracker.log("Review Parts Tapped", properties: [
                    "load": info.id,
                    "has_component": info.componentID != nil,
                ])
                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 description = info.componentID != nil
                ? String(localized: "affiliate.description.with_link", defaultValue: "Tapping above shows a full bill of materials before opening the affiliate link. Purchases may support VoltPlan.")
                : String(localized: "affiliate.description.without_link", defaultValue: "Tapping above shows a full bill of materials with shopping searches to help you source parts.")
            Text(description)
                .font(.caption2)
                .foregroundColor(.secondary)
        }
        .padding()
        .background(Color(.secondarySystemBackground))
        .clipShape(RoundedRectangle(cornerRadius: 16, style: .continuous))
    }

    private func buildBillOfMaterialsItems(componentID: String?) -> [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 = "AWG \(ElectricalCalculations.formatAWG(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.recommendedFuseFormatted
        let fuseDetailFormat = String(localized: "bom.fuse.detail", defaultValue: "Inline holder and %@A fuse")
        let fuseDetail = String.localizedStringWithFormat(fuseDetailFormat, fuseRating)

        let cableShoesDetailFormat = String(localized: "bom.terminals.detail", defaultValue: "Ring or spade terminals sized for %@ wiring")
        let cableShoesDetail = String.localizedStringWithFormat(cableShoesDetailFormat, crossSectionLabel.lowercased())

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

        let redCableSearchFormat = String(localized: "bom.search.cable.red", defaultValue: "%@ red battery cable")
        let redCableQuery = String(format: redCableSearchFormat, cableGaugeQuery)
        let blackCableSearchFormat = String(localized: "bom.search.cable.black", defaultValue: "%@ black battery cable")
        let blackCableQuery = String(format: blackCableSearchFormat, cableGaugeQuery)
        let fuseSearchFormat = String(localized: "bom.search.fuse", defaultValue: "inline fuse holder %@A")
        let fuseQuery = String(format: fuseSearchFormat, fuseRating)
        let terminalSearchFormat = String(localized: "bom.search.terminals", defaultValue: "%@ cable shoes")
        let terminalQuery = String(format: terminalSearchFormat, cableGaugeQuery)
        let deviceFallbackFormat = String(localized: "bom.search.device.fallback", defaultValue: "DC device %.0fW %.0fV")
        let deviceQueryBase = calculator.loadName.isEmpty
            ? String(format: deviceFallbackFormat, 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: componentID.map { .component($0) } ?? .search(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: .search(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: .search(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: .search(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: .search(terminalQuery),
                isPrimaryComponent: false
            )
        )

        return items
    }
    
    private var advancedSettingsTitle: String {
        String(
            localized: "calculator.advanced.section.title",
            comment: "Title for the advanced load settings section"
        )
    }

    private var dutyCycleTitle: String {
        String(
            localized: "calculator.advanced.duty_cycle.title",
            comment: "Title for the duty cycle slider"
        )
    }

    private var dutyCycleHelperText: String {
        String(
            localized: "calculator.advanced.duty_cycle.helper",
            comment: "Helper text explaining duty cycle"
        )
    }

    private var usageHoursTitle: String {
        String(
            localized: "calculator.advanced.usage_hours.title",
            comment: "Title for the daily usage slider"
        )
    }

    private var usageHoursHelperText: String {
        String(
            localized: "calculator.advanced.usage_hours.helper",
            comment: "Helper text explaining daily usage hours"
        )
    }

    private var dutyCycleAlertTitle: String {
        String(
            localized: "calculator.alert.duty_cycle.title",
            comment: "Title for the duty cycle edit alert"
        )
    }

    private var dutyCycleAlertPlaceholder: String {
        String(
            localized: "calculator.alert.duty_cycle.placeholder",
            comment: "Placeholder for the duty cycle alert text field"
        )
    }

    private var dutyCycleAlertMessage: String {
        String(
            localized: "calculator.alert.duty_cycle.message",
            comment: "Helper message for the duty cycle alert"
        )
    }

    private var usageHoursAlertTitle: String {
        String(
            localized: "calculator.alert.usage_hours.title",
            comment: "Title for the daily usage edit alert"
        )
    }

    private var usageHoursAlertPlaceholder: String {
        String(
            localized: "calculator.alert.usage_hours.placeholder",
            comment: "Placeholder for the daily usage alert text field"
        )
    }

    private var usageHoursAlertMessage: String {
        String(
            localized: "calculator.alert.usage_hours.message",
            comment: "Helper message for the daily usage alert"
        )
    }

    private var slidersSection: some View {
        Section {
            voltageSlider
                .listRowSeparator(.hidden)
            currentPowerSlider
                .listRowSeparator(.hidden)
            lengthSlider
                .listRowSeparator(.hidden)
        }
        .listRowBackground(Color(.systemBackground))
        .listRowSeparator(.hidden)
        .listRowInsets(EdgeInsets(top: 12, leading: 18, bottom: 12, trailing: 18))
    }

    private var advancedSettingsSection: some View {
        Section {
            Button {
                withAnimation(.easeInOut(duration: 0.2)) {
                    isAdvancedExpanded.toggle()
                }
            } label: {
                HStack(spacing: 8) {
                    Text(advancedSettingsTitle.uppercased())
                        .font(.caption2)
                        .fontWeight(.medium)
                        .foregroundStyle(.secondary)
                    Spacer()
                    Image(systemName: isAdvancedExpanded ? "chevron.up" : "chevron.down")
                        .font(.footnote.weight(.semibold))
                        .foregroundStyle(.secondary)
                }
                .padding(.vertical, 10)
                .contentShape(Rectangle())
            }
            .buttonStyle(.plain)
            .listRowBackground(Color(.secondarySystemBackground))
            .listRowSeparator(.hidden)

            if isAdvancedExpanded {
                VStack(alignment: .leading, spacing: 8) {
                    dutyCycleSlider
                        .listRowSeparator(.hidden)
                        .listRowBackground(Color(.systemBackground))
                    Text(dutyCycleHelperText)
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }

                VStack(alignment: .leading, spacing: 8) {
                    usageHoursSlider
                        .listRowSeparator(.hidden)
                        .listRowBackground(Color(.systemBackground))
                    Text(usageHoursHelperText)
                        .font(.caption)
                        .foregroundStyle(.secondary)
                }
            }
        }
        .listRowSeparator(.hidden)
        .listRowInsets(EdgeInsets(top: 12, leading: 18, bottom: 12, trailing: 18))
        .animation(.easeInOut(duration: 0.2), value: isAdvancedExpanded)
    }

    private var voltageSliderRange: ClosedRange<Double> {
        let upperBound = max(48, calculator.voltage)
        return 0...upperBound
    }

    private var powerSliderRange: ClosedRange<Double> {
        let upperBound = max(2000, calculator.power)
        return 0...upperBound
    }

    private var currentSliderRange: ClosedRange<Double> {
        let upperBound = max(100, calculator.current)
        return 0...upperBound
    }

    private var lengthSliderRange: ClosedRange<Double> {
        let baseMax = unitSettings.unitSystem == .metric ? 20.0 : 60.0
        let upperBound = max(baseMax, displayLength)
        return 0...upperBound
    }

    private var dutyCycleRange: ClosedRange<Double> {
        0...100
    }

    private var usageHoursRange: ClosedRange<Double> {
        0...24
    }

    private var voltageSnapValues: [Double] {
        [3.3, 5.0, 6.0, 9.0, 12.0, 13.8, 24.0, 28.0, 48.0]
    }

    private var powerSnapValues: [Double] {
        [5, 10, 15, 20, 25, 30, 40, 50, 60, 75, 100, 125, 150, 200, 250, 300, 400, 500, 600, 750, 1000, 1250, 1500, 2000]
    }

    private var currentSnapValues: [Double] {
        [0.5, 1, 2, 3, 4, 5, 7.5, 10, 12, 15, 20, 25, 30, 40, 50, 60, 75, 80, 100]
    }

    private var lengthSnapValues: [Double] {
        if unitSettings.unitSystem == .metric {
            return [0.5, 1, 1.5, 2, 2.5, 3, 4, 5, 6, 7.5, 10, 12, 15, 20]
        } else {
            return [1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 25, 30, 40, 50, 60]
        }
    }
    
    private var voltageSlider: some View {
            SliderSection(title: String(localized: "slider.voltage.title", comment: "Title for the voltage slider"), 
                        value: Binding(
                            get: { calculator.voltage },
                            set: { newValue in
                                if editingValue == .voltage {
                                    calculator.voltage = roundToTenth(newValue)
                                } else {
                                    calculator.voltage = normalizedVoltage(for: newValue)
                                }
                            }
                        ), 
                        range: voltageSliderRange, 
                        unit: "V",
                        tapAction: beginVoltageEditing,
                        snapValues: editingValue == .voltage ? nil : voltageSnapValues)
        .onChange(of: calculator.voltage) { _, _ in
            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: Binding(
                            get: { calculator.power },
                            set: { newValue in
                                if editingValue == .power {
                                    calculator.power = roundToNearestFive(newValue)
                                } else {
                                    calculator.power = normalizedPower(for: newValue)
                                }
                            }
                        ), 
                        range: powerSliderRange, 
                        unit: "W",
                        buttonText: String(localized: "slider.button.watt", comment: "Button label when showing power control"),
                        buttonAction: {
                            isWattMode = false
                            calculator.updateFromPower()
                            autoUpdateSavedLoad()
                        },
                        tapAction: beginPowerEditing,
                        snapValues: editingValue == .power ? nil : powerSnapValues)
            .onChange(of: calculator.power) { _, _ in
                calculator.updateFromPower()
                calculator.objectWillChange.send()
                autoUpdateSavedLoad()
            }
        } else {
            SliderSection(title: String(localized: "slider.current.title", comment: "Title for the current slider"), 
                        value: Binding(
                            get: { calculator.current },
                            set: { newValue in
                                if editingValue == .current {
                                    calculator.current = roundToTenth(newValue)
                                } else {
                                    calculator.current = normalizedCurrent(for: newValue)
                                }
                            }
                        ), 
                        range: currentSliderRange, 
                        unit: "A",
                        buttonText: String(localized: "slider.button.ampere", comment: "Button label when showing current control"),
                        buttonAction: {
                            isWattMode = true
                            calculator.updateFromCurrent()
                            autoUpdateSavedLoad()
                        },
                        tapAction: beginCurrentEditing,
                        snapValues: editingValue == .current ? nil : currentSnapValues)
            .onChange(of: calculator.current) { _, _ in
                calculator.updateFromCurrent()
                calculator.objectWillChange.send()
                autoUpdateSavedLoad()
            }
        }
    }
    
    private var lengthSlider: some View {
        let lengthTitleFormat = String(localized: "slider.length.title", defaultValue: "Cable Length (%@)")
        return SliderSection(title: String(format: lengthTitleFormat, locale: Locale.current, unitSettings.unitSystem.lengthUnit),
                    value: Binding(
                        get: { displayLength },
                        set: { newValue in
                            if editingValue == .length {
                                calculator.length = metersFromDisplayLength(roundToTenth(newValue))
                            } else {
                                calculator.length = metersFromDisplayLength(normalizedLength(for: newValue))
                            }
                        }
                    ),
                    range: lengthSliderRange,
                    unit: unitSettings.unitSystem.lengthUnit,
                    tapAction: beginLengthEditing,
                    snapValues: editingValue == .length ? nil : lengthSnapValues)
        .onChange(of: calculator.length) { _, _ in
            calculator.objectWillChange.send()
            autoUpdateSavedLoad()
        }
    }

    private var dutyCycleSlider: some View {
        SliderSection(
            title: dutyCycleTitle,
            value: Binding(
                get: { calculator.dutyCyclePercent },
                set: { newValue in
                    let clamped = clampDutyCyclePercent(newValue)
                    calculator.dutyCyclePercent = clamped
                }
            ),
            range: dutyCycleRange,
            unit: "%",
            tapAction: beginDutyCycleEditing
        )
        .onChange(of: calculator.dutyCyclePercent) { _, newValue in
            let clamped = clampDutyCyclePercent(newValue)
            if abs(clamped - newValue) > 0.0001 {
                calculator.dutyCyclePercent = clamped
            }
            autoUpdateSavedLoad()
        }
    }

    private var usageHoursSlider: some View {
        SliderSection(
            title: usageHoursTitle,
            value: Binding(
                get: { calculator.dailyUsageHours },
                set: { newValue in
                    let clamped = clampUsageHours(newValue)
                    calculator.dailyUsageHours = clamped
                }
            ),
            range: usageHoursRange,
            unit: String(localized: "calculator.advanced.usage_hours.unit", comment: "Unit label for usage hours slider"),
            tapAction: beginUsageHoursEditing
        )
        .onChange(of: calculator.dailyUsageHours) { _, newValue in
            let clamped = clampUsageHours(newValue)
            if abs(clamped - newValue) > 0.0001 {
                calculator.dailyUsageHours = clamped
            }
            autoUpdateSavedLoad()
        }
    }

    private func normalizedVoltage(for value: Double) -> Double {
        let rounded = roundToTenth(value)
        if let snap = nearestValue(to: rounded, in: voltageSnapValues, tolerance: 0.3) {
            return snap
        }
        return rounded
    }

    private func normalizedCurrent(for value: Double) -> Double {
        let rounded = roundToTenth(value)
        if let snap = nearestValue(to: rounded, in: currentSnapValues, tolerance: 0.3) {
            return snap
        }
        return rounded
    }

    private func normalizedPower(for value: Double) -> Double {
        if let snap = nearestValue(to: value, in: powerSnapValues, tolerance: 2.5) {
            return snap
        }
        return roundToNearestFive(value)
    }

    private func normalizedLength(for value: Double) -> Double {
        let rounded = roundToTenth(value)
        if let snap = nearestValue(to: rounded, in: lengthSnapValues, tolerance: 0.5) {
            return snap
        }
        return rounded
    }

    private func clampDutyCyclePercent(_ value: Double) -> Double {
        min(100, max(0, roundToTenth(value)))
    }

    private func clampUsageHours(_ value: Double) -> Double {
        min(24, max(0, roundToTenth(value)))
    }

    private func nearestValue(to value: Double, in options: [Double], tolerance: Double) -> Double? {
        guard let closest = options.min(by: { abs($0 - value) < abs($1 - value) }) else { return nil }
        return abs(closest - value) <= tolerance ? closest : nil
    }

    private func roundToTenth(_ value: Double) -> Double {
        max(0, (value * 10).rounded() / 10)
    }

    // MARK: - Length Unit Conversion (calculator.length is always in meters)

    private static let metersToFeet = 3.28084
    private static let feetToMeters = 0.3048

    /// Length in display units (meters or feet) for showing to the user
    private var displayLength: Double {
        unitSettings.unitSystem == .imperial ? calculator.length * Self.metersToFeet : calculator.length
    }

    /// Convert a display-unit length (meters or feet) back to meters for storage
    private func metersFromDisplayLength(_ displayValue: Double) -> Double {
        unitSettings.unitSystem == .imperial ? displayValue * Self.feetToMeters : displayValue
    }

    private func roundToNearestFive(_ value: Double) -> Double {
        max(0, (value / 5).rounded() * 5)
    }

    private func formattedValue(_ value: Double) -> String {
        Self.editFormatter.string(from: NSNumber(value: roundToTenth(value))) ?? String(format: "%.1f", value)
    }

    private func parseInput(_ text: String) -> Double? {
        let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !trimmed.isEmpty else { return nil }
        if let number = Self.editFormatter.number(from: trimmed)?.doubleValue {
            return number
        }
        let decimalSeparator = Locale.current.decimalSeparator ?? "."
        let altSeparator = decimalSeparator == "." ? "," : "."
        let normalized = trimmed.replacingOccurrences(of: altSeparator, with: decimalSeparator)
        return Self.editFormatter.number(from: normalized)?.doubleValue
    }

    private func beginVoltageEditing() {
        voltageInput = formattedValue(calculator.voltage)
        editingValue = .voltage
    }

    private func beginCurrentEditing() {
        currentInput = formattedValue(calculator.current)
        editingValue = .current
    }

    private func beginPowerEditing() {
        powerInput = formattedValue(calculator.power)
        editingValue = .power
    }

    private func beginLengthEditing() {
        lengthInput = formattedValue(displayLength)
        editingValue = .length
    }

    private func beginDutyCycleEditing() {
        dutyCycleInput = formattedValue(calculator.dutyCyclePercent)
        editingValue = .dutyCycle
    }

    private func beginUsageHoursEditing() {
        usageHoursInput = formattedValue(calculator.dailyUsageHours)
        editingValue = .usageHours
    }
    
    
    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,
            dutyCyclePercent: calculator.dutyCyclePercent,
            dailyUsageHours: calculator.dailyUsageHours,
            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
        calculator.dutyCyclePercent = savedLoad.dutyCyclePercent
        calculator.dailyUsageHours = savedLoad.dailyUsageHours
        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.dutyCyclePercent = calculator.dutyCyclePercent
        savedLoad.dailyUsageHours = calculator.dailyUsageHours
        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 = String(localized: "bom.accessibility.mark.incomplete", defaultValue: "Mark %@ incomplete")
                                return String.localizedStringWithFormat(format, item.title)
                            } else {
                                let format = String(localized: "bom.accessibility.mark.complete", defaultValue: "Mark %@ 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 {
                                let isComponent: Bool
                                if case .component = item.destination { isComponent = true } else { isComponent = false }
                                AnalyticsTracker.log("BOM Item Tapped", properties: [
                                    "item": item.title,
                                    "is_component": isComponent,
                                    "domain": destinationURL.host ?? "unknown",
                                    "load": info.id,
                                ])
                                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 .component(let id):
            return VoltPlanRedirect.componentURL(id: id)
        case .search(let query):
            return VoltPlanRedirect.searchURL(query: query)
        }
    }
}

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]?
    var isButtonVisible: Bool
    
    init(
        title: String,
        value: Binding<Double>,
        range: ClosedRange<Double>,
        unit: String,
        buttonText: String? = nil,
        buttonAction: (() -> Void)? = nil,
        tapAction: (() -> Void)? = nil,
        snapValues: [Double]? = nil,
        isButtonVisible: Bool = true
    ) {
        self.title = title
        self._value = value
        self.range = range
        self.unit = unit
        self.buttonText = buttonText
        self.buttonAction = buttonAction
        self.tapAction = tapAction
        self.snapValues = snapValues
        self.isButtonVisible = isButtonVisible
    }
    
    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            HStack {
                Text(title)
                    .font(.headline)
                Spacer()
                if let buttonText = buttonText {
                    Button(buttonText) {
                        buttonAction?()
                    }
                    .buttonStyle(.borderedProminent)
                    .opacity(isButtonVisible ? 1 : 0)
                    .allowsHitTesting(isButtonVisible)
                    .accessibilityHidden(!isButtonVisible)
                    .disabled(!isButtonVisible || buttonAction == nil)
                }
            }
            
            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) { _, newValue in
                        // Always round to 1 decimal place first
                        var adjusted = (newValue * 10).rounded() / 10

                        if let snapValues = snapValues {
                            // Find the closest snap value
                            if let closest = snapValues.min(by: { abs($0 - adjusted) < abs($1 - adjusted) }),
                               abs(closest - adjusted) < 0.5 {
                                adjusted = closest
                            }
                        }

                        if abs(adjusted - newValue) > 0.000001 {
                            value = adjusted
                        }
                    }
                
                Text(String(format: "%.0f%@", range.upperBound, unit))
                    .font(.caption)
                    .foregroundColor(.secondary)
            }
        }
    }
}

struct EditableSliderRow: View {
    struct AlertCopy {
        let title: String
        let placeholder: String
        let message: String
        let cancelTitle: String
        let saveTitle: String
    }

    let title: String
    let unit: String
    let range: ClosedRange<Double>
    @Binding var value: Double
    var buttonText: String? = nil
    var buttonAction: (() -> Void)? = nil
    var isButtonVisible: Bool = true
    var snapValues: [Double]? = nil
    var sliderTransform: (Double) -> Double = { $0 }
    var alertTransform: (Double) -> Double = { $0 }
    var formatValue: (Double) -> String
    var parseInput: (String) -> Double?
    var alertCopy: AlertCopy

    @State private var isPresentingAlert = false
    @State private var inputText: String = ""

    var body: some View {
        SliderSection(
            title: title,
            value: Binding(
                get: { value },
                set: { newValue in
                    let transformed = sliderTransform(newValue)
                    let clamped = clampedValue(transformed)
                    value = clamped
                }
            ),
            range: range,
            unit: unit,
            buttonText: buttonText,
            buttonAction: buttonAction,
            tapAction: beginEditing,
            snapValues: isPresentingAlert ? nil : snapValues,
            isButtonVisible: isButtonVisible
        )
        .alert(
            alertCopy.title,
            isPresented: $isPresentingAlert
        ) {
            TextField(alertCopy.placeholder, text: $inputText)
                .keyboardType(.decimalPad)
                .onAppear {
                    if inputText.isEmpty {
                        inputText = formatValue(value)
                    }
                }
                .onChange(of: inputText) { _, newValue in
                    guard let parsed = parseInput(newValue) else { return }
                    value = clampedAlertValue(parsed)
                }

            Button(alertCopy.cancelTitle, role: .cancel) {
                inputText = ""
            }

            Button(alertCopy.saveTitle) {
                if let parsed = parseInput(inputText) {
                    value = clampedAlertValue(parsed)
                }
                inputText = ""
            }
        } message: {
            Text(alertCopy.message)
        }
    }

    private func beginEditing() {
        inputText = formatValue(value)
        isPresentingAlert = true
    }

    private func clampedValue(_ newValue: Double) -> Double {
        min(max(range.lowerBound, newValue), range.upperBound)
    }

    private func clampedAlertValue(_ rawValue: Double) -> Double {
        let transformed = alertTransform(rawValue)
        return clampedValue(transformed)
    }
}

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.power = savedLoad.power
        calculator.length = savedLoad.length
        calculator.dutyCyclePercent = savedLoad.dutyCyclePercent
        calculator.dailyUsageHours = savedLoad.dailyUsageHours
    }
    
    private func deleteLoads(offsets: IndexSet) {
        for index in offsets {
            modelContext.delete(savedLoads[index])
        }
    }
}

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