//! Scenes describe all the resources required to display the current game state.
//!
//! Only 1 scene can be active at any given moment.

use winit::event::WindowEvent;

use super::GameView;

pub trait Mode {
    /// Activates the scene
    fn on_enter(&mut self, game: &mut GameView);
    /// De-activates the scene
    fn on_exit(&mut self, game: &mut GameView);

    /// Scene input handing, true if handled
    fn input(&mut self, event: &WindowEvent, game: &mut GameView) -> bool;
    /// Updates the scene (and can return a SceneReference to go to another scene)
    fn update(&mut self, dt: std::time::Duration, game: &mut GameView) -> Option<ModeReference>;
    /// Renders to egui's gui
    fn gui_egui(&mut self, ctx: &egui::Context, game: &mut GameView);

    // Notice there's no "render" method? Yeah, the scene's responsibility is to adjust Game::world (and Game)
    // so that when the renderer comes around to rendering the world, the desired state is present to be rendered.
}

/// Scenes that can be referenced
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ModeReference {
    /// Initial scene that starts the game
    Init,
}

/// Library of all scenes that exist
pub struct ModeLibrary;

impl ModeLibrary {
    pub fn get_scene(&self, game: &mut GameView, scene: ModeReference) -> Box<dyn Mode + Send> {
        let _ = game;
        match scene {
            ModeReference::Init => Box::<DefaultMode>::default(),
        }
    }
}

#[derive(Default)]
pub struct DefaultMode {
    voop: String,
}

impl Mode for DefaultMode {
    fn on_enter(&mut self, game: &mut GameView<'_>) {
        let _ = game;
        // todo!()
    }

    fn on_exit(&mut self, game: &mut GameView<'_>) {
        let _ = game;
        todo!()
    }

    fn input(&mut self, event: &WindowEvent, game: &mut GameView<'_>) -> bool {
        let _ = game;
        let _ = event;
        false
    }

    fn update(
        &mut self,
        dt: std::time::Duration,
        game: &mut GameView<'_>,
    ) -> Option<ModeReference> {
        let dt_secs = dt.as_secs_f32();

        let negative = self.voop.starts_with('-');
        let negativity = if negative { -1.0 } else { 1.0 };
        if self.voop.to_lowercase().ends_with("camera") {
            if self.voop.contains("rot") {
                game.camera.transform *= glam::Affine3A::from_axis_angle(
                    glam::Vec3::Z,
                    negativity * std::f32::consts::FRAC_PI_4 * dt_secs,
                );
            } else {
                game.camera.transform.translation.x += negativity * dt_secs * 0.0025;
            }
        }

        None
    }

    fn gui_egui(&mut self, ctx: &egui::Context, game: &mut GameView) {
        let _ = game;

        egui::Window::new("gama")
            .default_pos((10.0, 200.0))
            .show(ctx, |ui| {
                ui.label(">> Welcome to Cat Waiter <<");
                if ui
                    .text_edit_singleline(&mut self.voop)
                    .on_hover_text("the best textbox of your life")
                    .changed()
                {
                    log::info!(">> new text: {}", self.voop);
                }
            });
    }
}