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"
    }

    private let defaults: UserDefaults

    var apiBaseURL: String
    var adminToken: String
    var preferredProvider: Provider
    var preferredModelByProvider: [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

        self.preferredModelByProvider = [
            .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"
        ]
    }

    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)
    }

    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 var components = URLComponents(string: raw) else {
            return nil
        }

        return components.url
    }
}
