import Foundation
import Security
import NucleicProtocol

/// What the phone pins about its Mac at pairing (SYNC §4.2): the host's static key (for IK
/// reconnect), a display name, and an optional LAN hint. The pairing secret is *not* stored —
/// it's one-time. Non-secret, so UserDefaults is fine; the device private key goes to Keychain.
struct PairedHost: Codable, Equatable {
    var deviceID: String
    var hostName: String
    var hostStaticKey: Data
    var fingerprint: String
    var lanHost: String?
    var lanPort: UInt16?
}

/// Loads/persists this device's long-term `DeviceIdentity` (Keychain) and the pinned host
/// (UserDefaults). The identity is generated once on first launch and reused thereafter.
enum IdentityStore {
    private static let keychainAccount = "xyz.blakeslee.nucleic.remote.identity"
    private static let pairedHostKey = "nucleic.pairedHost"
    private static let deviceIDKey = "nucleic.deviceID"

    static func loadOrCreateIdentity() -> DeviceIdentity {
        if let data = keychainRead(), let identity = try? DeviceIdentity(importingRaw: data) {
            return identity
        }
        let identity = DeviceIdentity()
        keychainWrite(identity.exportRaw())
        return identity
    }

    /// Stable per-install device id (re-used across reconnects so the host can match the pin).
    static func deviceID() -> String {
        let defaults = UserDefaults.standard
        if let existing = defaults.string(forKey: deviceIDKey) { return existing }
        let id = "iphone-" + UUID().uuidString.prefix(8).lowercased()
        defaults.set(id, forKey: deviceIDKey)
        return id
    }

    static func loadPairedHost() -> PairedHost? {
        guard let data = UserDefaults.standard.data(forKey: pairedHostKey) else { return nil }
        return try? JSONDecoder().decode(PairedHost.self, from: data)
    }

    static func savePairedHost(_ host: PairedHost) {
        if let data = try? JSONEncoder().encode(host) {
            UserDefaults.standard.set(data, forKey: pairedHostKey)
        }
    }

    static func clearPairedHost() {
        UserDefaults.standard.removeObject(forKey: pairedHostKey)
    }

    // MARK: - Keychain

    private static func keychainRead() -> Data? {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: keychainAccount,
            kSecReturnData as String: true,
            kSecMatchLimit as String: kSecMatchLimitOne,
        ]
        var item: CFTypeRef?
        guard SecItemCopyMatching(query as CFDictionary, &item) == errSecSuccess else { return nil }
        return item as? Data
    }

    private static func keychainWrite(_ data: Data) {
        let delete: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: keychainAccount,
        ]
        SecItemDelete(delete as CFDictionary)
        let add: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: keychainAccount,
            kSecValueData as String: data,
            kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
        ]
        SecItemAdd(add as CFDictionary, nil)
    }
}
