import Cocoa
import Carbon

@MainActor
class MediaKeyMonitor: ObservableObject {
    private var eventTap: CFMachPort?
    private var keyboardTap: CFMachPort?
    private var runLoopSource: CFRunLoopSource?
    private var keyboardRunLoopSource: CFRunLoopSource?
    @Published var isEnabled = false
    
    var onMicrophoneButtonPress: (() -> Void)?
    
    // Media key codes
    private let NX_KEYTYPE_SOUND_UP: Int32 = 0
    private let NX_KEYTYPE_SOUND_DOWN: Int32 = 1
    private let NX_KEYTYPE_MUTE: Int32 = 7
    private let NX_KEYTYPE_PLAY: Int32 = 16
    private let NX_KEYTYPE_NEXT: Int32 = 17
    private let NX_KEYTYPE_PREVIOUS: Int32 = 18
    private let NX_KEYTYPE_FAST: Int32 = 19
    private let NX_KEYTYPE_REWIND: Int32 = 20
    private let NX_KEYTYPE_DICTATION: Int32 = 23 // Media key code for dictation
    
    // Possible Dictation key virtual key codes
    private let kVK_Dictation_Candidates: Set<Int64> = [
        176,   // 0xB0 - ACTUAL DICTATION KEY (confirmed from testing!)
        178    // 0xB2 - Do Not Disturb key (for reference)
    ]
    
    func start() {
        guard !isEnabled else { return }
        
        print("🎹 Starting media key monitor...")
        
        // Check for accessibility permissions
        let options = [kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String: true] as CFDictionary
        let accessibilityEnabled = AXIsProcessTrustedWithOptions(options)
        
        guard accessibilityEnabled else {
            print("❌ Accessibility permissions not granted - please approve the prompt")
            return
        }
        
        print("✅ Accessibility permission granted")
        print("⚠️  Input Monitoring permission will be requested...")
        print("   If you see a prompt, click 'OK' to allow keyboard monitoring")
        
        // Monitor keyboard events for Dictation key BEFORE it becomes system event
        // This will trigger Input Monitoring permission request automatically
        let keyboardSuccess = startKeyboardMonitoring()
        
        if !keyboardSuccess {
            print("❌ Input Monitoring permission denied or not available")
            print("📋 To enable manually:")
            print("   1. Open System Settings")
            print("   2. Privacy & Security → Input Monitoring")
            print("   3. Toggle ON 'lowercase' (you may need to quit the app first)")
            print("   4. Restart the app")
            return
        }
        
        // Note: Media key backup monitoring disabled - keyboard tap is sufficient and prevents double-triggering
        // startMediaKeyMonitoring()
        
        isEnabled = true
        print("✅ Dictation key monitor active - Press Dictation key to start/stop!")
    }
    
    
    @discardableResult
    private func startKeyboardMonitoring() -> Bool {
        print("⌨️  Creating keyboard event tap for special function keys...")
        print("   Monitoring candidates: \(kVK_Dictation_Candidates)")
        print("   This will request Input Monitoring permission if not already granted")
        
        // Monitor keyboard events BEFORE they become system events
        let eventMask = (1 << CGEventType.keyDown.rawValue) | (1 << CGEventType.keyUp.rawValue) | (1 << CGEventType.flagsChanged.rawValue)
        
        // Use .cghidEventTap for lowest level interception
        // This will automatically trigger Input Monitoring permission request
        guard let tap = CGEvent.tapCreate(
            tap: .cghidEventTap,
            place: .headInsertEventTap,
            options: .defaultTap,
            eventsOfInterest: CGEventMask(eventMask),
            callback: { (proxy, type, event, refcon) -> Unmanaged<CGEvent>? in
                let keyCode = event.getIntegerValueField(.keyboardEventKeycode)
                
                // Define candidate keys inside callback (can't capture from outside)
                let candidateKeys: Set<Int64> = [
                    176    // 0xB0 - Dictation key
                ]
                
                // Check if this is the dictation key
                if candidateKeys.contains(keyCode) {
                    let isKeyDown = (type == .keyDown)
                    
                    if isKeyDown {
                        print("🎤 Dictation key pressed")
                        if let monitor = Unmanaged<MediaKeyMonitor>.fromOpaque(refcon!).takeUnretainedValue() as MediaKeyMonitor? {
                            Task { @MainActor in
                                monitor.onMicrophoneButtonPress?()
                            }
                        }
                    }
                    
                    // CRITICAL: Suppress the event to prevent system dictation popup
                    return nil
                }
                
                // Pass through all other keys
                return Unmanaged.passRetained(event)
            },
            userInfo: Unmanaged.passUnretained(self).toOpaque()
        ) else {
            print("❌ Failed to create keyboard event tap - Input Monitoring permission likely denied")
            return false
        }
        
        keyboardTap = tap
        keyboardRunLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0)
        CFRunLoopAddSource(CFRunLoopGetCurrent(), keyboardRunLoopSource, .commonModes)
        CGEvent.tapEnable(tap: tap, enable: true)
        
