use winit::{
    dpi::PhysicalSize,
    event::{Event, WindowEvent},
    event_loop::{ControlFlow, EventLoop},
    window::WindowBuilder,
};

mod render;
mod simulation;
mod material;

use render::Renderer;
use simulation::Simulation;

fn main() {
    // Fixed window size (500x500)
    let window_size = PhysicalSize::new(500, 500);

    // Create the event loop and window
    let event_loop = EventLoop::new();

    let window = WindowBuilder::new()
        .with_title("Falling Sand Simulator")
        .with_inner_size(window_size)
        .with_resizable(false) // Fixed size
        .build(&event_loop)
        .unwrap();

    // Initialize the renderer and simulation
    let mut renderer = pollster::block_on(Renderer::new(&window));
    let mut simulation = Simulation::new();

    // Run the event loop
    event_loop.run(move |event, _, control_flow| {
        *control_flow = ControlFlow::Poll;

        match event {
            Event::RedrawRequested(_) => {
                // Update simulation
                simulation.update();

                // Render
                match renderer.render(&simulation) {
                    Ok(_) => {}
                    // Recreate the surface if lost
                    Err(wgpu::SurfaceError::Lost) => renderer.resize(renderer.size),
                    // The system is out of memory, exit
                    Err(wgpu::SurfaceError::OutOfMemory) => *control_flow = ControlFlow::Exit,
                    // All other errors (Outdated, Timeout) should be resolved by the next frame
                    Err(e) => eprintln!("{:?}", e),
                }
            }
            Event::MainEventsCleared => {
                // Request a redraw
                window.request_redraw();
            }
            Event::WindowEvent { ref event, .. } => {
                if !renderer.input(event, &mut simulation) {
                    // Close window
                    match event {
                        WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
                        _ => {}
                    }
                }
            }
            _ => {}
        }
    });
}

#[repr(u32)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Material {
    Empty = 0,
    Sand = 1,
    Water = 2,
    Earth = 3,
    Lava = 4,
    // Add more materials if needed
}

impl Material {
    pub fn color(&self) -> [f32; 3] {
        match self {
            Material::Empty => [0.0, 0.0, 0.0],       // Black
            Material::Sand => [0.8, 0.7, 0.5],        // Sandy color
            Material::Water => [0.0, 0.5, 1.0],       // Blue
            Material::Earth => [0.4, 0.3, 0.2],       // Brown
            Material::Lava => [1.0, 0.3, 0.0],        // Orange-red
        }
    }
}

use crate::material::Material;

pub const SIM_WIDTH: u32 = 125;
pub const SIM_HEIGHT: u32 = 125;

pub struct Simulation {
    pub cells: Vec<Material>, // Simulation grid of materials
}

impl Simulation {
    pub fn new() -> Self {
        // Initialize the grid with empty materials
        let cells = vec![Material::Empty; (SIM_WIDTH * SIM_HEIGHT) as usize];

        Self { cells }
    }

    pub fn update(&mut self) {
        // Update the simulation state on CPU if needed
        // In this case, we are handling the simulation on GPU, so this may be minimal
    }

    // Add methods to interact with the simulation (e.g., add material at position)
    pub fn add_material(&mut self, x: u32, y: u32, material: Material) {
        if x < SIM_WIDTH && y < SIM_HEIGHT {
            let index = (y * SIM_WIDTH + x) as usize;
            self.cells[index] = material;
        }
    }
}

pub mod material;
pub mod render;
pub mod simulation;

   Compiling falling_sand_simulator v0.1.0 (C:\Users\Enzo\Documents\falling_sand_simulator)
error[E0277]: the trait bound `Material: NoUninit` is not satisfied
   --> src\render.rs:259:34
    |
259 |             bytemuck::cast_slice(&simulation.cells),
    |             -------------------- ^^^^^^^^^^^^^^^^^ the trait `Pod` is not implemented for `Material`, which is required by `Material: NoUninit`
    |             |
    |             required by a bound introduced by this call
    |
    = help: the following other types implement trait `Pod`:
              ()
              ManuallyDrop<T>
              Option<T>
              PhantomData<T>
              PhantomPinned
              Wrapping<T>
              [T; 0]
              [T; 1024]
            and 60 others
    = note: required for `Material` to implement `NoUninit`
note: required by a bound in `bytemuck::cast_slice`
   --> C:\Users\Enzo\.cargo\registry\src\index.crates.io-6f17d22bba15001f\bytemuck-1.18.0\src/lib.rs:367:22
    |
367 | pub fn cast_slice<A: NoUninit, B: AnyBitPattern>(a: &[A]) -> &[B] {
    |                      ^^^^^^^^ required by this bound in `cast_slice`

For more information about this error, try `rustc --explain E0277`.
error: could not compile `falling_sand_simulator` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...