use crate::define_store;
use wgpu::BufferUsages;
use wgpu::util::{BufferInitDescriptor, DeviceExt};

define_store!(Mesh);

/// Represents a mesh
pub struct Mesh {
    /// Vertices of this mesh
    pub(crate) vertex_buffer: wgpu::Buffer,
    /// Indices of this mesh
    pub(crate) index_buffer: Option<wgpu::Buffer>,
    /// Number of vertices in this mesh
    pub(crate) num_vertices: usize,
    /// Number of indices in this mesh
    pub(crate) num_indices: usize,
}

impl Mesh {
    /// Create a non-indexed mesh from vertices
    pub fn non_indexed<T: bytemuck::Pod + bytemuck::Zeroable>(
        device: &wgpu::Device,
        vertices: &[T],
    ) -> Mesh {
        let num_vertices = vertices.len();
        let vertex_buffer = device.create_buffer_init(&BufferInitDescriptor {
            label: Some(&format!("Vertex Buffer (len: {num_vertices})")),
            contents: bytemuck::cast_slice(vertices),
            usage: BufferUsages::VERTEX,
        });

        Self {
            vertex_buffer,
            index_buffer: None,
            num_vertices,
            num_indices: 0usize,
        }
    }

    /// Create an indexed mesh from vertices and indices
    pub fn indexed<T: bytemuck::Pod + bytemuck::Zeroable>(device: &wgpu::Device, vertices: &[T], indices: &[u16]) -> Mesh {
        let num_vertices = vertices.len();
        let num_indices = indices.len();

        let vertex_buffer = device.create_buffer_init(&BufferInitDescriptor {
            label: Some(&format!("Vertex Buffer (len: {num_vertices})")),
            contents: bytemuck::cast_slice(vertices),
            usage: BufferUsages::VERTEX,
        });
        let index_buffer = device.create_buffer_init(&BufferInitDescriptor {
            label: Some(&format!("Index Buffer (len: {num_indices})")),
            contents: bytemuck::cast_slice(indices),
            usage: BufferUsages::INDEX,
        });

        Self {
            vertex_buffer,
            index_buffer: Some(index_buffer),
            num_vertices,
            num_indices,
        }
    }

    /// Is this mesh indexed?
    pub fn is_indexed(&self) -> bool {
        self.index_buffer.is_some()
    }

    /// Get count of vertices
    pub fn vertex_count(&self) -> usize {
        self.num_vertices
    }

    /// Get count of indices
    pub fn index_count(&self) -> usize {
        self.num_indices
    }

    /// Get inner vertex buffer
    #[allow(unused)]
    pub(crate) fn vertex_buffer(&self) -> &wgpu::Buffer {
        &self.vertex_buffer
    }

    /// Get inner index buffer
    #[allow(unused)]
    pub(crate) fn index_buffer(&self) -> Option<&wgpu::Buffer> {
        self.index_buffer.as_ref()
    }
}
