import Foundation
import IOKit

/// Simple utility to obfuscate sensitive data stored in UserDefaults
struct Obfuscator {
    
    /// Encodes a string using Base64 with a device-specific salt
    static func encode(_ string: String, salt: String) -> String {
        let salted = salt + string + salt
        let data = Data(salted.utf8)
        return data.base64EncodedString()
    }
    
    /// Decodes a Base64 string using a device-specific salt
    static func decode(_ base64: String, salt: String) -> String? {
        guard let data = Data(base64Encoded: base64),
              let salted = String(data: data, encoding: .utf8) else {
            return nil
        }
        
        // Remove the salt from both ends
        guard salted.hasPrefix(salt), salted.hasSuffix(salt) else { 
            return nil 
        }
        
        return String(salted.dropFirst(salt.count).dropLast(salt.count))
    }
    
    /// Gets a device-specific identifier to use as salt
    static func getDeviceIdentifier() -> String {
        // Try to get Mac serial number first
        if let serialNumber = getMacSerialNumber() {
            return serialNumber
        }
        
        // Fallback to stored UUID
        let defaults = UserDefaults.standard
        if let storedId = defaults.string(forKey: "VoiceInkDeviceIdentifier") {
            return storedId
        }
        
        // Create and store new UUID
        let newId = UUID().uuidString
        defaults.set(newId, forKey: "VoiceInkDeviceIdentifier")
        return newId
    }
    
    /// Try to get the Mac serial number
    private static func getMacSerialNumber() -> String? {
        let platformExpert = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOPlatformExpertDevice"))
        if platformExpert == 0 { return nil }
        
        defer { IOObjectRelease(platformExpert) }
        
        if let serialNumber = IORegistryEntryCreateCFProperty(platformExpert, "IOPlatformSerialNumber" as CFString, kCFAllocatorDefault, 0) {
            return (serialNumber.takeRetainedValue() as? String)?.trimmingCharacters(in: .whitespacesAndNewlines)
        }
        
        return nil
    }
}
