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

use common::{db::RedisMgr, net::tools::Packet, ServiceBox};
use dashmap::DashMap;
use proto::PlayerLoginReq;

use crate::{
    config::GameserverConfig,
    network::{NetworkMgr, PlayerSessionProxy},
    player::PlayerMgr,
};

pub struct GameserverService {
    pub config: GameserverConfig,
    pub network_mgr: NetworkMgr,
    pub service_box: ServiceBox,
    pub redis_mgr: RedisMgr,
    pub player_sessions: DashMap<u32, Arc<PlayerSessionProxy>>,
    pub player_mgr: PlayerMgr,
}

impl GameserverService {
    pub async fn new(config: GameserverConfig) -> Result<Self, Box<dyn Error>> {
        let network_mgr = NetworkMgr::new(&config).await?;
        let service_box = ServiceBox::new(config.app_id, &config.applications);
        let redis_mgr = RedisMgr::new(&config.database.redis_url).await?;

        Ok(Self {
            config,
            network_mgr,
            service_box,
            redis_mgr,
            player_sessions: DashMap::new(),
            player_mgr: PlayerMgr::new(),
        })
    }

    pub async fn run(&self) {
        self.network_mgr.run().await
    }

    pub fn find_player_session(&self, uid: u32) -> Option<Arc<PlayerSessionProxy>> {
        self.player_sessions.get(&uid).map(|a| a.clone())
    }

    pub fn remove_player_session(&self, uid: u32) {
        self.player_sessions.remove(&uid);
    }

    pub fn create_player_session(
        &self,
        packet: &Packet,
        login_req: PlayerLoginReq,
    ) -> Option<Arc<PlayerSessionProxy>> {
        let uid = packet.head.user_id;
        let mut session = PlayerSessionProxy::new(uid);
        session.set_login_packet_head(packet);
        session.set_login_req(login_req.clone());

        if self.player_sessions.contains_key(&uid) {
            tracing::warn!("duplicated session: {uid}");
            None
        } else {
            let session = Arc::new(session);
            self.player_sessions.insert(uid, session.clone());

            session.on_connect();
            Some(session)
        }
    }
}