        print("✅ Keyboard monitor active - watching for special function keys")
        print("✅ Input Monitoring permission granted!")
        print("📋 Press ANY key to see its keycode in console, then press Dictation key")
        return true
    }
    
    private func startMediaKeyMonitoring() {
        print("🎹 Creating media key event tap (backup method)...")
        
        // Create event tap for system-defined events (media keys)
        // NX_SYSDEFINED = 14
        let eventMask = CGEventMask(1 << 14)
        
        // Try multiple tap locations for maximum interception
        let tapLocations: [CGEventTapLocation] = [.cghidEventTap, .cgSessionEventTap, .cgAnnotatedSessionEventTap]
        
        for (index, tapLocation) in tapLocations.enumerated() {
            print("   Attempting tap location \(index + 1): \(tapLocation)")
            
            guard let tap = CGEvent.tapCreate(
                tap: tapLocation,
                place: .headInsertEventTap,
                options: .defaultTap,
                eventsOfInterest: eventMask,
                callback: { (proxy, type, event, refcon) -> Unmanaged<CGEvent>? in
                    // Check for system-defined event type (14)
                    guard type.rawValue == 14 else {
                        return Unmanaged.passRetained(event)
                    }
                    
                    print("📨 System-defined event detected!")
                    
                    // Get the system event data from NSEvent wrapper
                    guard let nsEvent = NSEvent(cgEvent: event) else {
                        print("   Could not convert to NSEvent")
                        return Unmanaged.passRetained(event)
                    }
                    
                    // Extract system-defined event data
                    let data1 = nsEvent.data1
                    let data2 = nsEvent.data2
                    let subtype = nsEvent.subtype
                    
                    print("   Raw data1: \(data1), data2: \(data2), subtype: \(subtype.rawValue)")
                    
                    // NX event structure (different bit layout)
                    // For media keys: subtype determines the key type
                    let keyCode = (data1 >> 16) & 0xFFFF
                    let keyFlags = (data1 >> 8) & 0xFF
                    let keyState = data1 & 0xFF
                    let keyDown = (keyFlags & 0x1) != 0 || keyState != 0
                    let keyRepeat = (keyFlags & 0x2) != 0
                    
                    print("   Decoded - keyCode: \(keyCode), state: \(keyState), down: \(keyDown), repeat: \(keyRepeat)")
                    
                    // Dictation key detection:
                    // Subtype 8 = NX_SUBTYPE_AUX_CONTROL_BUTTONS (media keys)
                    // Check if this might be dictation based on multiple criteria
                    let isDictationCandidate = (
                        subtype.rawValue == 8 ||  // Media key subtype
                        keyCode == 23 ||           // Known dictation code
                        keyCode == 0xB3 ||         // Alternate dictation
                        (data1 == 1 && data2 <= 1) // Pattern we're seeing
                    )
                    
                    if isDictationCandidate {
                        print("🎯 POTENTIAL DICTATION EVENT!")
                        print("   Will suppress and trigger our app")
                        
                        if keyDown && !keyRepeat {
                            if let monitor = Unmanaged<MediaKeyMonitor>.fromOpaque(refcon!).takeUnretainedValue() as MediaKeyMonitor? {
                                Task { @MainActor in
                                    print("   ✅ Triggering app recording...")
                                    monitor.handleMediaKey(Int32(keyCode))
                                }
                            }
                        }
                        
                        // AGGRESSIVE: Suppress ALL potential dictation events
                        print("🚫 SUPPRESSING EVENT - RETURNING NIL")
                        return nil
                    }
                    
                    return Unmanaged.passRetained(event)
                },
                userInfo: Unmanaged.passUnretained(self).toOpaque()
            ) else {
                print("   ❌ Failed at location \(tapLocation)")
                continue
            }
            
            // Successfully created tap
            eventTap = tap
            runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0)
            CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, .commonModes)
            CGEvent.tapEnable(tap: tap, enable: true)
            
            print("✅ Media key monitor active at location: \(tapLocation)")
            return
        }
        
        print("❌ Failed to create media key event tap at any location!")
    }
    
    
    
    private func handleMediaKey(_ keyCode: Int32) {
        print("🎹 Media key pressed: \(keyCode)")
        
        // Check for dictation/microphone key
        if keyCode == NX_KEYTYPE_DICTATION {
            print("🎤 Microphone button pressed!")
            onMicrophoneButtonPress?()
        }
    }
    
    func stop() {
        guard isEnabled else { return }
        
        if let tap = keyboardTap {
            CGEvent.tapEnable(tap: tap, enable: false)
            CFRunLoopRemoveSource(CFRunLoopGetCurrent(), keyboardRunLoopSource, .commonModes)
            keyboardTap = nil
            keyboardRunLoopSource = nil
        }
        
        if let tap = eventTap {
            CGEvent.tapEnable(tap: tap, enable: false)
            CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoopSource, .commonModes)
            eventTap = nil
            runLoopSource = nil
        }
        
        
        isEnabled = false
        print("Media key monitor stopped")
    }
    
    func disableSystemDictation() {
        print("🔧 Disabling system dictation via multiple methods...")
        
        // Method 1: Disable auto-enable
        let process1 = Process()
        process1.executableURL = URL(fileURLWithPath: "/usr/bin/defaults")
        process1.arguments = ["write", "com.apple.HIToolbox", "AppleDictationAutoEnable", "-int", "0"]
        
        do {
            try process1.run()
            process1.waitUntilExit()
            print("   Method 1: AppleDictationAutoEnable = \(process1.terminationStatus == 0 ? "✅" : "❌")")
        } catch {
            print("   Method 1 error: \(error)")
        }
        
        // Method 2: Disable dictation enabled flag
        let process2 = Process()
        process2.executableURL = URL(fileURLWithPath: "/usr/bin/defaults")
        process2.arguments = ["write", "com.apple.HIToolbox", "AppleDictationEnabled", "-int", "0"]
        
        do {
            try process2.run()
            process2.waitUntilExit()
            print("   Method 2: AppleDictationEnabled = \(process2.terminationStatus == 0 ? "✅" : "❌")")
        } catch {
            print("   Method 2 error: \(error)")
        }
        
        // Method 3: Disable speech recognition
        let process3 = Process()
        process3.executableURL = URL(fileURLWithPath: "/usr/bin/defaults")
        process3.arguments = ["write", "com.apple.speech.recognition.AppleSpeechRecognition.prefs", "DictationIMEnabled", "-bool", "false"]
        
        do {
            try process3.run()
            process3.waitUntilExit()
            print("   Method 3: DictationIMEnabled = \(process3.terminationStatus == 0 ? "✅" : "❌")")
        } catch {
            print("   Method 3 error: \(error)")
        }
        
        print("✅ System dictation disabled (multiple methods applied)")
    }
    
    func enableSystemDictation() {
        print("🔧 Re-enabling system dictation...")
        let process = Process()
        process.executableURL = URL(fileURLWithPath: "/usr/bin/defaults")
        process.arguments = ["delete", "com.apple.HIToolbox", "AppleDictationAutoEnable"]
        
        do {
            try process.run()
            process.waitUntilExit()
            
            if process.terminationStatus == 0 {
                print("✅ System dictation re-enabled")
            } else {
                print("⚠️  Failed to re-enable system dictation (exit code: \(process.terminationStatus))")
            }
        } catch {
            print("❌ Error re-enabling system dictation: \(error)")
        }
    }
    
    deinit {
        Task { @MainActor in
            self.stop()
        }
    }
}
