use std::time::{Duration, Instant};

use crossterm::event::{self, Event as CrosstermEvent, KeyEvent};
use tokio::sync::mpsc;

#[derive(Debug, Clone)]
pub struct LatencySample {
    pub network_us: i64, // now - E (WS server to client)
    pub engine_us: i64,  // E - T (engine to WS server)
    #[allow(dead_code)]
    pub timestamp: Instant,
}

#[derive(Debug)]
#[allow(dead_code)]
pub enum AppEvent {
    Key(KeyEvent),
    Tick,
    WsUpdate(WsMessage),
    ActionResult(ActionResult),
    CommandResult {
        command: String,
        output: String,
        success: bool,
    },
    Resize(u16, u16),
}

#[derive(Debug, Clone)]
#[allow(dead_code)]
pub enum WsMessage {
    // Public streams
    Ticker(serde_json::Value),
    Depth(serde_json::Value),
    Trade(serde_json::Value),
    Kline(serde_json::Value),
    MarkPrice(serde_json::Value),
    // Private streams
    OrderUpdate(serde_json::Value),
    BalanceUpdate(serde_json::Value),
    // Latency tracking
    LatencySample(LatencySample),
    PingRtt(Duration),
    // Public connection lifecycle
    Connected,
    Disconnected,
    Reconnecting(u32),
    // Private connection lifecycle
    PrivateConnected,
    PrivateDisconnected,
    PrivateReconnecting(u32),
}

/// Result of an async trading action, sent back to the main loop for notification display.
#[derive(Debug, Clone)]
pub enum ActionResult {
    OrderPlaced {
        symbol: String,
        side: String,
        qty: String,
        price: Option<String>,
    },
    OrderCancelled {
        symbol: String,
        order_id: String,
    },
    OrderFailed {
        message: String,
    },
    PositionClosed {
        symbol: String,
    },
    PositionCloseFailed {
        message: String,
    },
    OrdersCancelled {
        symbol: String,
        count: usize,
    },
    OrdersCancelFailed {
        message: String,
    },
    NukeCompleted {
        orders_cancelled: usize,
        positions_closed: usize,
    },
    NukeFailed {
        message: String,
    },
}

pub struct EventStream {
    rx: mpsc::UnboundedReceiver<AppEvent>,
}

impl EventStream {
    pub fn new(tick_rate: Duration) -> (Self, mpsc::UnboundedSender<AppEvent>) {
        let (tx, rx) = mpsc::unbounded_channel();
        let key_tx = tx.clone();

        // Spawn crossterm key event reader
        std::thread::spawn(move || loop {
            if event::poll(tick_rate).unwrap_or(false) {
                match event::read() {
                    Ok(CrosstermEvent::Key(key)) => {
                        if key_tx.send(AppEvent::Key(key)).is_err() {
                            break;
                        }
                    }
                    Ok(CrosstermEvent::Resize(w, h)) => {
                        if key_tx.send(AppEvent::Resize(w, h)).is_err() {
                            break;
                        }
                    }
                    _ => {}
                }
            } else if key_tx.send(AppEvent::Tick).is_err() {
                break;
            }
        });

        (Self { rx }, tx)
    }

    pub async fn next(&mut self) -> Option<AppEvent> {
        self.rx.recv().await
    }
}
