use data::tables::AvatarBaseID;

use crate::logic::game::{GameInstance, LogicError};
use crate::logic::procedure::ProcedureAction;

use super::core::NetError;
use super::*;

pub async fn on_get_player_basic_info(
    _session: &NetSession,
    player: &mut Player,
    _req: GetPlayerBasicInfoCsReq,
) -> NetResult<GetPlayerBasicInfoScRsp> {
    Ok(GetPlayerBasicInfoScRsp {
        retcode: Retcode::RetSucc.into(),
        basic_info: Some(player.basic_data_model.player_basic_info()),
    })
}

pub async fn on_create_role(
    session: &NetSession,
    player: &mut Player,
    req: CreateRoleCsReq,
) -> NetResult<CreateRoleScRsp> {
    let avatar_id = AvatarBaseID::new(req.avatar_id).ok_or(Retcode::RetFail)?;

    let GameInstance::Fresh(fresh_game) = &mut player.game_instance else {
        return Err(NetError::from(Retcode::RetFail));
    };

    fresh_game
        .procedure_mgr
        .on_action(ProcedureAction::SelectRole)
        .map_err(LogicError::from)?;

    player.set_frontend_avatar(avatar_id)?;

    session
        .notify(PlayerSyncScNotify {
            basic_info: Some(player.basic_data_model.player_basic_info()),
            ..Default::default()
        })
        .await?;

    Ok(CreateRoleScRsp {
        retcode: Retcode::RetSucc.into(),
    })
}

pub async fn on_get_player_transaction(
    _session: &NetSession,
    _player: &mut Player,
    _req: GetPlayerTransactionCsReq,
) -> NetResult<GetPlayerTransactionScRsp> {
    Ok(GetPlayerTransactionScRsp {
        retcode: Retcode::RetSucc.into(),
        transaction: format!("{}-{}", 1337, 100),
    })
}

pub async fn on_mod_nickname(
    session: &NetSession,
    _player: &mut Player,
    _req: ModNicknameCsReq,
) -> NetResult<ModNicknameScRsp> {
    _player.basic_data_model.nick_name = Some(_req.nick_name.to_string());
    session
        .notify(PlayerSyncScNotify {
            basic_info: Some(_player.basic_data_model.player_basic_info()),
            ..Default::default()
        })
        .await?;

    Ok(ModNicknameScRsp {
        retcode: Retcode::RetSucc.into(),
        ..Default::default()
    })
}

pub async fn on_keep_alive(
    _session: &NetSession,
    _player: &mut Player,
    _ntf: KeepAliveNotify,
) -> NetResult<()> {
    Ok(())
}

pub async fn on_player_logout(
    session: &NetSession,
    _player: &mut Player,
    _ntf: PlayerLogoutNotify,
) -> NetResult<()> {
    tracing::info!(
        "player logout requested (uid: {})",
        session.player_uid().unwrap()
    );
    Err(NetError::Logout)
}
