use std::{error::Error, sync::Arc};

use common::{
    impl_net_service,
    net::{kcp_server::KcpServerMgr, tools::Packet, AServer, NetError, ServiceType},
    rpc_handlers,
};
use proto::{ENetReason, PacketHead};

use crate::{config::GateserverConfig, gateserver_service};

use super::{dispatch_connect::DispatchConnect, PlayerSession};

pub struct NetworkMgr {
    server: AServer,
    dispatch_conn: Arc<DispatchConnect>,
    kcp_server_mgr: Arc<KcpServerMgr<PlayerSession>>,
}

impl NetworkMgr {
    pub async fn new(config: &GateserverConfig) -> Result<Self, NetError> {
        let app_config = config
            .applications
            .get(&ServiceType::Gateserver)
            .map(|v| v.iter().find(|a| a.app_id == config.app_id))
            .unwrap_or_default()
            .expect("Failed to get applications.Gateserver entry");

        let server = AServer::bind(app_config.inner_ip.clone()).await?;

        let player_server_conf = &config.net.player_server;
        let kcp_server_mgr = Arc::new(
            KcpServerMgr::<PlayerSession>::new(
                player_server_conf.outer_ip.clone(),
                player_server_conf.listen_port,
                player_server_conf.max_conn_num,
                player_server_conf.mtu,
                player_server_conf.recv_buf_len,
            )
            .await
            .expect("failed to initialize KcpServerMgr"),
        );

        Ok(Self {
            server,
            dispatch_conn: Arc::new(DispatchConnect),
            kcp_server_mgr,
        })
    }

    pub async fn run(&self) {
        tokio::spawn(self.kcp_server_mgr.clone().run());

        self.dispatch_conn.on_connect().await.unwrap();
        tokio::spawn(self.dispatch_conn.clone().keep_alive_loop());

        loop {
            let Ok(mut packets) = self.server.recv().await else {
                continue;
            };

            while let Some(packet) = packets.pop_front() {
                if let Err(err) = self.on_recv(packet).await {
                    tracing::warn!("on_recv fail: {err}");
                }
            }
        }
    }

    rpc_handlers! {
        GetPlayerTokenRsp;
        PlayerLoginRsp;
    }

    async fn on_get_player_token_rsp(&self, packet: Packet) -> Result<(), Box<dyn Error>> {
        let rsp = gateserver_service()
            .login_handler
            .on_get_player_token_rsp(&packet)
            .await;

        if let Some(session) = self.find_player_session(packet.head.user_session_id) {
            session
                .send_packet(Packet::new(rsp, PacketHead::default()))
                .await?;
        }

        Ok(())
    }

    async fn on_player_login_rsp(&self, packet: Packet) -> Result<(), Box<dyn Error>> {
        gateserver_service()
            .login_handler
            .on_player_login_rsp(packet)
            .await;

        Ok(())
    }

    pub async fn default_packet_process_func(&self, packet: Packet) -> Result<(), Box<dyn Error>> {
        if let Some(session) = self.find_player_session(packet.head.user_session_id) {
            session.send_packet(packet).await?;
        }

        Ok(())
    }

    pub async fn disconnect(&self, session_id: u32, reason: ENetReason) {
        self.kcp_server_mgr
            .disconnect(session_id, reason as u32)
            .await
    }

    pub fn get_player_session_num(&self) -> usize {
        self.kcp_server_mgr.session_count()
    }

    pub fn find_player_session(&self, session_id: u32) -> Option<Arc<PlayerSession>> {
        self.kcp_server_mgr.find_session(session_id)
    }
}

impl_net_service!(Gateserver);
