use std::{error::Error, net::Ipv4Addr};

use common::{
    config::IpString,
    net::{tools::Packet, AServerSession, NetError, ServiceType},
    rpc_handlers,
};

use paste::paste;
use proto::AddGateserverNotify;

use crate::dispatch_service;

pub struct GateserverSession {
    server_session: AServerSession,
}

impl GateserverSession {
    pub async fn new(app_id: u32, service_ip: IpString, cur_app_id: u32) -> Result<Self, NetError> {
        Ok(Self {
            server_session: AServerSession::new(app_id, service_ip, cur_app_id),
        })
    }

    async fn on_add_gateserver_notify(&self, packet: Packet) -> Result<(), Box<dyn Error>> {
        let service = dispatch_service();
        let Some(inner_ip) = service
            .config
            .applications
            .get(&ServiceType::Gateserver)
            .unwrap()
            .iter()
            .find(|a| a.app_id == packet.head.sender_app_id)
            .map(|a| a.inner_ip.clone())
        else {
            tracing::error!("app_id {} not found!", packet.head.sender_app_id);
            return Ok(());
        };

        let proto = packet.get_proto::<AddGateserverNotify>()?;
        let outer_ip = Ipv4Addr::from(proto.outer_ip);

        service.gateserver_mgr.add_gateserver(
            packet.head.sender_app_id,
            inner_ip.0.to_string(),
            outer_ip.to_string(),
            proto.listen_port as u16,
            proto.use_domain_name,
            proto.domain_name,
            0,
        );

        Ok(())
    }

    async fn on_keep_alive_notify(&self, packet: Packet) -> Result<(), Box<dyn Error>> {
        dispatch_service()
            .gateserver_mgr
            .sync_gateserver_load(self.server_session.app_id, packet.head.sender_load);

        Ok(())
    }

    rpc_handlers! {
        AddGateserverNotify;
        KeepAliveNotify;
    }

    async fn default_packet_process_func(&self, _packet: Packet) -> Result<(), Box<dyn Error>> {
        Ok(())
    }
}
