import Foundation

#if canImport(Security)
import Security
#endif

// Secure stores for the user-supplied API keys Nucleic Control sessions use when the
// corresponding `ContainerServiceSettings.*AuthMode == .apiKey`. On macOS these are Keychain
// generic-password items Nucleic owns (never UserDefaults, a plist, or a command line); on
// Linux (the runner) they live in the 0600-file `LinuxSecretStore` — the CLOUD_RUNTIME §3.1
// Keychain seam — where they land via the sealed credential mesh (ANTIMATTER_RUNNER §6).
// All operations are best-effort and synchronous.

/// Shared shape of the two control-key stores: load/save/clear one secret string.
private enum ControlKeyBacking {
    #if canImport(Security)
    static func load(service: String, account: String, linuxAccount: String) -> String? {
        let base: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: service,
            kSecAttrAccount as String: account,
        ]
        guard let data = KeychainOwnedAccess.copyData(base),
              let key = String(data: data, encoding: .utf8),
              !key.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
        else { return nil }
        return key
    }

    static func save(service: String, account: String, linuxAccount: String, key: String) -> Bool {
        let trimmed = key.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !trimmed.isEmpty else { return clear(service: service, account: account, linuxAccount: linuxAccount) }
        var add: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: service,
            kSecAttrAccount as String: account,
        ]
        add[kSecValueData as String] = Data(trimmed.utf8)
        return KeychainOwnedAccess.set(add, label: service) == errSecSuccess
    }

    static func clear(service: String, account: String, linuxAccount: String) -> Bool {
        KeychainOwnedAccess.remove([
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: service,
            kSecAttrAccount as String: account,
        ])
        return true
    }
    #else
    static func load(service: String, account: String, linuxAccount: String) -> String? {
        guard let data = LinuxSecretStore.read(account: linuxAccount),
              let key = String(data: data, encoding: .utf8),
              !key.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
        else { return nil }
        return key
    }

    static func save(service: String, account: String, linuxAccount: String, key: String) -> Bool {
        let trimmed = key.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !trimmed.isEmpty else { return clear(service: service, account: account, linuxAccount: linuxAccount) }
        return LinuxSecretStore.write(account: linuxAccount, data: Data(trimmed.utf8))
    }

    static func clear(service: String, account: String, linuxAccount: String) -> Bool {
        LinuxSecretStore.remove(account: linuxAccount)
        return true
    }
    #endif
}

/// Store for the user-supplied Anthropic API key (`controlAuthMode == .apiKey`).
public enum ControlAPIKeyStore {
    private static let service = "Nucleic Control API Key"
    private static let account = "anthropic"
    private static let linuxAccount = "com.nucleic.control.anthropic-api-key"

    /// The stored API key, or nil if none is set (or what's stored is blank).
    public static func load() -> String? {
        ControlKeyBacking.load(service: service, account: account, linuxAccount: linuxAccount)
    }

    /// Whether a (non-blank) API key is currently stored.
    public static var hasKey: Bool { load() != nil }

    /// Store (or replace) the API key. A blank value clears it instead. Returns whether the
    /// store ended in the intended state.
    @discardableResult
    public static func save(_ key: String) -> Bool {
        ControlKeyBacking.save(service: service, account: account, linuxAccount: linuxAccount, key: key)
    }

    /// Remove the stored API key. Succeeds whether or not one was present.
    @discardableResult
    public static func clear() -> Bool {
        ControlKeyBacking.clear(service: service, account: account, linuxAccount: linuxAccount)
    }
}

/// Store for the user-supplied OpenAI API key (`codexControlAuthMode == .apiKey`). The Codex
/// sibling of ``ControlAPIKeyStore`` — a static key sidesteps the ChatGPT OAuth refresh-token
/// rotation that otherwise revokes host and container against each other (see ``CodexAuthFile``).
public enum CodexControlAPIKeyStore {
    private static let service = "Nucleic Control Codex API Key"
    private static let account = "openai"
    private static let linuxAccount = "com.nucleic.control.openai-api-key"

    /// The stored API key, or nil if none is set (or what's stored is blank).
    public static func load() -> String? {
        ControlKeyBacking.load(service: service, account: account, linuxAccount: linuxAccount)
    }

    /// Whether a (non-blank) API key is currently stored.
    public static var hasKey: Bool { load() != nil }

    /// Store (or replace) the API key. A blank value clears it instead. Returns whether the
    /// store ended in the intended state.
    @discardableResult
    public static func save(_ key: String) -> Bool {
        ControlKeyBacking.save(service: service, account: account, linuxAccount: linuxAccount, key: key)
    }

    /// Remove the stored API key. Succeeds whether or not one was present.
    @discardableResult
    public static func clear() -> Bool {
        ControlKeyBacking.clear(service: service, account: account, linuxAccount: linuxAccount)
    }
}
