use super::state::{self, StateResult};

use serde_json::{from_str, json, Value};
use std::env;
use ulid::Ulid;
use ws::{listen, CloseCode, Error, Handler, Handshake, Message, Result, Sender};

struct Server {
    sender: Sender,
    user_id: Option<String>,
    id: String,
}

impl Handler for Server {
    fn on_open(&mut self, _: Handshake) -> Result<()> {
        state::add_connection(self.id.clone(), self.sender.clone());
        Ok(())
    }

    fn on_message(&mut self, msg: Message) -> Result<()> {
        if let Message::Text(text) = msg {
            if let Ok(data) = from_str(&text) as std::result::Result<Value, _> {
                if let Value::String(packet_type) = &data["type"] {
                    if packet_type == "authenticate" {
                        if self.user_id.is_some() {
                            self.sender.send(
                                json!({
                                    "type": "authenticate",
                                    "success": false,
                                    "error": "Already authenticated!"
                                })
                                .to_string(),
                            )
                        } else if let Value::String(token) = &data["token"] {
                            let mut state = unsafe { state::DATA.get().unwrap().write().unwrap() };

                            match state.try_authenticate(self.id.clone(), token.to_string()) {
                                StateResult::Success(user_id) => {
                                    let user = crate::database::user::fetch_user(&user_id).unwrap().unwrap();
                                    
                                    self.user_id = Some(user_id);
                                    self.sender.send(
                                        json!({
                                            "type": "authenticate",
                                            "success": true,
                                        })
                                        .to_string(),
                                    )?;
                                    
                                    self.sender.send(
                                        json!({
                                            "type": "ready",
                                            "data": {
                                                // ! FIXME: rewrite
                                                "user": user
                                            }
                                        })
                                        .to_string(),
                                    )
                                }
                                StateResult::DatabaseError => self.sender.send(
                                    json!({
                                        "type": "authenticate",
                                        "success": false,
                                        "error": "Had database error."
                                    })
                                    .to_string(),
                                ),
                                StateResult::InvalidToken => self.sender.send(
                                    json!({
                                        "type": "authenticate",
                                        "success": false,
                                        "error": "Invalid token."
                                    })
                                    .to_string(),
                                ),
                            }
                        } else {
                            self.sender.send(
                                json!({
                                    "type": "authenticate",
                                    "success": false,
                                    "error": "Token not present."
                                })
                                .to_string(),
                            )
                        }
                    } else {
                        Ok(())
                    }
                } else {
                    Ok(())
                }
            } else {
                Ok(())
            }
        } else {
            Ok(())
        }
    }

    fn on_close(&mut self, _code: CloseCode, _reason: &str) {
        unsafe {
            state::DATA
                .get()
                .unwrap()
                .write()
                .unwrap()
                .disconnect(self.user_id.clone(), self.id.clone());
        }

        println!("User disconnected. [{}]", self.id);
    }

    fn on_error(&mut self, err: Error) {
        println!("The server encountered an error: {:?}", err);
    }
}

pub fn launch_server() {
    state::init();

    listen(
        env::var("WS_HOST").unwrap_or("0.0.0.0:9999".to_string()),
        |sender| Server {
            sender,
            user_id: None,
            id: Ulid::new().to_string(),
        },
    )
    .unwrap()
}