use common::util;
use data::tables::{ArchiveBattleQuestID, TrainingQuestID};
use proto::{DungeonInfo, DungeonItemData, FightSceneInfo, SceneInfo, WeatherPoolInfo};
use thiserror::Error;

use crate::logic::{
    battle::{EquippedBuddyDataItem, InLevelAvatarDataItem, TeamDataItem},
    ELocalPlayType, ESceneType, TimePeriodType, WeatherType,
};

use super::NapGameMode;

#[derive(Error, Debug)]
pub enum HollowGameError {}

pub struct HollowGame {
    pub quest_id: u32,
    pub battle_event_id: u32,
    pub time_period: TimePeriodType,
    pub weather: WeatherType,
    pub play_type: ELocalPlayType,
    pub start_timestamp: i64,
    pub team_data: TeamDataItem,
}

impl HollowGame {
    pub fn create_training_game(
        training_quest_id: TrainingQuestID,
        play_type: ELocalPlayType,
        avatars: &[u32],
    ) -> Result<Self, HollowGameError> {
        let template = training_quest_id.template();

        Ok(Self {
            quest_id: template.id.value(),
            battle_event_id: template.battle_event_id,
            time_period: TimePeriodType::Morning,
            weather: WeatherType::SunShine,
            start_timestamp: util::cur_timestamp() as i64,
            play_type,
            team_data: TeamDataItem::new(avatars, 0),
        })
    }

    pub fn create_archive_battle(
        archive_battle_quest_id: ArchiveBattleQuestID,
        play_type: ELocalPlayType,
        avatars: &[u32],
        buddy_id: u32,
    ) -> Result<Self, HollowGameError> {
        let template = archive_battle_quest_id.template();

        Ok(Self {
            quest_id: template.id.value(),
            battle_event_id: template.battle_event_id,
            time_period: TimePeriodType::Morning,
            weather: WeatherType::SunShine,
            start_timestamp: util::cur_timestamp() as i64,
            play_type,
            team_data: TeamDataItem::new(avatars, buddy_id),
        })
    }
}

impl NapGameMode for HollowGame {
    fn scene_type(&self) -> ESceneType {
        ESceneType::Fight
    }

    fn scene_info(&self) -> Option<SceneInfo> {
        Some(SceneInfo {
            scene_type: self.scene_type() as u32,
            battle_event_id: self.battle_event_id,
            play_type: self.play_type as u32,
            fight_scene_info: Some(FightSceneInfo {
                weather_pool: Some(WeatherPoolInfo {
                    time_period: self.time_period.to_string(),
                    weather: self.weather.to_string(),
                    ..Default::default()
                }),
                ..Default::default()
            }),
            ..Default::default()
        })
    }

    fn dungeon_info(&self) -> Option<DungeonInfo> {
        Some(DungeonInfo {
            quest_id: self.quest_id,
            start_timestamp: self.start_timestamp,
            dungeon_item_data: Some(DungeonItemData::default()),
            avatar_list: self
                .team_data
                .avatar_member_list
                .iter()
                .map(InLevelAvatarDataItem::to_client)
                .collect(),
            buddy_list: self
                .team_data
                .equipped_buddy_list
                .iter()
                .map(EquippedBuddyDataItem::to_client)
                .collect(),
            ..Default::default()
        })
    }
}
