import Foundation
import Security

enum AiConfigStore {
    private static let service = "com.stellia.studydeck.ai"
    private static let keyAccount = "runtime_config_json"
    private static let tokenAccount = "session_token"
    private static let baseAccount = "ai_share_base_url"
    private static let aesAccount = "session_aes_key"
    private static let metaKey = "ai_config_meta"

    private static var defaults: UserDefaults { .standard }

    static func saveSession(baseURL: String, token: String, aesKey: Data) {
        setKeychain(account: baseAccount, data: Data(baseURL.utf8))
        setKeychain(account: tokenAccount, data: Data(token.utf8))
        setKeychain(account: aesAccount, data: aesKey)
    }

    static func clearSession() {
        deleteKeychain(account: tokenAccount)
        deleteKeychain(account: aesAccount)
        deleteKeychain(account: baseAccount)
    }

    static var sessionToken: String? {
        guard let d = getKeychain(account: tokenAccount) else { return nil }
        return String(data: d, encoding: .utf8)
    }

    static var shareBaseURL: String? {
        guard let d = getKeychain(account: baseAccount) else { return nil }
        return String(data: d, encoding: .utf8)
    }

    static var aesKey: Data? {
        getKeychain(account: aesAccount)
    }

    static var isPaired: Bool {
        sessionToken != nil && aesKey != nil && shareBaseURL != nil
    }

    static func saveConfig(_ config: AiRuntimeConfig) throws {
        let data = try JSONEncoder().encode(config)
        setKeychain(account: keyAccount, data: data)
        defaults.set(
            ["updatedAt": config.updatedAt, "version": config.version, "source": config.source],
            forKey: metaKey
        )
    }

    static func loadConfig() -> AiRuntimeConfig? {
        guard let data = getKeychain(account: keyAccount) else { return nil }
        return try? JSONDecoder().decode(AiRuntimeConfig.self, from: data)
    }

    static func clearConfig() {
        deleteKeychain(account: keyAccount)
        defaults.removeObject(forKey: metaKey)
    }

    static var cachedUpdatedAt: String? {
        (defaults.dictionary(forKey: metaKey)?["updatedAt"] as? String)
    }

    // MARK: - Keychain

    private static func setKeychain(account: String, data: Data) {
        deleteKeychain(account: account)
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: service,
            kSecAttrAccount as String: account,
            kSecValueData as String: data,
            kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
        ]
        SecItemAdd(query as CFDictionary, nil)
    }

    private static func getKeychain(account: String) -> Data? {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: service,
            kSecAttrAccount as String: account,
            kSecReturnData as String: true,
            kSecMatchLimit as String: kSecMatchLimitOne,
        ]
        var item: CFTypeRef?
        let status = SecItemCopyMatching(query as CFDictionary, &item)
        guard status == errSecSuccess else { return nil }
        return item as? Data
    }

    private static func deleteKeychain(account: String) {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: service,
            kSecAttrAccount as String: account,
        ]
        SecItemDelete(query as CFDictionary)
    }
}
