import Foundation
import Security
import os.log

private let logger = Logger(subsystem: "ro.xdev.healthprobe", category: "KeychainService")

enum KeychainService {
    private static let service = "ro.xdev.healthprobe.deviceid"
    private static let account = "stable_device_id"
    private static var cached: String?

    struct Resolution {
        let id: String
        let isRecovered: Bool
    }

    // If swiftDataStoreIsEmpty is true and Keychain has an existing ID, the DB was wiped
    // (reinstall or manual reset) but Keychain survived. We keep the same deviceID but signal
    // that a new chain must start and is marked recovered.
    static func resolveDeviceID(swiftDataStoreIsEmpty: Bool) -> Resolution {
        if let existing = readFromKeychain() {
            if swiftDataStoreIsEmpty {
                // DB was wiped but Keychain survived — recovered device ID
                return Resolution(id: existing, isRecovered: true)
            }
            return Resolution(id: existing, isRecovered: false)
        }
        let new = UUID().uuidString
        writeToKeychain(new)
        return Resolution(id: new, isRecovered: false)
    }

    private static func readFromKeychain() -> String? {
        if let cached { return cached }
        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 result: AnyObject?
        let status = SecItemCopyMatching(query as CFDictionary, &result)
        guard status == errSecSuccess,
              let data = result as? Data,
              let string = String(data: data, encoding: .utf8) else {
            return nil
        }
        cached = string
        return string
    }

    private static func writeToKeychain(_ value: String) {
        guard let data = value.data(using: .utf8) else { return }
        let attributes: [String: Any] = [
            kSecClass as String:        kSecClassGenericPassword,
            kSecAttrService as String:  service,
            kSecAttrAccount as String:  account,
            kSecValueData as String:    data,
        ]
        let status = SecItemAdd(attributes as CFDictionary, nil)
        if status == errSecDuplicateItem {
            let query: [String: Any] = [
                kSecClass as String:        kSecClassGenericPassword,
                kSecAttrService as String:  service,
                kSecAttrAccount as String:  account,
            ]
            SecItemUpdate(query as CFDictionary, [kSecValueData as String: data] as CFDictionary)
        } else if status != errSecSuccess {
            logger.error("Keychain write failed: \(status)")
        }
        cached = value
    }
}
