use crate::base::*;
use axon_core::*;
use renet::*;
use renet_netcode::*;
use serde::Serializer;
use std::fmt;
use std::net::{SocketAddr, UdpSocket};
use std::time::SystemTime;

#[derive(Debug)]
pub enum ServerError {
    Io(std::io::Error),
    AddrParse(std::net::AddrParseError),
    TimeError(std::time::SystemTimeError),
    TransportError(renet_netcode::NetcodeTransportError),
}

impl fmt::Display for ServerError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ServerError::Io(e) => write!(f, "IO error: {}", e),
            ServerError::AddrParse(e) => write!(f, "Address parse error: {}", e),
            ServerError::TimeError(e) => write!(f, "Time error: {}", e),
            ServerError::TransportError(e) => write!(f, "Transport error: {}", e),
        }
    }
}

impl std::error::Error for ServerError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            ServerError::Io(e) => Some(e),
            ServerError::AddrParse(e) => Some(e),
            ServerError::TimeError(e) => Some(e),
            ServerError::TransportError(e) => Some(e),
        }
    }
}

impl From<std::io::Error> for ServerError {
    fn from(e: std::io::Error) -> Self {
        ServerError::Io(e)
    }
}

impl From<std::net::AddrParseError> for ServerError {
    fn from(e: std::net::AddrParseError) -> Self {
        ServerError::AddrParse(e)
    }
}

impl From<std::time::SystemTimeError> for ServerError {
    fn from(e: std::time::SystemTimeError) -> Self {
        ServerError::TimeError(e)
    }
}

impl From<renet_netcode::NetcodeTransportError> for ServerError {
    fn from(e: renet_netcode::NetcodeTransportError) -> Self {
        ServerError::TransportError(e)
    }
}

pub struct Server {
    srv: RenetServer,
    transport: NetcodeServerTransport,
    snapshot: crate::base::AxonSnapshot,
    count: u32,
}

impl Server {
    pub fn new(add: &str, max_clients: usize) -> Result<Self, ServerError> {
        let server = RenetServer::new(ConnectionConfig::default());

        let socket = UdpSocket::bind(add)?;
        socket.set_nonblocking(true)?;

        let server_addr: SocketAddr = add.parse()?;
        let current_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?;
        let server_config = ServerConfig {
            current_time,
            max_clients: max_clients,
            protocol_id: 0,
            public_addresses: vec![server_addr],
            authentication: ServerAuthentication::Unsecure,
        };
        let transport = NetcodeServerTransport::new(server_config, socket)?;
        Ok(Self {
            srv: server,
            transport,
            snapshot: crate::base::AxonSnapshot::default(),
            count: 0,
        })
    }
}

impl IAxonContext for Server {
    fn spawn(&mut self, id: u64, t: u32) {
        self.snapshot.spawn(id, t);
        let mut s = axon_sbin::SbinSerializer::new();
        s.serialize_u8(ACTION_TYPE_SPAWN).unwrap();
        s.serialize_u64(id).unwrap();
        s.serialize_u32(t).unwrap();
        s.serialize_bytes(&[]).unwrap();
        self.srv
            .broadcast_message(DefaultChannel::ReliableOrdered, s.into_vec());
        self.count += 1;
        println!("spawn: {} {}", id, t);
    }
    fn despawn(&mut self, id: u64) {
        self.snapshot.despawn(id);
        let mut s = axon_sbin::SbinSerializer::new();
        s.serialize_u8(ACTION_TYPE_DESPAWN).unwrap();
        s.serialize_u64(id).unwrap();
        s.serialize_u32(0).unwrap();
        s.serialize_bytes(&[]).unwrap();
        self.srv
            .broadcast_message(DefaultChannel::ReliableOrdered, s.into_vec());
        self.count += 1;
        println!("despawn: {}", id);
    }
    fn change(&mut self, id: u64, t: u32, v: &[u8]) {
        self.snapshot.change(id, t, v);
        let mut s = axon_sbin::SbinSerializer::new();
        s.serialize_u8(ACTION_TYPE_CHANGE).unwrap();
        s.serialize_u64(id).unwrap();
        s.serialize_u32(t).unwrap();
        s.serialize_bytes(v).unwrap();
        self.srv
            .broadcast_message(DefaultChannel::ReliableOrdered, s.into_vec());
        self.count += 1;
    }
    fn invoke(&mut self, client_id: u64, id: u64, t: u32, v: &[u8]) {
        let mut s = axon_sbin::SbinSerializer::new();
        s.serialize_u8(ACTION_TYPE_INVOKE).unwrap();
        s.serialize_u64(id).unwrap();
        s.serialize_u32(t).unwrap();
        s.serialize_bytes(v).unwrap();
        self.srv
            .send_message(client_id, DefaultChannel::ReliableOrdered, s.into_vec());
        self.count += 1;
    }
    fn broadcast(&mut self, id: u64, t: u32, v: &[u8]) {
        let mut s = axon_sbin::SbinSerializer::new();
        s.serialize_u8(ACTION_TYPE_INVOKE).unwrap();
        s.serialize_u64(id).unwrap();
        s.serialize_u32(t).unwrap();
        s.serialize_bytes(v).unwrap();
        self.srv
            .broadcast_message(DefaultChannel::ReliableOrdered, s.into_vec());
        self.count += 1;
    }
    fn update(&mut self, delta_time: std::time::Duration) {
        self.srv.update(delta_time);
        let _ = self.transport.update(delta_time, &mut self.srv);
    }
    fn receive_event(&mut self, events: &mut Vec<AxonReceiveEvent>) {
        if let Some(event) = self.srv.get_event() {
            match event {
                ServerEvent::ClientConnected { client_id } => {
                    events.push(AxonReceiveEvent::AddClient { client_id });
                    let s = self.snapshot.snapshot();
                    self.srv
                        .send_message(client_id, DefaultChannel::ReliableOrdered, s);
                    self.count += 1;
                }
                ServerEvent::ClientDisconnected { client_id, .. } => {
                    events.push(AxonReceiveEvent::RemoveClient { client_id });
                }
            }
        }

        for client_id in self.srv.clients_id() {
            while let Some(raw) = self
                .srv
                .receive_message(client_id, DefaultChannel::ReliableOrdered)
            {
                crate::base::receive_events(client_id, &raw, events);
            }
        }
    }

    fn flush(&mut self) {
        if self.count > 0 {
            self.count = 0;
            let mut s = axon_sbin::SbinSerializer::new();
            s.serialize_u8(ACTION_TYPE_FRAME).unwrap();
            s.serialize_u64(0).unwrap();
            s.serialize_u32(0).unwrap();
            s.serialize_bytes(&[]).unwrap();
            self.srv
                .broadcast_message(DefaultChannel::ReliableOrdered, s.into_vec());
        }
        self.transport.send_packets(&mut self.srv);
    }
}
