//! Event handling for the TUI application

use anyhow::Result;
use crossterm::event::{self, Event, KeyCode, KeyEvent};
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

/// Application events
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub(crate) enum AppEvent {
    /// Tick event for periodic updates
    Tick,
    /// Key press event
    Key(KeyEvent),
    /// Mouse event
    Mouse(event::MouseEvent),
    /// Async data loaded
    DataLoaded,
}

/// Event handler that listens for terminal events
pub(crate) struct EventHandler {
    rx: mpsc::Receiver<AppEvent>,
}

impl EventHandler {
    /// Create a new event handler
    pub(crate) fn new(tick_rate: Duration) -> Result<Self> {
        let (tx, rx) = mpsc::channel();

        // Spawn a thread to listen for key events
        let tx_key = tx.clone();
        thread::spawn(move || loop {
            if event::poll(Duration::from_millis(100))
                .ok()
                .unwrap_or(false)
            {
                if let Ok(Event::Key(key)) = event::read() {
                    let _ = tx_key.send(AppEvent::Key(key));
                }
                if let Ok(Event::Mouse(mouse)) = event::read() {
                    let _ = tx_key.send(AppEvent::Mouse(mouse));
                }
            }
        });

        // Spawn a thread to send tick events
        let tx_tick = tx.clone();
        thread::spawn(move || loop {
            thread::sleep(tick_rate);
            let _ = tx_tick.send(AppEvent::Tick);
        });

        Ok(Self { rx })
    }

    /// Get the next event
    pub(crate) fn next(&self) -> Result<AppEvent> {
        Ok(self.rx.recv()?)
    }
}

/// Key bindings for the application
pub(crate) struct KeyBindings;

#[allow(dead_code)]
impl KeyBindings {
    /// Check if key is quit
    pub(crate) fn is_quit(key: KeyCode) -> bool {
        matches!(key, KeyCode::Char('q') | KeyCode::Esc)
    }

    /// Check if key is enter
    pub(crate) fn is_enter(key: KeyCode) -> bool {
        matches!(key, KeyCode::Enter)
    }

    /// Check if key is up
    pub(crate) fn is_up(key: KeyCode) -> bool {
        matches!(key, KeyCode::Up | KeyCode::Char('k'))
    }

    /// Check if key is down
    pub(crate) fn is_down(key: KeyCode) -> bool {
        matches!(key, KeyCode::Down | KeyCode::Char('j'))
    }

    /// Check if key is left
    pub(crate) fn is_left(key: KeyCode) -> bool {
        matches!(key, KeyCode::Left | KeyCode::Char('h'))
    }

    /// Check if key is right
    pub(crate) fn is_right(key: KeyCode) -> bool {
        matches!(key, KeyCode::Right | KeyCode::Char('l'))
    }

    /// Check if key is tab
    pub(crate) fn is_tab(key: KeyCode) -> bool {
        matches!(key, KeyCode::Tab)
    }

    /// Check if key is backspace
    pub(crate) fn is_backspace(key: KeyCode) -> bool {
        matches!(key, KeyCode::Backspace)
    }
}
