import Foundation
import Observation

@MainActor
@Observable
final class SybilSettingsStore {
    private enum Keys {
        static let apiBaseURL = "sybil.ios.apiBaseURL"
        static let adminToken = "sybil.ios.adminToken"
        static let preferredProvider = "sybil.ios.preferredProvider"
        static let preferredOpenAIModel = "sybil.ios.preferredOpenAIModel"
        static let preferredAnthropicModel = "sybil.ios.preferredAnthropicModel"
        static let preferredXAIModel = "sybil.ios.preferredXAIModel"
        static let preferredGeminiModel = "sybil.ios.preferredGeminiModel"
        static let preferredHermesAgentModel = "sybil.ios.preferredHermesAgentModel"
        static let quickQuestionPreferredProvider = "sybil.ios.quickQuestionPreferredProvider"
        static let quickQuestionPreferredOpenAIModel = "sybil.ios.quickQuestionPreferredOpenAIModel"
        static let quickQuestionPreferredAnthropicModel = "sybil.ios.quickQuestionPreferredAnthropicModel"
        static let quickQuestionPreferredXAIModel = "sybil.ios.quickQuestionPreferredXAIModel"
        static let quickQuestionPreferredGeminiModel = "sybil.ios.quickQuestionPreferredGeminiModel"
        static let quickQuestionPreferredHermesAgentModel = "sybil.ios.quickQuestionPreferredHermesAgentModel"
    }

    private let defaults: UserDefaults

    var apiBaseURL: String
    var adminToken: String
    var preferredProvider: Provider
    var preferredModelByProvider: [Provider: String]
    var quickQuestionPreferredProvider: Provider
    var quickQuestionPreferredModelByProvider: [Provider: String]

    init(defaults: UserDefaults = .standard) {
        self.defaults = defaults

        let storedBaseURL = defaults.string(forKey: Keys.apiBaseURL)?.trimmingCharacters(in: .whitespacesAndNewlines)
        let fallbackBaseURL = "http://127.0.0.1:8787"
        self.apiBaseURL = storedBaseURL?.isEmpty == false ? storedBaseURL! : fallbackBaseURL

        self.adminToken = defaults.string(forKey: Keys.adminToken) ?? ""

        let provider = defaults.string(forKey: Keys.preferredProvider).flatMap(Provider.init(rawValue:)) ?? .openai
        self.preferredProvider = provider

        let preferredModels: [Provider: String] = [
            .openai: defaults.string(forKey: Keys.preferredOpenAIModel) ?? "gpt-4.1-mini",
            .anthropic: defaults.string(forKey: Keys.preferredAnthropicModel) ?? "claude-3-5-sonnet-latest",
            .xai: defaults.string(forKey: Keys.preferredXAIModel) ?? "grok-3-mini",
            .gemini: defaults.string(forKey: Keys.preferredGeminiModel) ?? "gemini-3.5-flash",
            .hermesAgent: defaults.string(forKey: Keys.preferredHermesAgentModel) ?? "hermes-agent"
        ]
        self.preferredModelByProvider = preferredModels

        self.quickQuestionPreferredProvider =
            defaults.string(forKey: Keys.quickQuestionPreferredProvider).flatMap(Provider.init(rawValue:)) ?? provider
        self.quickQuestionPreferredModelByProvider = [
            .openai: defaults.string(forKey: Keys.quickQuestionPreferredOpenAIModel) ?? preferredModels[.openai] ?? "gpt-4.1-mini",
            .anthropic: defaults.string(forKey: Keys.quickQuestionPreferredAnthropicModel) ?? preferredModels[.anthropic] ?? "claude-3-5-sonnet-latest",
            .xai: defaults.string(forKey: Keys.quickQuestionPreferredXAIModel) ?? preferredModels[.xai] ?? "grok-3-mini",
            .gemini: defaults.string(forKey: Keys.quickQuestionPreferredGeminiModel) ?? preferredModels[.gemini] ?? "gemini-3.5-flash",
            .hermesAgent: defaults.string(forKey: Keys.quickQuestionPreferredHermesAgentModel) ?? preferredModels[.hermesAgent] ?? "hermes-agent"
        ]
    }

    func persist() {
        defaults.set(apiBaseURL.trimmingCharacters(in: .whitespacesAndNewlines), forKey: Keys.apiBaseURL)

        let trimmedToken = adminToken.trimmingCharacters(in: .whitespacesAndNewlines)
        if trimmedToken.isEmpty {
            defaults.removeObject(forKey: Keys.adminToken)
        } else {
            defaults.set(trimmedToken, forKey: Keys.adminToken)
        }

        defaults.set(preferredProvider.rawValue, forKey: Keys.preferredProvider)
        defaults.set(preferredModelByProvider[.openai], forKey: Keys.preferredOpenAIModel)
        defaults.set(preferredModelByProvider[.anthropic], forKey: Keys.preferredAnthropicModel)
        defaults.set(preferredModelByProvider[.xai], forKey: Keys.preferredXAIModel)
        defaults.set(preferredModelByProvider[.gemini], forKey: Keys.preferredGeminiModel)
        defaults.set(preferredModelByProvider[.hermesAgent], forKey: Keys.preferredHermesAgentModel)

        defaults.set(quickQuestionPreferredProvider.rawValue, forKey: Keys.quickQuestionPreferredProvider)
        defaults.set(quickQuestionPreferredModelByProvider[.openai], forKey: Keys.quickQuestionPreferredOpenAIModel)
        defaults.set(quickQuestionPreferredModelByProvider[.anthropic], forKey: Keys.quickQuestionPreferredAnthropicModel)
        defaults.set(quickQuestionPreferredModelByProvider[.xai], forKey: Keys.quickQuestionPreferredXAIModel)
        defaults.set(quickQuestionPreferredModelByProvider[.gemini], forKey: Keys.quickQuestionPreferredGeminiModel)
        defaults.set(quickQuestionPreferredModelByProvider[.hermesAgent], forKey: Keys.quickQuestionPreferredHermesAgentModel)
    }

    var trimmedTokenOrNil: String? {
        let value = adminToken.trimmingCharacters(in: .whitespacesAndNewlines)
        return value.isEmpty ? nil : value
    }

    var normalizedAPIBaseURL: URL? {
        var raw = apiBaseURL.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !raw.isEmpty else { return nil }

        while raw.hasSuffix("/") {
            raw.removeLast()
        }

        guard let components = URLComponents(string: raw) else {
            return nil
        }

        return components.url
    }
}
