//
//  MainView.swift
//  iKeyMon
//
//  Created by tracer on 30.03.25.
//

import SwiftUI

struct MainView: View {
    
    private static let serverOrderKeyStatic = "serverOrder"
    private static let storedServersKeyStatic = "storedServers"

    @EnvironmentObject private var sparkleUpdater: SparkleUpdater
    @State var showAddServerSheet: Bool = false
    @State private var serverBeingEdited: Server?
    @State private var serverToDelete: Server?
    @State private var showDeleteConfirmation = false
    @State private var isFetchingInfo: Bool = false
    @State private var refreshTimer = Timer.publish(every: 60, on: .main, in: .common).autoconnect()
    @State private var pingTimer: Timer?
    private let serverOrderKey = MainView.serverOrderKeyStatic
    private let storedServersKey = MainView.storedServersKeyStatic

    @State private var servers: [Server] = MainView.loadStoredServers()

//    @State private var selectedServer: Server?
    @State private var selectedServerID: UUID?

    var body: some View {
        var mainContent: some View {
            NavigationSplitView {
                List(selection: $selectedServerID) {
                ForEach(servers) { server in
                    HStack {
                        Image(systemName: "dot.circle.fill")
                            .foregroundColor(server.pingable ? .green : .red)
                        Text(server.hostname)
                    }
                    .tag(server)
                    .contextMenu {
                        Button("Edit") {
                            print("Editing:", server.hostname)
                            serverBeingEdited = server
                        }
                        Divider()
                        Button("Delete", role: .destructive) {
                            serverToDelete = server
                            showDeleteConfirmation = true
                        }
                    }
                }
                .onMove(perform: moveServer)
            }
            .toolbar {
                ToolbarItem(placement: .primaryAction) {
                    Button(action: { showAddServerSheet = true }) {
                        Image(systemName: "plus")
                    }
                    .help("Add Host")
                }
                ToolbarItem {
                    Button {
                        sparkleUpdater.checkForUpdates()
                    } label: {
                        Image(systemName: "square.and.arrow.down")
                    }
                    .help("Check for Updates")
                }
            }
            .navigationTitle("Servers")
            .onChange(of: selectedServerID) {
                if let selectedServerID {
                    UserDefaults.standard.set(selectedServerID.uuidString, forKey: "selectedServerID")
                    fetchServerInfo(for: selectedServerID)
                }
            }
        } detail: {
            if let selectedServerID,
               let index = servers.firstIndex(where: { selectedServerID == $0.id }) {
                ServerDetailView(server: $servers[index], isFetching: isFetchingInfo)
            } else {
                ContentUnavailableView("No Server Selected", systemImage: "server.rack")
            }
            }
        }
        return mainContent
        .sheet(isPresented: $showAddServerSheet) {
            ServerFormView(
                mode: .add,
                servers: $servers,
                dismiss: { showAddServerSheet = false }
            )
        }
        .sheet(item: $serverBeingEdited) { server in
            ServerFormView(
                mode: .edit(server),
                servers: $servers,
                dismiss: { serverBeingEdited = nil }
            )
        }
        .alert("Are you sure you want to delete this server?", isPresented: $showDeleteConfirmation, presenting: serverToDelete) { server in
            Button("Delete", role: .destructive) {
                ServerFormView.delete(server: server, from: &servers)
            }
            Button("Cancel", role: .cancel) {}
        }
        .onReceive(refreshTimer) { _ in
            for server in servers {
                fetchServerInfo(for: server.id)
            }
        }
        .onAppear {
            let initialID: UUID?
            if let storedID = UserDefaults.standard.string(forKey: "selectedServerID"),
               let uuid = UUID(uuidString: storedID),
               servers.contains(where: { $0.id == uuid }) {
                print("✅ [MainView] Restored selected server \(uuid)")
                initialID = uuid
            } else if let first = servers.first {
                print("✅ [MainView] Selecting first server \(first.hostname)")
                initialID = first.id
            } else {
                print("ℹ️ [MainView] No stored selection")
                initialID = nil
            }

            selectedServerID = initialID

            if let initialID {
                Task {
                    await prefetchOtherServers(activeID: initialID)
                }
            }
            pingAllServers()
            pingTimer = Timer.scheduledTimer(withTimeInterval: 10.0, repeats: true) { _ in
                pingAllServers()
            }
        }
        .frame(minWidth: 800, minHeight: 450)
    }
    
