mod fresh;
mod frontend;
mod hollow;
mod long_fight;
pub use fresh::*;
pub use frontend::*;
pub use hollow::*;
pub use long_fight::*;

use proto::{DungeonInfo, SceneInfo, WorldInitScNotify};
use thiserror::Error;

use super::{battle::DungeonQuestError, procedure::ProcedureError, ESceneType};

#[derive(Default)]
pub enum GameInstance {
    Frontend(FrontendGame),
    Fresh(FreshGame),
    Hollow(HollowGame),
    LongFight(LongFightGame),
    #[default]
    Null,
}

#[derive(Error, Debug)]
pub enum LogicError {
    #[error("game instance is NULL!")]
    GameIsNull,
    #[error("frontend error: {0}")]
    Frontend(#[from] FrontendGameError),
    #[error("procedure error: {0}")]
    Procedure(#[from] ProcedureError),
    #[error("hollow error: {0}")]
    Hollow(#[from] HollowGameError),
    #[error("longfight error: {0}")]
    LongFight(#[from] LongFightGameError),
    #[error("dungeon quest error: {0}")]
    DungeonQuest(#[from] DungeonQuestError),
}

impl GameInstance {
    pub fn is_null(&self) -> bool {
        matches!(self, Self::Null)
    }

    pub fn create_world_init_notify(&self) -> Result<WorldInitScNotify, LogicError> {
        Ok(Self::world_init_sc_notify(match self {
            Self::Frontend(game) => game,
            Self::Fresh(game) => game,
            Self::Hollow(game) => game,
            Self::LongFight(game) => game,
            Self::Null => return Err(LogicError::GameIsNull),
        }))
    }

    fn world_init_sc_notify(game: &dyn NapGameMode) -> WorldInitScNotify {
        WorldInitScNotify {
            scene_info: game.scene_info(),
            dungeon_info: game.dungeon_info(),
        }
    }
}

pub trait NapGameMode {
    fn scene_type(&self) -> ESceneType;
    fn scene_info(&self) -> Option<SceneInfo>;
    fn dungeon_info(&self) -> Option<DungeonInfo>;
}
