//
//  SystemsView.swift
//  Cable
//
//  Created by Stefan Lange-Hegermann on 09.10.25.
//


import SwiftUI
import SwiftData

struct SystemsView: View {
    @Environment(\.modelContext) private var modelContext
    @EnvironmentObject var unitSettings: UnitSystemSettings
    @Query(sort: \ElectricalSystem.timestamp, order: .reverse) private var systems: [ElectricalSystem]
    @Query(sort: \SavedLoad.timestamp, order: .reverse) private var allLoads: [SavedLoad]
    @State private var systemNavigationTarget: SystemNavigationTarget?
    @State private var showingComponentLibrary = false
    @State private var showingSettings = false
    @State private var hasPerformedInitialAutoNavigation = false

    private let systemColorOptions = [
        "blue", "green", "orange", "red", "purple", "yellow",
        "pink", "teal", "indigo", "mint", "cyan", "brown", "gray"
    ]
    private let defaultSystemIconName = "building.2"
    private var systemIconMappings: [(keywords: [String], icon: String)] {
        [
            (keywords(for: "system.icon.keywords.rv", fallback: ["rv", "van", "camper", "motorhome", "coach"]), "bus"),
            (keywords(for: "system.icon.keywords.truck", fallback: ["truck", "trailer", "rig"]), "truck.box"),
            (keywords(for: "system.icon.keywords.boat", fallback: ["boat", "marine", "yacht", "sail"]), "sailboat"),
            (keywords(for: "system.icon.keywords.plane", fallback: ["plane", "air", "flight"]), "airplane"),
            (keywords(for: "system.icon.keywords.ferry", fallback: ["ferry", "ship"]), "ferry"),
            (keywords(for: "system.icon.keywords.house", fallback: ["house", "home", "cabin", "cottage", "lodge"]), "house"),
            (keywords(for: "system.icon.keywords.building", fallback: ["building", "office", "warehouse", "factory", "facility"]), "building"),
            (keywords(for: "system.icon.keywords.tent", fallback: ["camp", "tent", "outdoor"]), "tent"),
            (keywords(for: "system.icon.keywords.solar", fallback: ["solar", "sun"]), "sun.max"),
            (keywords(for: "system.icon.keywords.battery", fallback: ["battery", "storage"]), "battery.100"),
            (keywords(for: "system.icon.keywords.server", fallback: ["server", "data", "network", "rack"]), "server.rack"),
            (keywords(for: "system.icon.keywords.computer", fallback: ["computer", "electronics", "lab", "tech"]), "cpu"),
            (keywords(for: "system.icon.keywords.gear", fallback: ["gear", "mechanic", "machine", "workshop"]), "gear"),
            (keywords(for: "system.icon.keywords.tool", fallback: ["tool", "maintenance", "repair", "shop"]), "wrench.adjustable"),
            (keywords(for: "system.icon.keywords.hammer", fallback: ["hammer", "carpentry"]), "hammer"),
            (keywords(for: "system.icon.keywords.light", fallback: ["light", "lighting", "lamp"]), "lightbulb"),
            (keywords(for: "system.icon.keywords.bolt", fallback: ["bolt", "power", "electric"]), "bolt"),
            (keywords(for: "system.icon.keywords.plug", fallback: ["plug"]), "powerplug"),
            (keywords(for: "system.icon.keywords.engine", fallback: ["engine", "generator", "motor"]), "engine.combustion"),
            (keywords(for: "system.icon.keywords.fuel", fallback: ["fuel", "diesel", "gas"]), "fuelpump"),
            (keywords(for: "system.icon.keywords.water", fallback: ["water", "pump", "tank"]), "drop"),
            (keywords(for: "system.icon.keywords.heat", fallback: ["heat", "heater", "furnace"]), "flame"),
            (keywords(for: "system.icon.keywords.cold", fallback: ["cold", "freeze", "cool"]), "snowflake"),
            (keywords(for: "system.icon.keywords.climate", fallback: ["climate", "hvac", "temperature"]), "thermometer")
        ]
    }

    private struct SystemNavigationTarget: Identifiable, Hashable {
        let id = UUID()
        let system: ElectricalSystem
        let presentSystemEditor: Bool
        let loadToOpenOnAppear: SavedLoad?
        
        static func == (lhs: SystemNavigationTarget, rhs: SystemNavigationTarget) -> Bool {
            lhs.id == rhs.id
        }
        
        func hash(into hasher: inout Hasher) {
            hasher.combine(id)
        }
    }

