import Cocoa
import CoreGraphics

/// 全局热键监听器：Fn 键（语音输入）+ Control 键（AI 助手）
final class KeyMonitor {

    // Fn 键：NX_SECONDARYFNMASK
    private static let fnMask: UInt64 = 0x00800000
    // Control 键：NX_CONTROLMASK
    private static let controlMask: UInt64 = 0x00001000

    private var eventTap: CFMachPort?
    private var runLoopSource: CFRunLoopSource?
    private var isFnPressed = false
    private var isControlPressed = false

    var onFnDown: (() -> Void)?
    var onFnUp: (() -> Void)?
    var onControlDown: (() -> Void)?
    var onControlUp: (() -> Void)?

    func start() -> Bool {
        guard eventTap == nil else { return true }

        guard CGPreflightListenEventAccess() else {
            CGRequestListenEventAccess()
            print("[KeyMonitor] ❌ Accessibility permission not granted")
            return false
        }

        let eventMask = (1 << CGEventType.flagsChanged.rawValue)
                      | (1 << CGEventType.keyDown.rawValue)
                      | (1 << CGEventType.keyUp.rawValue)

        let callback: CGEventTapCallBack = { (proxy, type, event, refcon) -> Unmanaged<CGEvent>? in
            let monitor = Unmanaged<KeyMonitor>.fromOpaque(refcon!).takeUnretainedValue()
            return monitor.handleEvent(proxy: proxy, type: type, event: event)
        }

        var tap = CGEvent.tapCreate(
            tap: .cghidEventTap,
            place: .headInsertEventTap,
            options: .defaultTap,
            eventsOfInterest: CGEventMask(eventMask),
            callback: callback,
            userInfo: Unmanaged.passUnretained(self).toOpaque()
        )

        if tap == nil {
            print("[KeyMonitor] ⚠️ HID tap failed, falling back to session tap")
            tap = CGEvent.tapCreate(
                tap: .cgSessionEventTap,
                place: .headInsertEventTap,
                options: .defaultTap,
                eventsOfInterest: CGEventMask(eventMask),
                callback: callback,
                userInfo: Unmanaged.passUnretained(self).toOpaque()
            )
        }

        guard let tap = tap else {
            print("[KeyMonitor] ❌ Failed to create event tap")
            return false
        }

        eventTap = tap
        runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, tap, 0)
        CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, .commonModes)
        CGEvent.tapEnable(tap: tap, enable: true)

        print("[KeyMonitor] ✅ Started (Fn + Control)")
        return true
    }

    func stop() {
        guard let tap = eventTap else { return }
        CGEvent.tapEnable(tap: tap, enable: false)
        if let source = runLoopSource {
            CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, .commonModes)
        }
        eventTap = nil
        runLoopSource = nil
        print("[KeyMonitor] Stopped")
    }

    private func handleEvent(proxy: CGEventTapProxy, type: CGEventType, event: CGEvent) -> Unmanaged<CGEvent>? {
        let flags = event.flags.rawValue
        _ = event.getIntegerValueField(.keyboardEventKeycode)

        let fnInFlags = (flags & Self.fnMask) != 0
        let controlInFlags = (flags & Self.controlMask) != 0

        switch type {
        case .flagsChanged:
            // Fn 键检测
            if fnInFlags && !isFnPressed {
                isFnPressed = true
                DispatchQueue.main.async { [weak self] in
                    self?.onFnDown?()
                }
                return nil
            }
            if !fnInFlags && isFnPressed {
                isFnPressed = false
                DispatchQueue.main.async { [weak self] in
                    self?.onFnUp?()
                }
                return nil
            }
            
            // Control 键检测
            if controlInFlags && !isControlPressed {
                isControlPressed = true
                DispatchQueue.main.async { [weak self] in
                    self?.onControlDown?()
                }
                return nil
            }
            if !controlInFlags && isControlPressed {
                isControlPressed = false
                DispatchQueue.main.async { [weak self] in
                    self?.onControlUp?()
                }
                return nil
            }
            return Unmanaged.passUnretained(event)

        default:
            return Unmanaged.passUnretained(event)
        }
    }
}
