use crate::loaders::mesh::InstanceRaw;
use crate::render::DrawCall;
use crate::world::World;
use bytemuck::cast_slice;

pub fn render_system(world: &World) -> Vec<DrawCall>
{
    let all_entities = world.entities.all_entities();

    all_entities
        .iter()
        .filter_map(|&entity| {
            let transform = world.transforms.get(entity)?;
            let mesh_component = world.meshes.get(entity)?;

            let model_matrix = transform.to_matrix();

            let (instance_buffer, num_instances) = if let Some(ref buffer) =
                mesh_component.instance_buffer
            {
                (Some(buffer.clone()), mesh_component.num_instances)
            }
            else
            {
                let dissolve_amount = world.dissolves.get(entity).map(|d| d.amount).unwrap_or(0.0);

                let instance_data = InstanceRaw {
                    model: model_matrix.to_cols_array_2d(),
                    dissolve_amount,
                    _padding: [0.0; 3],
                };

                let buffer = crate::render::with_device(|device| {
                    let buffer = device.create_buffer(&wgpu::BufferDescriptor {
                        label: Some("Instance Buffer"),
                        size: std::mem::size_of::<InstanceRaw>() as u64,
                        usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
                        mapped_at_creation: false,
                    });

                    crate::render::with_queue(|queue| {
                        queue.write_buffer(&buffer, 0, cast_slice(&[instance_data]));
                    });

                    buffer
                });

                (Some(buffer), 1)
            };

            Some(DrawCall {
                vertex_buffer: mesh_component.mesh.vertex_buffer.clone(),
                index_buffer: mesh_component.mesh.index_buffer.clone(),
                num_indices: mesh_component.mesh.num_indices,
                model: model_matrix,
                pipeline: mesh_component.pipeline,
                instance_buffer,
                num_instances,
                tile_scale: mesh_component.tile_scale,
                enable_dissolve: mesh_component.enable_dissolve,
                enable_snow_light: mesh_component.enable_snow_light,
                displacement_bind_group: None,
                entity: Some(entity),
            })
        })
        .collect()
}