    var body: some View {
        NavigationStack {
            Group {
                if systems.isEmpty {
                    systemsEmptyState
                } else {
                    List {
                        ForEach(systems) { system in
                            Button {
                                handleSystemSelection(system)
                            } label: {
                                systemRow(for: system)
                                    .contentShape(Rectangle())
                            }
                            .buttonStyle(.plain)
                            .accessibilityLabel(system.name)
                            .accessibilityHint(Text("systems.list.row.accessibility.hint", comment: "Accessibility hint for systems list row"))
                            .accessibilityAddTraits(.isButton)
                        }
                        .onDelete(perform: deleteSystems)
                    }
                    .accessibilityIdentifier("systems-list")
                }
            }
            .navigationTitle("Systems")
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button {
                        openSettings()
                    } label: {
                        Image(systemName: "gearshape")
                    }
                }
                ToolbarItem(placement: .navigationBarTrailing) {
                    HStack {
                        Button(action: {
                            AnalyticsTracker.log("System Create Navigation")
                            createNewSystem()
                        }) {
                            Image(systemName: "plus")
                        }
                        EditButton()
                    }
                }
            }
            .navigationDestination(item: $systemNavigationTarget) { target in
                LoadsView(
                    system: target.system,
                    presentSystemEditorOnAppear: target.presentSystemEditor,
                    loadToOpenOnAppear: target.loadToOpenOnAppear
                )
            }
        }
        .onAppear {
            performInitialAutoNavigationIfNeeded()
        }
        .sheet(isPresented: $showingComponentLibrary) {
            ComponentLibraryView { item in
                addComponentFromLibrary(item)
            }
        }
        .sheet(isPresented: $showingSettings) {
            SettingsView()
                .environmentObject(unitSettings)
        }
    }
    
    private var systemsEmptyState: some View {
        SystemsOnboardingView { name in
            createOnboardingSystem(named: name)
        }
    }

    private func openSettings() {
        AnalyticsTracker.log("Settings Opened")
        showingSettings = true
    }
    
    private func handleSystemSelection(_ system: ElectricalSystem) {
        AnalyticsTracker.log(
            "System Opened",
            properties: [
                "name": system.name,
                "source": "list"
            ]
        )
        navigateToSystem(
            system,
            presentSystemEditor: false,
            loadToOpen: nil,
            source: "list"
        )
    }
    
    @ViewBuilder
    private func systemRow(for system: ElectricalSystem) -> some View {
        HStack(spacing: 12) {
            ZStack {
                RoundedRectangle(cornerRadius: 10)
                    .fill(Color.componentColor(named: system.colorName))
                    .frame(width: 44, height: 44)

                Image(systemName: system.iconName)
                    .font(.title3)
                    .foregroundColor(.white)
            }

            VStack(alignment: .leading, spacing: 4) {
                Text(system.name)
                    .fontWeight(.medium)

                if !system.location.isEmpty {
                    Text(system.location)
                        .font(.caption)
                        .foregroundColor(.secondary)
                }

                Text(componentSummary(for: system))
                    .font(.caption)
                    .foregroundColor(.secondary)
            }

            Spacer()

            Image(systemName: "chevron.right")
                .font(.footnote.weight(.semibold))
                .foregroundColor(.secondary.opacity(0.6))
        }
        .padding(.vertical, 4)
        .frame(maxWidth: .infinity, alignment: .leading)
    }
    
    private func createNewSystem() {
        let system = makeSystem()
        AnalyticsTracker.log(
            "System Created",
            properties: [
                "name": system.name,
                "source": "toolbar"
            ]
        )
        navigateToSystem(
            system,
            presentSystemEditor: true,
            loadToOpen: nil,
            source: "created"
        )
    }

    private func createNewSystem(named name: String) {
        let system = makeSystem(preferredName: name)
        AnalyticsTracker.log(
            "System Created",
            properties: [
                "name": system.name,
                "source": "named"
            ]
        )
        navigateToSystem(
            system,
            presentSystemEditor: true,
            loadToOpen: nil,
            source: "created-named"
        )
    }

    private func createOnboardingSystem(named name: String) {
        let system = makeSystem(
            preferredName: name,
            colorName: randomSystemColorName()
        )
        navigateToSystem(
            system,
            presentSystemEditor: false,
            loadToOpen: nil,
            source: "onboarding"
        )
    }

    private func navigateToSystem(
        _ system: ElectricalSystem,
        presentSystemEditor: Bool,
        loadToOpen: SavedLoad?,
        animated: Bool = true,
        source: String = "programmatic"
    ) {
        AnalyticsTracker.log(
            "System Opened",
            properties: [
                "name": system.name,
                "source": source,
                "loads": loads(for: system).count
            ]
        )
        let target = SystemNavigationTarget(
            system: system,
            presentSystemEditor: presentSystemEditor,
            loadToOpenOnAppear: loadToOpen
        )

        if animated {
            systemNavigationTarget = target
        } else {
            var transaction = Transaction()
            transaction.disablesAnimations = true
            withTransaction(transaction) {
                systemNavigationTarget = target
            }
        }
    }

    @discardableResult
    private func makeSystem(preferredName: String? = nil, colorName: String? = nil, iconName: String? = nil) -> ElectricalSystem {
        let existingNames = Set(systems.map { $0.name })
        let trimmedPreferred = preferredName?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
        let baseName = trimmedPreferred.isEmpty ? String(localized: "default.system.new", comment: "Default name for a newly created system") : trimmedPreferred
        var systemName = baseName
        var counter = 2

        while existingNames.contains(systemName) {
            systemName = "\(baseName) \(counter)"
            counter += 1
        }

        let resolvedColorName = colorName ?? "blue"
        let resolvedIconName = iconName ?? systemIconName(for: systemName)

        let newSystem = ElectricalSystem(
            name: systemName,
            location: "",
            iconName: resolvedIconName,
            colorName: resolvedColorName
        )
        modelContext.insert(newSystem)
        return newSystem
    }

    private func performInitialAutoNavigationIfNeeded() {
        guard !hasPerformedInitialAutoNavigation else { return }
        hasPerformedInitialAutoNavigation = true

        guard systems.count == 1, let system = systems.first else { return }
        navigateToSystem(
            system,
            presentSystemEditor: false,
            loadToOpen: nil,
            animated: false,
            source: "auto"
        )
    }

    private func addComponentFromLibrary(_ item: ComponentLibraryItem) {
        let system = makeSystem()
        AnalyticsTracker.log(
            "System Created",
            properties: [
                "name": system.name,
                "source": "library"
            ]
        )
        let load = createLoad(from: item, in: system)
        AnalyticsTracker.log(
            "Library Load Added",
            properties: [
                "id": item.id,
                "name": item.localizedName,
                "system": system.name
            ]
        )
        navigateToSystem(
            system,
            presentSystemEditor: false,
            loadToOpen: load,
            animated: false,
            source: "library"
        )
    }

    private func createLoad(from item: ComponentLibraryItem, in system: ElectricalSystem) -> SavedLoad {
        let localizedName = item.localizedName
        let baseName = localizedName.isEmpty
            ? String(localized: "default.load.library", comment: "Default name when importing a library load")
            : localizedName
        let loadName = uniqueLoadName(for: system, startingWith: baseName)
        let voltage = item.displayVoltage ?? 12.0

        let power: Double
        if let watt = item.watt {
            power = watt
        } else if let derivedCurrent = item.current, voltage > 0 {
            power = derivedCurrent * voltage
        } else {
            power = 0
        }

        let current: Double
        if let explicitCurrent = item.current {
            current = explicitCurrent
        } else if voltage > 0 {
            current = power / voltage
        } else {
            current = 0
        }

        let dutyCyclePercent = item.normalizedDutyCyclePercent ?? 100
        let dailyUsageHours = item.defaultDailyUsageHours ?? 1

        let newLoad = SavedLoad(
            name: loadName,
            voltage: voltage,
            current: current,
            power: power,
            length: 10.0,
            crossSection: 1.0,
            iconName: "lightbulb",
            colorName: "blue",
            isWattMode: item.watt != nil,
            dutyCyclePercent: dutyCyclePercent,
            dailyUsageHours: dailyUsageHours,
            system: system,
            remoteIconURLString: item.iconURL?.absoluteString,
            componentID: item.id
        )

        modelContext.insert(newLoad)
        return newLoad
    }

    private func uniqueLoadName(for system: ElectricalSystem, startingWith baseName: String) -> String {
        let descriptor = FetchDescriptor<SavedLoad>()
        let fetchedLoads = (try? modelContext.fetch(descriptor)) ?? []
        let existingNames = Set(fetchedLoads.filter { $0.system == system }.map { $0.name })

        if !existingNames.contains(baseName) {
            return baseName
        }

        var counter = 2
        var candidate = "\(baseName) \(counter)"

        while existingNames.contains(candidate) {
            counter += 1
            candidate = "\(baseName) \(counter)"
        }

        return candidate
    }
    
    private func deleteSystems(offsets: IndexSet) {
        let systemsToDelete = offsets.map { systems[$0] }
        withAnimation {
            for system in systemsToDelete {
                AnalyticsTracker.log(
                    "System Deleted",
                    properties: [
                        "name": system.name,
                        "loads": loads(for: system).count
                    ]
                )
                deleteLoads(for: system)
                modelContext.delete(system)
            }
        }
    }

    private func deleteLoads(for system: ElectricalSystem) {
        let descriptor = FetchDescriptor<SavedLoad>()
        if let loads = try? modelContext.fetch(descriptor) {
            for load in loads where load.system == system {
                AnalyticsTracker.log(
                    "Load Deleted",
                    properties: [
                        "name": load.name,
                        "system": system.name,
                        "source": "system-delete"
                    ]
                )
                modelContext.delete(load)
            }
        }
    }

    private func loads(for system: ElectricalSystem) -> [SavedLoad] {
        allLoads.filter { $0.system == system }
    }

    private func componentSummary(for system: ElectricalSystem) -> String {
        let systemLoads = loads(for: system)
        guard !systemLoads.isEmpty else {
            return String(localized: "system.list.no.components", comment: "Message shown when a system has no components yet")
        }

        let count = systemLoads.count
        let totalPower = systemLoads.reduce(0.0) { $0 + $1.power }

        let formattedPower: String
        if totalPower >= 1000 {
            formattedPower = String(format: "%.1fkW", totalPower / 1000)
        } else {
            formattedPower = String(format: "%.0fW", totalPower)
        }

        let format = String(localized: "system.list.component.summary", defaultValue: "%#@component_count@ • %@")
        return String.localizedStringWithFormat(format, count, formattedPower)
    }

    private func randomSystemColorName() -> String {
        systemColorOptions.randomElement() ?? "blue"
    }

    private func systemIconName(for name: String) -> String {
        let normalized = name
            .folding(options: [.diacriticInsensitive, .caseInsensitive], locale: .current)
            .lowercased()

        for mapping in systemIconMappings {
            if mapping.keywords.contains(where: { keyword in normalized.contains(keyword) }) {
                return mapping.icon
            }
        }

        return defaultSystemIconName
    }

    private func keywords(for localizationKey: String, fallback: [String]) -> [String] {
        let fallbackValue = fallback.joined(separator: ",")
        let localizedKeywords = Bundle.main.localizedString(
            forKey: localizationKey,
            value: fallbackValue,
            table: nil
        )
        let separators = CharacterSet(charactersIn: ",;")
        let components = localizedKeywords
            .components(separatedBy: separators)
            .map { $0.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() }
            .filter { !$0.isEmpty }

        var uniqueKeywords: [String] = []

        for keyword in fallback.map({ $0.lowercased() }) + components {
            if !uniqueKeywords.contains(keyword) {
                uniqueKeywords.append(keyword)
            }
        }

        return uniqueKeywords
    }

}

