use std::{error::Error, rc::Rc};

use common::net::tools::Packet;
use proto::{
    EnterSceneDoneRsp, EnterSceneReadyRsp, PostEnterSceneRsp, Retcode, SceneInitFinishRsp,
};

use crate::player::Player;

use super::get_proto;

pub fn on_enter_scene_ready_req(player: &Rc<Player>, packet: Packet) -> Result<(), Box<dyn Error>> {
    let req = get_proto!(packet, EnterSceneReadyReq);

    let result = player.enter_scene_ready(&req);

    player.send_proto(EnterSceneReadyRsp {
        enter_scene_token: req.enter_scene_token,
        retcode: result.err().unwrap_or_default().into(),
    });

    Ok(())
}

pub fn on_scene_init_finish_req(player: &Rc<Player>, packet: Packet) -> Result<(), Box<dyn Error>> {
    let req = get_proto!(packet, SceneInitFinishReq);

    let mut rsp = SceneInitFinishRsp {
        retcode: Retcode::RetFail.into(),
        enter_scene_token: req.enter_scene_token,
    };

    player.player_basic_comp.borrow().notify_server_time();
    let ret = player
        .scene_init_finish(&req)
        .err()
        .unwrap_or(Retcode::RetSucc);

    rsp.retcode = ret.into();
    player.send_proto(rsp);
    Ok(())
}

pub fn on_enter_scene_done_req(player: &Rc<Player>, packet: Packet) -> Result<(), Box<dyn Error>> {
    let req = get_proto!(packet, EnterSceneDoneReq);

    if let Err(ret) = player.enter_scene_done(&req) {
        tracing::info!("end_enter_scene failed, uid:{}", player.uid);
        player.send_proto(EnterSceneDoneRsp {
            retcode: ret.into(),
            enter_scene_token: req.enter_scene_token,
        });
    }

    Ok(())
}

pub fn on_post_enter_scene_req(player: &Rc<Player>, packet: Packet) -> Result<(), Box<dyn Error>> {
    let req = get_proto!(packet, PostEnterSceneReq);

    if let Err(ret) = player.post_enter_scene(&req) {
        tracing::info!("post_enter_scene failed, uid:{}", player.uid);
        player.send_proto(PostEnterSceneRsp {
            retcode: ret.into(),
            enter_scene_token: req.enter_scene_token,
        });
    }

    Ok(())
}
