import Foundation
import os

/// Stores minimal session credentials in Keychain for background VoIP push wake-up.
/// Only `publicKey` + `privateKeyHash` — NOT the raw private key.
/// Uses `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly` so PushKit can read
/// them even when the app was killed, as long as the device has been unlocked once.
final class SessionCredentialsManager: @unchecked Sendable {

    static let shared = SessionCredentialsManager()

    private static let logger = Logger(subsystem: "com.rosetta.messenger", category: "SessionCreds")
    private static let service = "com.rosetta.messenger.session"
    private static let account = "voip_session_credentials"

    struct Credentials {
        let publicKey: String
        let privateKeyHash: String
    }

    private init() {}

    // MARK: - Save

    func save(publicKey: String, privateKeyHash: String) {
        let payload = "\(publicKey):\(privateKeyHash)"
        guard let data = payload.data(using: .utf8) else { return }

        // Delete existing first
        let deleteQuery: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: Self.service,
            kSecAttrAccount as String: Self.account,
        ]
        SecItemDelete(deleteQuery as CFDictionary)

        let addQuery: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: Self.service,
            kSecAttrAccount as String: Self.account,
            kSecValueData as String: data,
            kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
        ]

        let status = SecItemAdd(addQuery as CFDictionary, nil)
        if status == errSecSuccess {
            Self.logger.info("Session credentials saved to Keychain")
        } else {
            Self.logger.error("Failed to save session credentials: \(status)")
        }
    }

    // MARK: - Load

    func load() -> Credentials? {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: Self.service,
            kSecAttrAccount as String: Self.account,
            kSecReturnData as String: true,
            kSecMatchLimit as String: kSecMatchLimitOne,
        ]

        var result: AnyObject?
        let status = SecItemCopyMatching(query as CFDictionary, &result)

        guard status == errSecSuccess,
              let data = result as? Data,
              let payload = String(data: data, encoding: .utf8) else {
            return nil
        }

        let parts = payload.components(separatedBy: ":")
        guard parts.count == 2, !parts[0].isEmpty, !parts[1].isEmpty else {
            return nil
        }

        return Credentials(publicKey: parts[0], privateKeyHash: parts[1])
    }

    // MARK: - Clear

    func clear() {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: Self.service,
            kSecAttrAccount as String: Self.account,
        ]
        SecItemDelete(query as CFDictionary)
        Self.logger.info("Session credentials cleared from Keychain")
    }
}
