use crate::logic::{game::LogicError, EOperator, ESystem};

use super::*;

use data::tables::{self, PostGirlConfigID, QuickFuncID};

pub async fn on_get_tips_info(
    _session: &NetSession,
    _player: &mut Player,
    req: GetTipsInfoCsReq,
) -> NetResult<GetTipsInfoScRsp> {
    Ok(GetTipsInfoScRsp {
        retcode: Retcode::RetSucc.into(),
        tips_info: Some(TipsInfo::default()),
        r#type: req.r#type, // tips group type
    })
}

pub async fn on_get_client_systems_info(
    _session: &NetSession,
    player: &mut Player,
    _req: GetClientSystemsInfoCsReq,
) -> NetResult<GetClientSystemsInfoScRsp> {
    let mut post_girl_data = PostGirlData {
        post_girl_list: tables::post_girl_config_template_tb::iter()
            .map(|template| PostGirlItem {
                template_id: template.id.value(),
                unlock_time: 1720052644,
            })
            .collect(),
        ..Default::default()
    };
    if let Some(post_girl_id) = player.basic_data_model.selected_post_girl_id {
        post_girl_data
            .selected_post_girl_id_list
            .push(post_girl_id.value());
    }

    Ok(GetClientSystemsInfoScRsp {
        retcode: Retcode::RetSucc.into(),
        info: Some(ClientSystemsInfo {
            post_girl_data: Some(post_girl_data),
            unlock_data: Some(player.lock_model.to_client()),
            calling_card_data: Some(CallingCardData::default()),
            teleport_data: Some(TeleportData {
                unlock_id_list: tables::teleport_config_template_tb::iter()
                    .filter(|template| template.client_visible > 0)
                    .map(|template| template.teleport_id.value() as i32)
                    .collect(),
                ..Default::default()
            }),
            ..Default::default()
        }),
    })
}

pub async fn on_get_news_stand_data(
    _session: &NetSession,
    _player: &mut Player,
    _req: GetNewsStandDataCsReq,
) -> NetResult<GetNewsStandDataScRsp> {
    Ok(GetNewsStandDataScRsp {
        retcode: Retcode::RetSucc.into(),
        news_stand_data: Some(NewsStandData::default()),
    })
}

pub async fn on_news_stand_seen(
    _session: &NetSession,
    _player: &mut Player,
    _req: NewsStandSeenCsReq,
) -> NetResult<NewsStandSeenScRsp> {
    Ok(NewsStandSeenScRsp {
        retcode: Retcode::RetSucc.into(),
    })
}

pub async fn on_get_trashbin_hermit_data(
    _session: &NetSession,
    _player: &mut Player,
    _req: GetTrashbinHermitDataCsReq,
) -> NetResult<GetTrashbinHermitDataScRsp> {
    Ok(GetTrashbinHermitDataScRsp {
        retcode: Retcode::RetSucc.into(),
        trashbin_hermit_data: Some(TrashbinHermitData::default()),
    })
}

pub async fn on_get_exploration_data(
    _session: &NetSession,
    _player: &mut Player,
    _req: GetExplorationDataCsReq,
) -> NetResult<GetExplorationDataScRsp> {
    Ok(GetExplorationDataScRsp {
        retcode: Retcode::RetSucc.into(),
        ..Default::default()
    })
}

pub async fn on_report_ui_layout_platform(
    _session: &NetSession,
    _player: &mut Player,
    _req: ReportUiLayoutPlatformCsReq,
) -> NetResult<ReportUiLayoutPlatformScRsp> {
    Ok(ReportUiLayoutPlatformScRsp {
        retcode: Retcode::RetSucc.into(),
    })
}

pub async fn on_unlock_newbie_group(
    _session: &NetSession,
    _player: &mut Player,
    req: UnlockNewbieGroupCsReq,
) -> NetResult<UnlockNewbieGroupScRsp> {
    Ok(UnlockNewbieGroupScRsp {
        retcode: Retcode::RetSucc.into(),
        group_id: req.group_id,
    })
}

pub async fn on_battle_report(
    _session: &NetSession,
    _player: &mut Player,
    _req: BattleReportCsReq,
) -> NetResult<BattleReportScRsp> {
    Ok(BattleReportScRsp {
        retcode: Retcode::RetSucc.into(),
    })
}

pub async fn on_player_operation(
    _session: &NetSession,
    _player: &mut Player,
    req: PlayerOperationCsReq,
) -> NetResult<PlayerOperationScRsp> {
    tracing::info!(
        "PlayerOperation(system={:?}, operator={:?}, param={})",
        ESystem::from(req.system),
        EOperator::from(req.operator),
        req.param
    );

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

pub async fn on_player_system_parameter_change(
    _session: &NetSession,
    _player: &mut Player,
    req: PlayerSystemParameterChangeCsReq,
) -> NetResult<PlayerSystemParameterChangeScRsp> {
    tracing::info!(
        "PlayerSystemParameterChange(type={}, param={})",
        req.r#type,
        req.params,
    );

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

pub async fn on_pop_up_window_seen(
    _session: &NetSession,
    _player: &mut Player,
    req: PopUpWindowSeenCsReq,
) -> NetResult<PopUpWindowSeenScRsp> {
    Ok(PopUpWindowSeenScRsp {
        retcode: Retcode::RetSucc.into(),
        popup_group_id_list: req.popup_group_id_list,
    })
}

pub async fn on_report_system_settings_change(
    _session: &NetSession,
    _player: &mut Player,
    req: ReportSystemSettingsChangeCsReq,
) -> NetResult<ReportSystemSettingsChangeScRsp> {
    tracing::info!("system settings change {req:?}");

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

pub async fn on_interact_with_scene_object(
    _session: &NetSession,
    _player: &mut Player,
    _req: InteractWithSceneObjectCsReq,
) -> NetResult<InteractWithSceneObjectScRsp> {
    // this request is used for interaction with STATIC scene objects (not controlled by server, e.g. door in workshop)
    Ok(InteractWithSceneObjectScRsp {
        retcode: Retcode::RetSucc.into(),
    })
}

pub async fn on_mod_quick_menu(
    session: &NetSession,
    player: &mut Player,
    req: ModQuickMenuCsReq,
) -> NetResult<ModQuickMenuScRsp> {
    req.quick_access_data_list.iter().for_each(|data| {
        player
            .lock_model
            .mod_quick_access(data.quick_access_index, QuickFuncID::new(data.btn_id).ok())
    });

    session
        .notify(PlayerSyncScNotify {
            client_systems_sync: Some(ClientSystemsSync {
                quick_access_data_list: player.lock_model.quick_access_to_client(),
                ..Default::default()
            }),
            ..Default::default()
        })
        .await?;

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

pub async fn on_change_post_girl(
    session: &NetSession,
    player: &mut Player,
    req: ChangePostGirlCsReq,
) -> NetResult<ChangePostGirlScRsp> {
    let post_girl_id = *req
        .new_selected_post_girl_id_list
        .get(0)
        .ok_or(Retcode::RetFail)?;

    let post_girl_id = PostGirlConfigID::new(post_girl_id).map_err(LogicError::from)?;

    player.basic_data_model.selected_post_girl_id = Some(post_girl_id);
    session
        .notify(PlayerSyncScNotify {
            client_systems_sync: Some(ClientSystemsSync {
                post_girl_data: Some(PostGirlSync {
                    selected_post_girl_id_list: vec![post_girl_id.value()],
                    ..Default::default()
                }),
                ..Default::default()
            }),
            ..Default::default()
        })
        .await?;

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