import SwiftUI

@MainActor
struct ConfigSettings: View {
    @State private var configModel: String = ""
    @State private var customModel: String = ""
    @State private var configSaving = false
    @State private var hasLoaded = false
    @State private var models: [ModelChoice] = []
    @State private var modelsLoading = false
    @State private var modelError: String?
    @AppStorage(modelCatalogPathKey) private var modelCatalogPath: String = ModelCatalogLoader.defaultPath
    @AppStorage(modelCatalogReloadKey) private var modelCatalogReloadBump: Int = 0
    @State private var allowAutosave = false
    @State private var heartbeatMinutes: Int?
    @State private var heartbeatBody: String = "HEARTBEAT"
    @AppStorage(webChatEnabledKey) private var webChatEnabled: Bool = true
    @AppStorage(webChatPortKey) private var webChatPort: Int = 18788

    var body: some View {
        VStack(alignment: .leading, spacing: 14) {
            Text("Clawdis CLI config")
                .font(.title3.weight(.semibold))
            Text("Edit ~/.clawdis/clawdis.json (inbound.reply.agent/session).")
                .font(.callout)
                .foregroundStyle(.secondary)

            LabeledContent("Model") {
                VStack(alignment: .leading, spacing: 6) {
                    Picker("Model", selection: self.$configModel) {
                        ForEach(self.models) { choice in
                            Text(
                                "\(choice.name) — \(choice.provider.uppercased())")
                                .tag(choice.id)
                        }
                        Text("Manual entry…").tag("__custom__")
                    }
                    .labelsHidden()
                    .frame(width: 360)
                    .disabled(self.modelsLoading || (!self.modelError.isNilOrEmpty && self.models.isEmpty))
                    .onChange(of: self.configModel) { _, _ in
                        self.autosaveConfig()
                    }

                    if self.configModel == "__custom__" {
                        TextField("Enter model ID", text: self.$customModel)
                            .textFieldStyle(.roundedBorder)
                            .frame(width: 320)
                            .onChange(of: self.customModel) { _, newValue in
                                self.configModel = newValue
                                self.autosaveConfig()
                            }
                    }

                    if let contextLabel = self.selectedContextLabel {
                        Text(contextLabel)
                            .font(.footnote)
                            .foregroundStyle(.secondary)
                    }

                    if let modelError {
                        Text(modelError)
                            .font(.footnote)
                            .foregroundStyle(.secondary)
                    }
                }
            }

            LabeledContent("Heartbeat") {
                VStack(alignment: .leading, spacing: 6) {
                    HStack(spacing: 12) {
                        Stepper(
                            value: Binding(
                                get: { self.heartbeatMinutes ?? 10 },
                                set: { self.heartbeatMinutes = $0; self.autosaveConfig() }),
                            in: 0...720)
                        {
                            Text("Every \(self.heartbeatMinutes ?? 10) min")
                        }
                        .help("Set to 0 to disable automatic heartbeats")

                        TextField("HEARTBEAT", text: self.$heartbeatBody)
                            .textFieldStyle(.roundedBorder)
                            .frame(width: 240)
                            .onChange(of: self.heartbeatBody) { _, _ in
                                self.autosaveConfig()
                            }
                            .help("Message body sent on each heartbeat")
                    }

                    Text("Heartbeats keep Pi sessions warm; 0 minutes disables them.")
                        .font(.footnote)
                        .foregroundStyle(.secondary)
                }
            }

            Divider().padding(.vertical, 4)

            LabeledContent("Web chat") {
                VStack(alignment: .leading, spacing: 6) {
                    Toggle("Enable embedded web chat (loopback only)", isOn: self.$webChatEnabled)
                        .toggleStyle(.switch)
                        .frame(width: 320, alignment: .leading)
                    HStack(spacing: 8) {
                        Text("Port")
                        TextField("18788", value: self.$webChatPort, formatter: NumberFormatter())
                            .textFieldStyle(.roundedBorder)
                            .frame(width: 100)
                            .disabled(!self.webChatEnabled)
                    }
                    Text(
                        """
                        Mac app connects to the relay’s loopback web chat on this port.
                        Remote mode uses SSH -L to forward it.
                        """)
                        .font(.footnote)
                        .foregroundStyle(.secondary)
                        .frame(maxWidth: 480, alignment: .leading)
                }
            }

            Spacer()
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .padding(.horizontal, 12)
        .onChange(of: self.modelCatalogPath) { _, _ in
            Task { await self.loadModels() }
        }
        .onChange(of: self.modelCatalogReloadBump) { _, _ in
            Task { await self.loadModels() }
        }
        .task {
            guard !self.hasLoaded else { return }
            self.hasLoaded = true
            self.loadConfig()
            await self.loadModels()
            self.allowAutosave = true
        }
    }

    private func configURL() -> URL {
        FileManager.default.homeDirectoryForCurrentUser
            .appendingPathComponent(".clawdis")
            .appendingPathComponent("clawdis.json")
    }

    private func loadConfig() {
        let parsed = self.loadConfigDict()
        let inbound = parsed["inbound"] as? [String: Any]
        let reply = inbound?["reply"] as? [String: Any]
        let agent = reply?["agent"] as? [String: Any]
        let heartbeatMinutes = reply?["heartbeatMinutes"] as? Int
        let heartbeatBody = reply?["heartbeatBody"] as? String

        let loadedModel = (agent?["model"] as? String) ?? ""
        if !loadedModel.isEmpty {
            self.configModel = loadedModel
            self.customModel = loadedModel
        } else {
            self.configModel = SessionLoader.fallbackModel
            self.customModel = SessionLoader.fallbackModel
        }

        if let heartbeatMinutes { self.heartbeatMinutes = heartbeatMinutes }
        if let heartbeatBody, !heartbeatBody.isEmpty { self.heartbeatBody = heartbeatBody }
    }

    private func autosaveConfig() {
        guard self.allowAutosave else { return }
        Task { await self.saveConfig() }
    }

    private func saveConfig() async {
        guard !self.configSaving else { return }
        self.configSaving = true
        defer { self.configSaving = false }

        var root = self.loadConfigDict()
        var inbound = root["inbound"] as? [String: Any] ?? [:]
        var reply = inbound["reply"] as? [String: Any] ?? [:]
        var agent = reply["agent"] as? [String: Any] ?? [:]

        let chosenModel = (self.configModel == "__custom__" ? self.customModel : self.configModel)
            .trimmingCharacters(in: .whitespacesAndNewlines)
        let trimmedModel = chosenModel
        if !trimmedModel.isEmpty { agent["model"] = trimmedModel }

        reply["agent"] = agent

        if let heartbeatMinutes {
            reply["heartbeatMinutes"] = heartbeatMinutes
        }

        let trimmedBody = self.heartbeatBody.trimmingCharacters(in: .whitespacesAndNewlines)
        if !trimmedBody.isEmpty {
            reply["heartbeatBody"] = trimmedBody
        }

        inbound["reply"] = reply
        root["inbound"] = inbound

        do {
            let data = try JSONSerialization.data(withJSONObject: root, options: [.prettyPrinted, .sortedKeys])
            let url = self.configURL()
            try FileManager.default.createDirectory(
                at: url.deletingLastPathComponent(),
                withIntermediateDirectories: true)
            try data.write(to: url, options: [.atomic])
        } catch {}
    }

    private func loadConfigDict() -> [String: Any] {
        let url = self.configURL()
        guard let data = try? Data(contentsOf: url) else { return [:] }
        return (try? JSONSerialization.jsonObject(with: data) as? [String: Any]) ?? [:]
    }

    private func loadModels() async {
        guard !self.modelsLoading else { return }
        self.modelsLoading = true
        self.modelError = nil
        do {
            let loaded = try await ModelCatalogLoader.load(from: self.modelCatalogPath)
            self.models = loaded
            if !self.configModel.isEmpty, !loaded.contains(where: { $0.id == self.configModel }) {
                self.customModel = self.configModel
                self.configModel = "__custom__"
            }
        } catch {
            self.modelError = error.localizedDescription
            self.models = []
        }
        self.modelsLoading = false
    }

    private var selectedContextLabel: String? {
        let chosenId = (self.configModel == "__custom__") ? self.customModel : self.configModel
        guard
            !chosenId.isEmpty,
            let choice = self.models.first(where: { $0.id == chosenId }),
            let context = choice.contextWindow
        else {
            return nil
        }

        let human = context >= 1000 ? "\(context / 1000)k" : "\(context)"
        return "Context window: \(human) tokens"
    }
}