#Preview("Sample Systems") {
    // An in-memory SwiftData container for previews so we don't persist anything
    let configuration = ModelConfiguration(isStoredInMemoryOnly: true)
    let container = try! ModelContainer(for: ElectricalSystem.self, SavedLoad.self, configurations: configuration)

    // Seed sample data only once per preview session
    if (try? ModelContext(container).fetch(FetchDescriptor<ElectricalSystem>()))?.isEmpty ?? true {
        let context = ModelContext(container)

        // Sample systems
        let system1 = ElectricalSystem(name: "Camper Van", location: "Road Trip", iconName: "bus", colorName: "teal")
        let system2 = ElectricalSystem(name: "Sailboat Aurora", location: "Marina 7", iconName: "sailboat", colorName: "blue")

        context.insert(system1)
        context.insert(system2)

        // Sample loads for system 1
        let load1 = SavedLoad(
            name: "LED Cabin Light",
            voltage: 12,
            current: 0.5,
            power: 6,
            length: 5,
            crossSection: 1.5,
            iconName: "lightbulb",
            colorName: "yellow",
            isWattMode: false,
            system: system1,
            remoteIconURLString: nil,
            componentID: nil
        )

        let load2 = SavedLoad(
            name: "Water Pump",
            voltage: 12,
            current: 5,
            power: 60,
            length: 3,
            crossSection: 2.5,
            iconName: "drop",
            colorName: "blue",
            isWattMode: false,
            system: system1,
            remoteIconURLString: nil,
            componentID: nil
        )

        // Sample loads for system 2
        let load3 = SavedLoad(
            name: "Navigation Lights",
            voltage: 12,
            current: 1.2,
            power: 14.4,
            length: 8,
            crossSection: 1.5,
            iconName: "lightbulb",
            colorName: "green",
            isWattMode: false,
            system: system2,
            remoteIconURLString: nil,
            componentID: nil
        )

        context.insert(load1)
        context.insert(load2)
        context.insert(load3)
    }

    return SystemsView()
        .modelContainer(container)
        .environmentObject(UnitSystemSettings())
}
