use crate::errors::{AleaticoError, AleaticoResult};
use crate::renderer::RenderStats;
use crate::renderer::resources::ResourceStore;
use wgpu::RenderPass;
use crate::renderer::camera::Camera;

/// The main renderer pass, separated into this type for readability
pub(crate) struct MainPass;

impl MainPass {
    pub(crate) fn render(
        pass: &mut RenderPass,
        camera: &Camera,
        resources: &ResourceStore,
        stats: &mut RenderStats,
    ) -> AleaticoResult<()> {
        let mut triangles: usize = 0;

        for render_item in &resources.render_item_store {
            let mesh = resources
                .mesh_store
                .get(render_item.mesh_id)
                .ok_or(AleaticoError::MeshNotFound)?;

            let material = resources
                .material_store
                .get(render_item.material_id)
                .ok_or(AleaticoError::TextureNotFound)?;

            let pipeline = resources
                .pipeline_store
                .get(material.pipeline_id)
                .ok_or(AleaticoError::PipelineNotFound)?;

            pass.set_pipeline(pipeline.raw());

            if let Some(albedo_id) = material.textures.albedo {
                let texture = resources
                    .texture_store
                    .get(albedo_id)
                    .ok_or(AleaticoError::TextureNotFound)?;

                pass.set_bind_group(0, texture.raw(), &[]);
            }
            pass.set_bind_group(1, camera.bind_group(), &[]);
            pass.set_vertex_buffer(0, mesh.vertex_buffer.slice(..));

            if let Some(index_buffer) = &mesh.index_buffer {
                pass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint16);
                pass.draw_indexed(0..mesh.num_indices as u32, 0, 0..1);

                triangles += mesh.num_indices / 3;
            } else {
                pass.draw(0..mesh.num_vertices as u32, 0..1);

                triangles += mesh.num_vertices / 3;
            }
        }

        stats.triangles = triangles;

        Ok(())
    }
}
