#![allow(incomplete_features)]
#![feature(generic_const_exprs)]

pub mod egui_renderer;
pub mod state;
pub mod voxel;
use std::sync::Arc;

use winit::application::ApplicationHandler;
use winit::event::WindowEvent;
use winit::event_loop::EventLoop;
use winit::event_loop::{self};
use winit::window::Window;

use crate::state::State;

pub fn run() -> anyhow::Result<()>
{
    env_logger::init();

    let event_loop = EventLoop::with_user_event().build()?;
    let mut app = App::default();
    event_loop.run_app(&mut app)?;

    Ok(())
}

// App struct
#[derive(Default)]
pub struct App
{
    state: Option<State>,
}

impl ApplicationHandler for App
{
    fn resumed(&mut self, event_loop: &event_loop::ActiveEventLoop)
    {
        // Create window
        let window = Arc::new(
            event_loop
                .create_window(
                    Window::default_attributes()
                        .with_title("Wgpu Template")
                        .with_resizable(true),
                )
                .unwrap(),
        );

        let state = pollster::block_on(State::new(window.clone()));
        self.state = Some(state);

        window.request_redraw();
        window.set_cursor_visible(false);
        window
            .set_cursor_grab(winit::window::CursorGrabMode::Locked)
            .unwrap();
    }

    fn window_event(
        &mut self,
        event_loop: &event_loop::ActiveEventLoop,
        _window_id: winit::window::WindowId,
        event: winit::event::WindowEvent,
    )
    {
        let state = self.state.as_mut().unwrap();
        state.handle_event(&event);

        match event
        {
            WindowEvent::CloseRequested =>
            {
                event_loop.exit();
            }
            WindowEvent::RedrawRequested =>
            {
                state.render();
                state.get_window().request_redraw();
            }

            WindowEvent::Resized(size) =>
            {
                state.resize(size);
            }

            WindowEvent::MouseWheel { delta, .. } =>
            {
                state.mouse_wheel(delta);
            }

            _ =>
            {}
        }
    }

    fn device_event(
        &mut self,
        _event_loop: &event_loop::ActiveEventLoop,
        _device_id: winit::event::DeviceId,
        event: winit::event::DeviceEvent,
    )
    {
        let state = self.state.as_mut().unwrap();

        #[allow(clippy::single_match)]
        match event
        {
            winit::event::DeviceEvent::MouseMotion { delta } =>
            {
                state.cursor_moved(delta.0 as f32, delta.1 as f32);
            }

            _ =>
            {}
        }
    }
}
