use ewebsock::WsEvent;
use macroquad::prelude::{error, info};
use serde::{Serialize, de::DeserializeOwned};

use crate::cfg::{Cfg, ClientType};

pub struct Context {
    pub sender: ewebsock::WsSender,
    pub reciever: ewebsock::WsReceiver,
    pub token: String,
    pub username: String,
    pub user_id: u64,
    pub game_code: String,
    pub client_type: ClientType,
}

impl Context {
    pub fn new(url: &str, cfg: Cfg) -> Context {
        info!("Connecting to web socket server @ {}", url);
        let (sender, reciever) = ewebsock::connect(url, ewebsock::Options::default()).unwrap();

        Self {
            sender,
            reciever,
            token: cfg.token,
            username: cfg.username,
            game_code: cfg.game_code,
            user_id: cfg.user_id,
            client_type: cfg.client_type,
        }
    }

    pub fn send_msg<T: Serialize>(&mut self, msg: &T) {
        let msg = serde_json::to_string(msg).unwrap();
        self.sender.send(ewebsock::WsMessage::Text(msg));
    }

    pub fn recv_msg<T: DeserializeOwned>(&mut self) -> Option<T> {
        if let Some(msg) = self.reciever.try_recv() {
            match msg {
                WsEvent::Opened => {
                    info!("Web socket opened!");
                    None
                }
                WsEvent::Message(ws_message) => match ws_message {
                    ewebsock::WsMessage::Text(msg) => serde_json::from_str(&msg).ok(),
                    _ => None,
                },
                WsEvent::Error(err) => {
                    error!("Something hecky going on: {}", err);
                    None
                }
                WsEvent::Closed => {
                    panic!("Socket closed, something up...");
                }
            }
        } else {
            None
        }
    }
}