    private func fetchServerInfo(for id: UUID) {
        guard let server = servers.first(where: { $0.id == id }) else {
            print("❌ [MainView] fetchServerInfo: server not found for id \(id)")
            return
        }
        guard let apiKey = KeychainHelper.loadApiKey(for: server.hostname)?.trimmingCharacters(in: .whitespacesAndNewlines),
              !apiKey.isEmpty else {
            print("❌ [MainView] fetchServerInfo: missing API key for \(server.hostname)")
            return
        }
        guard let baseURL = URL(string: "https://\(server.hostname)") else {
            print("❌ [MainView] Invalid base URL for \(server.hostname)")
            return
        }

        isFetchingInfo = true

        Task {
            defer { isFetchingInfo = false }
            do {
                let api = try await APIFactory.detectAndCreateAPI(baseURL: baseURL, apiKey: apiKey)
                let info = try await api.fetchServerSummary(apiKey: apiKey)
                await MainActor.run {
                    if let index = servers.firstIndex(where: { $0.id == id }) {
                        var updated = servers[index]
                        updated.info = info
                        servers[index] = updated
                    }
                }
            } catch {
                print("❌ Failed to fetch server data: \(error)")
            }
        }
    }

    private func prefetchOtherServers(activeID: UUID) async {
        let others = servers.filter { $0.id != activeID }
        await withTaskGroup(of: Void.self) { group in
            for server in others {
                group.addTask {
                    await fetchServerInfoAsync(for: server.id)
                }
            }
        }
    }

    private func fetchServerInfoAsync(for id: UUID) async {
        guard let server = servers.first(where: { $0.id == id }) else { return }
        guard let apiKey = KeychainHelper.loadApiKey(for: server.hostname)?.trimmingCharacters(in: .whitespacesAndNewlines),
              !apiKey.isEmpty,
              let baseURL = URL(string: "https://\(server.hostname)")
        else { return }

        do {
            let api = try await APIFactory.detectAndCreateAPI(baseURL: baseURL, apiKey: apiKey)
            let info = try await api.fetchServerSummary(apiKey: apiKey)
            await MainActor.run {
                if let index = servers.firstIndex(where: { $0.id == id }) {
                    var updated = servers[index]
                    updated.info = info
                    servers[index] = updated
                }
            }
        } catch {
            print("❌ Prefetch failed for \(server.hostname): \(error)")
        }
    }
    
    private func moveServer(from source: IndexSet, to destination: Int) {
        servers.move(fromOffsets: source, toOffset: destination)
        saveServerOrder()
    }
    
    private func saveServerOrder() {
        let ids = servers.map { $0.id.uuidString }
        UserDefaults.standard.set(ids, forKey: serverOrderKey)
        print("💾 [MainView] Saved server order with \(ids.count) entries")
    }
    
    private struct PingResponse: Codable {
        let response: String
    }
        
    func pingAllServers() {
        for (index, server) in servers.enumerated() {
            Task {
                let apiKey = KeychainHelper.loadApiKey(for: server.hostname)?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
                let pingable = await PingService.ping(hostname: server.hostname, apiKey: apiKey)
                await MainActor.run {
                    servers[index].pingable = pingable
                }
                if !pingable {
                    print("📶 [MainView] Ping \(server.hostname): offline")
                }
            }
        }
    }

    private static func loadStoredServers() -> [Server] {
        let defaults = UserDefaults.standard
        guard let data = defaults.data(forKey: storedServersKeyStatic) else {
            print("ℹ️ [MainView] No storedServers data found")
            return []
        }
        do {
            let saved = try JSONDecoder().decode([Server].self, from: data)
            print("📦 [MainView] Loaded \(saved.count) servers from UserDefaults")
            if let order = defaults.stringArray(forKey: serverOrderKeyStatic) {
                let idMap = order.compactMap(UUID.init)
                let sorted = saved.sorted { a, b in
                    guard
                        let i1 = idMap.firstIndex(of: a.id),
                        let i2 = idMap.firstIndex(of: b.id)
                    else { return false }
                    return i1 < i2
                }
                return sorted
            }
            return saved
        } catch {
            print("❌ [MainView] Failed to decode stored servers: \(error)")
            return []
        }
    }
}

#Preview {
    MainView()
        .environmentObject(SparkleUpdater())
}
