import CryptoKit
import Foundation
import Security

#if os(macOS)
import IOKit
#elseif os(iOS)
import UIKit
#endif

/// Derives a stable 8-hex room ID with no user configuration.
/// Priority:
///   1. iCloud account token (`ubiquityIdentityToken`) — portable across the user's devices
///   2. Hardware UUID — durable to this device even without an iCloud account
///   3. Keychain-stored UUID — last resort, survives app reinstalls
public enum RoomIdentity {
    public static func derive() -> String {
        iCloudDerived() ?? hardwareDerived() ?? keychainOrNew()
    }

    /// Non-nil when an iCloud account is signed in. Same value on every device
    /// signed into the same Apple ID. Changes if the user signs out.
    private static func iCloudDerived() -> String? {
        guard let token = FileManager.default.ubiquityIdentityToken,
              let data = try? NSKeyedArchiver.archivedData(withRootObject: token,
                                                           requiringSecureCoding: false)
        else { return nil }
        return sha8(data)
    }

    /// Machine/device hardware UUID — no account needed, no entitlements.
    private static func hardwareDerived() -> String? {
        #if os(macOS)
        let service = IOServiceGetMatchingService(kIOMainPortDefault,
                                                  IOServiceMatching("IOPlatformExpertDevice"))
        guard service != 0 else { return nil }
        defer { IOObjectRelease(service) }
        guard let raw = IORegistryEntryCreateCFProperty(
                service, "IOPlatformUUID" as CFString, kCFAllocatorDefault, 0),
              let uuid = raw.takeRetainedValue() as? String
        else { return nil }
        return sha8(Data(uuid.utf8))
        #elseif os(iOS)
        guard let uuid = UIDevice.current.identifierForVendor?.uuidString else { return nil }
        return sha8(Data(uuid.utf8))
        #else
        return nil
        #endif
    }

    /// Generate once, store in Keychain so it survives reinstalls.
    private static func keychainOrNew() -> String {
        let account = "io.pecord.tether.roomID"
        let query: [CFString: Any] = [kSecClass: kSecClassGenericPassword,
                                       kSecAttrAccount: account,
                                       kSecReturnData: true]
        var ref: AnyObject?
        if SecItemCopyMatching(query as CFDictionary, &ref) == errSecSuccess,
           let data = ref as? Data, let stored = String(data: data, encoding: .utf8) {
            return stored
        }
        let new = String(UUID().uuidString.lowercased().filter(\.isHexDigit).prefix(8))
        let add: [CFString: Any] = [kSecClass: kSecClassGenericPassword,
                                     kSecAttrAccount: account,
                                     kSecValueData: Data(new.utf8)]
        SecItemAdd(add as CFDictionary, nil)
        return new
    }

    private static func sha8(_ data: Data) -> String {
        SHA256.hash(data: data).prefix(4).map { String(format: "%02x", $0) }.joined()
    }
}
