use std::path::Path;

use anyhow::Result;

use ecs::*;
use engine::prelude::*;
use skybox::SkyBox;

fn main() -> Result<()> {
    let mut world_builder = World::builder();

    Engine::new::<GameState>(EngineCreateInfo::default(), &mut world_builder)?;

    world_builder.add_system(GameState::update);
    world_builder.resources.insert(GameState::default());

    let dir = Path::new("C:/Users/M.Huebner/Downloads/skybox");
    // let dir = Path::new("/home/michaelh/Sync/skybox_labeled");
    SkyBox::new(
        &mut world_builder,
        [
            dir.join("left.png"),
            dir.join("right.png"),
            dir.join("front.png"),
            dir.join("back.png"),
            dir.join("top.png"),
            dir.join("bottom.png"),
        ]
        .into_iter(),
    )?;

    let view = world_builder.resources.get_mut::<Scene>().view_mut();
    let camera_control = FreeCameraControl::new(view)?;
    world_builder.resources.insert(camera_control);

    world_builder.build().run()
}

#[derive(Default)]
enum GameState {
    #[default]
    Startup,

    Game(Game),
}

impl GameState {
    fn update(world: &mut World) -> Result<bool> {
        let me = world.resources.get_mut_unchecked::<Self>();

        match me {
            GameState::Startup => *me = GameState::Game(Game),
            GameState::Game(game) => game.update(world)?,
        }

        Ok(true)
    }
}

impl EventConsumer for GameState {
    fn event(&mut self, world: &mut World, event: EngineEvent<'_>) -> Result<()> {
        match self {
            GameState::Startup => (),
            GameState::Game(game) => game.event(world, event)?,
        }

        Ok(())
    }
}

struct Game;

impl Game {
    fn update(&mut self, _world: &mut World) -> Result<()> {
        Ok(())
    }

    fn event(&mut self, world: &mut World, event: EngineEvent<'_>) -> Result<()> {
        match event {
            EngineEvent::MouseButtonDown(MouseButton::Left) => {
                let camera_control = world.resources.get_mut::<FreeCameraControl>();
                camera_control.mouse_down();
            }
            EngineEvent::MouseButtonUp(MouseButton::Left) => {
                let camera_control = world.resources.get_mut::<FreeCameraControl>();
                camera_control.mouse_release();
            }
            EngineEvent::MouseMotion(x, y) => {
                let mut resources = world.resources.multi_mut();
                let scene = resources.get::<Scene>();
                let camera_control = resources.get::<FreeCameraControl>();

                camera_control.mouse_move(x, y, scene.view_mut())?;
            }

            _ => (),
        }

        Ok(())
    }
}