import Cocoa
import ApplicationServices

@MainActor
class GestureMonitor: ObservableObject {
    private var hidManager: IOHIDManager?
    private var eventMonitor: Any?
    @Published var isEnabled = false
    
    var onThreeFingerTap: (() -> Void)?
    
    private var activeTouches = Set<Int>()
    private var touchStartTime: Date?
    private let forceClickThreshold: Float = 1.0 // Force click pressure threshold
    private var didTrigger = false
    private var touchCount = 0
    private var lastTouchTime: Date?
    private var currentFingerCount = 0
    
    func start() {
        guard !isEnabled else { return }
        
        print("🚀 Starting gesture monitor...")
        
        // Try HID-based detection first
        startHIDMonitoring()
        
        // Fallback: Use NSEvent gesture monitoring (simpler, more reliable)
        startEventMonitoring()
        
        isEnabled = true
        print("✅ Gesture monitor started - Try 3-finger tap now!")
    }
    
    private func startEventMonitoring() {
        // Monitor for pressure events (force click)
        eventMonitor = NSEvent.addGlobalMonitorForEvents(matching: [.pressure, .gesture, .leftMouseDown]) { [weak self] event in
            guard let self = self else { return }
            
            Task { @MainActor in
                // Detect force click (pressure-based)
                if event.type == .pressure {
                    let pressure = event.pressure
                    let stage = event.stage
                    
                    // Force click detected (stage 2) with 3+ fingers
                    if stage >= 2 && pressure > self.forceClickThreshold && !self.didTrigger {
                        print("💪 Force click detected! Pressure: \(pressure), Stage: \(stage)")
                        
                        // Check if we have 3 fingers down
                        if self.currentFingerCount >= 3 {
                            print("🎯 3-finger FORCE CLICK detected!")
                            self.didTrigger = true
                            self.onThreeFingerTap?()
                            
                            // Reset after delay
                            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
                                self?.didTrigger = false
                            }
                        }
                    }
                }
                
                // Track finger count via gesture events
                if event.type == .gesture {
                    // Gesture events can indicate multi-touch
                    print("🖐️ Gesture event detected")
                }
                
                // Fallback: Detect rapid taps as potential 3-finger gesture
                if event.type == .leftMouseDown {
                    // Check didTrigger to prevent duplicate callbacks
                    guard !self.didTrigger else { return }
                    
                    let now = Date()
                    
                    if let lastTime = self.lastTouchTime,
                       now.timeIntervalSince(lastTime) < 0.3 {
                        self.touchCount += 1
                        
                        // If we see multiple rapid taps, might be 3-finger gesture
                        if self.touchCount >= 2 {
                            print("🎯 Fallback: 3-finger tap pattern detected!")
                            self.didTrigger = true
                            self.onThreeFingerTap?()
                            self.touchCount = 0
                            self.lastTouchTime = nil
                            
                            // Reset didTrigger after delay
                            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
                                self?.didTrigger = false
                            }
                            return
                        }
                    } else {
                        self.touchCount = 1
                    }
                    
                    self.lastTouchTime = now
                }
            }
        }
        
        print("📡 Event monitor active (pressure + fallback)")
    }
    
    private func startHIDMonitoring() {
        // Create HID Manager to monitor trackpad
        hidManager = IOHIDManagerCreate(kCFAllocatorDefault, IOOptionBits(kIOHIDOptionsTypeNone))
        
        guard let manager = hidManager else {
            print("⚠️  Failed to create HID manager - using fallback only")
            return
        }
        
        // Match trackpad devices
        let matching: [[String: Any]] = [
            [
                kIOHIDDeviceUsagePageKey as String: kHIDPage_Digitizer,
                kIOHIDDeviceUsageKey as String: kHIDUsage_Dig_TouchPad
            ],
            [
                kIOHIDDeviceUsagePageKey as String: kHIDPage_Digitizer,
                kIOHIDDeviceUsageKey as String: kHIDUsage_Dig_TouchScreen
            ]
        ]
        
        IOHIDManagerSetDeviceMatchingMultiple(manager, matching as CFArray)
        
        // Register input value callback
        IOHIDManagerRegisterInputValueCallback(manager, { context, result, sender, value in
            guard let context = context else { return }
            let monitor = Unmanaged<GestureMonitor>.fromOpaque(context).takeUnretainedValue()
            
            Task { @MainActor in
                monitor.handleHIDValue(value)
            }
        }, Unmanaged.passUnretained(self).toOpaque())
        
        // Schedule with run loop
        IOHIDManagerScheduleWithRunLoop(manager, CFRunLoopGetMain(), CFRunLoopMode.defaultMode.rawValue)
        
        // Open the manager
        let openResult = IOHIDManagerOpen(manager, IOOptionBits(kIOHIDOptionsTypeNone))
        
        if openResult == kIOReturnSuccess {
            print("✅ HID monitor started")
        } else {
            print("⚠️  Failed to open HID manager (code: \(openResult)) - fallback active")
        }
    }
    
    private func handleHIDValue(_ value: IOHIDValue) {
        let element = IOHIDValueGetElement(value)
        let usage = IOHIDElementGetUsage(element)
        let usagePage = IOHIDElementGetUsagePage(element)
        let intValue = Int(IOHIDValueGetIntegerValue(value))
        
        // Look for digitizer touch events
        guard usagePage == kHIDPage_Digitizer else { return }
        
        // Debug: Print all events
        // print("HID Event - Usage: \(usage), Page: \(usagePage), Value: \(intValue)")
        
        // Touch/Contact ID (tracks individual fingers)
        if usage == kHIDUsage_Dig_ContactIdentifier {
            // Track which finger this is
            return
        }
        
        // Tip switch (finger touching/leaving trackpad)
        if usage == kHIDUsage_Dig_TipSwitch || usage == kHIDUsage_Dig_Touch {
            let timestamp = IOHIDValueGetTimeStamp(value)
            let touchID = timestamp // Use timestamp as unique ID for this touch session
            
            if intValue == 1 {
                // Finger down
                activeTouches.insert(Int(touchID % 1000))
                print("👆 Touch detected - Total touches: \(activeTouches.count)")
                
                if touchStartTime == nil {
                    touchStartTime = Date()
                    didTrigger = false
                }
                
                // Check if we have 3+ fingers
                if activeTouches.count >= 3 && !didTrigger {
                    print("🎯 3+ fingers detected!")
                    checkForThreeFingerTap()
                }
            } else if intValue == 0 {
                // Finger up - clear tracking
                activeTouches.removeAll()
                
                // Reset after a delay
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
                    self?.touchStartTime = nil
                    self?.didTrigger = false
                }
            }
        }
        
        // Contact count (some trackpads report total fingers)
        if usage == kHIDUsage_Dig_ContactCount {
            let fingerCount = intValue
            currentFingerCount = fingerCount
            
            if fingerCount > 0 {
                print("👋 Contact count: \(fingerCount) fingers")
            }
            
            if fingerCount >= 3 && !didTrigger {
                if touchStartTime == nil {
                    touchStartTime = Date()
                    didTrigger = false
                }
                print("🎯 3+ fingers detected - waiting for force click...")
                // Don't auto-trigger, wait for force click
                // checkForThreeFingerTap()
            } else if fingerCount == 0 {
                // All fingers lifted
                activeTouches.removeAll()
                currentFingerCount = 0
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
                    self?.touchStartTime = nil
                    self?.didTrigger = false
                }
            }
        }
        
        // Tip pressure (force touch detection)
        if usage == kHIDUsage_Dig_TipPressure {
            let pressure = Double(intValue) / 255.0 // Normalize to 0-1
            
            if pressure > Double(forceClickThreshold) && currentFingerCount >= 3 && !didTrigger {
                print("💪 Force pressure detected with 3 fingers! Pressure: \(pressure)")
                didTrigger = true
                onThreeFingerTap?()
                
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
                    self?.didTrigger = false
                }
            }
        }
    }
    
    private func checkForThreeFingerTap() {
        guard !didTrigger else { return }
        
        // This is now primarily for force click detection
        // Regular taps are handled by the fallback in startEventMonitoring
        didTrigger = true
        print("🎯 3-finger action detected!")
        onThreeFingerTap?()
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
            self?.didTrigger = false
        }
    }
    
    func stop() {
        guard isEnabled else { return }
        
        if let manager = hidManager {
            IOHIDManagerClose(manager, IOOptionBits(kIOHIDOptionsTypeNone))
            hidManager = nil
        }
        
        if let monitor = eventMonitor {
            NSEvent.removeMonitor(monitor)
            eventMonitor = nil
        }
        
        isEnabled = false
        activeTouches.removeAll()
        touchStartTime = nil
        didTrigger = false
        touchCount = 0
        lastTouchTime = nil
        currentFingerCount = 0
        print("Gesture monitor stopped")
    }
    
    deinit {
        // deinit is nonisolated; hop to the main actor to call the isolated method.
        Task { @MainActor in
            self.stop()
        }
    }
}
