use binrw::BinRead;

/// On-disk size of a [`Mesh`] entry in bytes.
pub const MESH_SIZE: usize = 36;

/// On-disk size of a [`Submesh`] entry in bytes.
pub const SUBMESH_SIZE: usize = 16;

/// On-disk size of a [`TerrainShadowMesh`] entry in bytes.
pub const TERRAIN_SHADOW_MESH_SIZE: usize = 20;

/// On-disk size of a [`TerrainShadowSubmesh`] entry in bytes.
pub const TERRAIN_SHADOW_SUBMESH_SIZE: usize = 12;

/// Mesh descriptor — references vertex/index buffers and describes per-stream layout.
///
/// Multiple [`Submesh`] entries can share a single `Mesh`; the submesh range is
/// `submesh_index..submesh_index + submesh_count`.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, BinRead)]
#[br(little)]
pub struct Mesh {
    /// Number of vertices in this mesh.
    pub vertex_count: u16,
    #[allow(dead_code)]
    pub padding: u16,
    /// Number of indices in this mesh.
    pub index_count: u32,
    /// Index into the model's material list.
    pub material_index: u16,
    /// Index of the first [`Submesh`] belonging to this mesh.
    pub submesh_index: u16,
    /// Number of submeshes belonging to this mesh.
    pub submesh_count: u16,
    /// Index into the model's [`BoneTable`](crate::mdl::bone::BoneTable) list.
    pub bone_table_index: u16,
    /// Starting index within the LOD's index buffer.
    pub start_index: u32,
    /// Per-stream byte offsets within the LOD's vertex buffer.
    pub vertex_buffer_offset: [u32; 3],
    /// Per-stream byte stride of a single vertex.
    pub vertex_buffer_stride: [u8; 3],
    /// Number of active vertex streams for this mesh.
    pub vertex_stream_count: u8,
}

/// Submesh descriptor — a contiguous range of indices sharing common attributes.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, BinRead)]
#[br(little)]
pub struct Submesh {
    /// Byte offset into the mesh's index data.
    pub index_offset: u32,
    /// Number of indices in this submesh.
    pub index_count: u32,
    /// Bitmask indicating which attribute slots apply to this submesh.
    pub attribute_index_mask: u32,
    /// First bone in the submesh's bone palette slice within [`Mdl::submesh_bone_map`].
    ///
    /// [`Mdl::submesh_bone_map`]: crate::mdl::parser::Mdl::submesh_bone_map
    pub bone_start_index: u16,
    /// Number of bones used by this submesh.
    pub bone_count: u16,
}

/// Terrain-specific shadow mesh descriptor.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, BinRead)]
#[br(little)]
pub struct TerrainShadowMesh {
    /// Number of indices in this mesh.
    pub index_count: u32,
    /// Starting index within the LOD's index buffer.
    pub start_index: u32,
    /// Byte offset into the LOD's vertex buffer.
    pub vertex_buffer_offset: u32,
    /// Number of vertices in this mesh.
    pub vertex_count: u16,
    /// Index of the first [`TerrainShadowSubmesh`].
    pub submesh_index: u16,
    /// Number of terrain shadow submeshes.
    pub submesh_count: u16,
    /// Byte stride of a single vertex.
    pub vertex_buffer_stride: u8,
    #[allow(dead_code)]
    pub padding: u8,
}

/// Terrain-specific shadow submesh descriptor.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, BinRead)]
#[br(little)]
pub struct TerrainShadowSubmesh {
    /// Byte offset into the mesh's index data.
    pub index_offset: u32,
    /// Number of indices in this submesh.
    pub index_count: u32,
    /// Unknown `u16` field.
    pub unknown1: u16,
    /// Unknown `u16` field.
    pub unknown2: u16,
}
