use std::{future::Future, pin::pin, time::Duration};
use crossterm::event::{Event as CrosstermEvent, KeyEvent, MouseEvent};
use futures::{FutureExt as _, StreamExt as _};
use tokio::sync::mpsc;
use crate::common::client::{connection::read::SimplifiedServerMessage, state::ClientStateView};
#[derive(Clone, Debug)]
pub enum Event {
Tick,
Key(KeyEvent),
Mouse(MouseEvent),
#[expect(unused)]
Resize(u16, u16),
#[expect(clippy::enum_variant_names)]
ServerEvent(ServerEvent),
ClientStateUpdated(ClientStateView),
}
#[derive(Clone, Debug)]
pub enum ServerEvent {
Other,
Error(String),
}
impl From<SimplifiedServerMessage> for Event {
fn from(value: SimplifiedServerMessage) -> Self {
Event::ServerEvent(match value {
SimplifiedServerMessage::NewRoomState(_) => ServerEvent::Other,
SimplifiedServerMessage::Pong(_) => ServerEvent::Other,
SimplifiedServerMessage::Error(error) => ServerEvent::Error(error),
})
}
}
impl From<ClientStateView> for Event {
fn from(value: ClientStateView) -> Self {
Event::ClientStateUpdated(value)
}
}
pub struct EventHandler {
sender: mpsc::UnboundedSender<Event>,
receiver: mpsc::UnboundedReceiver<Event>,
#[expect(unused)]
handler: tokio::task::JoinHandle<()>,
}
impl EventHandler {
pub fn new(tick_rate: Duration) -> Self {
let (sender, receiver) = mpsc::unbounded_channel();
let _sender = sender.clone();
let handler = tokio::task::spawn(async move {
let mut reader = crossterm::event::EventStream::new();
let mut tick = tokio::time::interval(tick_rate);
loop {
let mut crossterm_event = reader.next().fuse();
let mut tick_delay = pin!(tick.tick().fuse());
futures::select! {
_ = tick_delay => {
_sender.send(Event::Tick).unwrap();
},
evt = crossterm_event => {
if let Some(Ok(evt)) = evt {
match evt {
CrosstermEvent::Key(key) => {
if key.kind == crossterm::event::KeyEventKind::Press {
_sender.send(Event::Key(key)).unwrap();
}
},
CrosstermEvent::Mouse(mouse) => {
_sender.send(Event::Mouse(mouse)).unwrap();
},
CrosstermEvent::Resize(x, y) => {
_sender.send(Event::Resize(x, y)).unwrap();
},
CrosstermEvent::FocusLost => {
},
CrosstermEvent::FocusGained => {
},
CrosstermEvent::Paste(_) => {
},
}
}
}
};
}
});
Self {
sender,
receiver,
handler,
}
}
#[expect(clippy::needless_lifetimes)]
pub fn next<'a>(&'a mut self) -> impl Future<Output = Option<Event>> + 'a {
self.receiver.recv()
}
pub fn get_sender(&self) -> mpsc::UnboundedSender<Event> {
self.sender.clone()
}
}