use binrw::BinRead;

/// On-disk size of an [`ElementId`] entry in bytes.
pub const ELEMENT_ID_SIZE: usize = 32;

/// On-disk size of a [`Lod`] entry in bytes.
pub const LOD_SIZE: usize = 60;

/// On-disk size of an [`ExtraLod`] entry in bytes.
pub const EXTRA_LOD_SIZE: usize = 40;

/// Named element attachment point, relating a game-object ID to a parent bone.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, BinRead)]
#[br(little)]
pub struct ElementId {
    /// Game-object element identifier.
    pub element_id: u32,
    /// String-table offset of the parent bone name.
    pub parent_bone_name: u32,
    /// Translation offset relative to the parent bone.
    pub translate: [f32; 3],
    /// Rotation offset relative to the parent bone (Euler angles).
    pub rotate: [f32; 3],
}

/// Level-of-detail descriptor — maps a LOD level to ranges within the mesh/buffer tables.
///
/// There are always [`LOD_COUNT`](crate::mdl::parser::LOD_COUNT) `Lod` entries per model.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, BinRead)]
#[br(little)]
pub struct Lod {
    /// Index of the first [`Mesh`](crate::mdl::mesh::Mesh) used by this LOD.
    pub mesh_index: u16,
    /// Number of meshes used by this LOD.
    pub mesh_count: u16,
    /// Camera distance at which this LOD activates for the model geometry.
    pub model_lod_range: f32,
    /// Camera distance at which this LOD activates for textures.
    pub texture_lod_range: f32,
    /// Index of the first water mesh for this LOD.
    pub water_mesh_index: u16,
    /// Number of water meshes for this LOD.
    pub water_mesh_count: u16,
    /// Index of the first shadow mesh for this LOD.
    pub shadow_mesh_index: u16,
    /// Number of shadow meshes for this LOD.
    pub shadow_mesh_count: u16,
    /// Index of the first terrain-shadow mesh for this LOD.
    pub terrain_shadow_mesh_index: u16,
    /// Number of terrain-shadow meshes for this LOD.
    pub terrain_shadow_mesh_count: u16,
    /// Index of the first vertical-fog mesh for this LOD.
    pub vertical_fog_mesh_index: u16,
    /// Number of vertical-fog meshes for this LOD.
    pub vertical_fog_mesh_count: u16,
    /// Byte size of edge geometry data for this LOD.
    pub edge_geometry_size: u32,
    /// Byte offset of edge geometry data for this LOD.
    pub edge_geometry_data_offset: u32,
    /// Total polygon count for this LOD.
    pub polygon_count: u32,
    /// Unknown `u32` field.
    pub unknown1: u32,
    /// Byte size of the vertex buffer for this LOD.
    pub vertex_buffer_size: u32,
    /// Byte size of the index buffer for this LOD.
    pub index_buffer_size: u32,
    /// Byte offset of vertex data within the LOD's buffer.
    pub vertex_data_offset: u32,
    /// Byte offset of index data within the LOD's buffer.
    pub index_data_offset: u32,
}

/// Extra LOD data for specialised mesh categories (light shafts, glass, crest swaps, …).
///
/// Present only when [`ModelFlags2::EXTRA_LOD_ENABLED`](crate::mdl::header::ModelFlags2::EXTRA_LOD_ENABLED) is set.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, BinRead)]
#[br(little)]
pub struct ExtraLod {
    /// Index of the first light-shaft mesh for this LOD.
    pub light_shaft_mesh_index: u16,
    /// Number of light-shaft meshes for this LOD.
    pub light_shaft_mesh_count: u16,
    /// Index of the first glass mesh for this LOD.
    pub glass_mesh_index: u16,
    /// Number of glass meshes for this LOD.
    pub glass_mesh_count: u16,
    /// Index of the first material-change mesh for this LOD.
    pub material_change_mesh_index: u16,
    /// Number of material-change meshes for this LOD.
    pub material_change_mesh_count: u16,
    /// Index of the first crest-change mesh for this LOD.
    pub crest_change_mesh_index: u16,
    /// Number of crest-change meshes for this LOD.
    pub crest_change_mesh_count: u16,
    /// Unknown reserved fields.
    pub unknown: [u16; 12],
}
