//! Mesh store -- manages uploaded GPU meshes via `MeshHandle`.

use crate::handles::MeshHandle;

/// Uploaded mesh metadata (GPU buffers are owned internally).
pub struct UploadedMesh {
    /// Vertex count.
    pub vertex_count: u32,
    /// Index count.
    pub index_count: u32,
    /// Vertex buffer.
    pub vertex_buffer: wgpu::Buffer,
    /// Index buffer (optional for non-indexed meshes).
    pub index_buffer: Option<wgpu::Buffer>,
}

/// GPU mesh store.
pub struct MeshStore {
    meshes: Vec<Option<UploadedMesh>>,
    /// Generation counter per slot for dangling reference detection.
    generations: Vec<u32>,
    next_id: u32,
}

impl MeshStore {
    /// Create an empty mesh store.
    pub fn new() -> Self {
        Self {
            meshes: Vec::new(),
            generations: Vec::new(),
            next_id: 0,
        }
    }

    /// Insert an already-uploaded mesh and return its handle.
    pub fn insert(&mut self, mesh: UploadedMesh) -> MeshHandle {
        let idx = self.next_id;
        self.next_id += 1;

        if (idx as usize) < self.meshes.len() {
            self.meshes[idx as usize] = Some(mesh);
        } else {
            while self.meshes.len() < idx as usize {
                self.meshes.push(None);
                self.generations.push(0);
            }
            self.meshes.push(Some(mesh));
            self.generations.push(0);
        }
        let gen = self.generations[idx as usize];
        MeshHandle(idx, gen)
    }

    /// Get mesh metadata by handle. Returns None if generation mismatches.
    pub fn get(&self, handle: MeshHandle) -> Option<&UploadedMesh> {
        let idx = handle.0 as usize;
        if self.generations.get(idx).copied() != Some(handle.1) {
            return None;
        }
        self.meshes.get(idx).and_then(|s| s.as_ref())
    }

    /// Remove a mesh. GPU buffers are dropped. Increments generation.
    pub fn remove(&mut self, handle: MeshHandle) -> bool {
        let idx = handle.0 as usize;
        if idx < self.meshes.len() && self.meshes[idx].is_some() {
            self.meshes[idx] = None;
            self.generations[idx] += 1;
            true
        } else {
            false
        }
    }

    /// Check if a handle is valid (index and generation match).
    pub fn contains(&self, handle: MeshHandle) -> bool {
        let idx = handle.0 as usize;
        self.generations.get(idx).copied() == Some(handle.1) && self.meshes.get(idx).is_some_and(|s| s.is_some())
    }

    /// Number of loaded meshes.
    pub fn len(&self) -> usize {
        self.meshes.iter().filter(|s| s.is_some()).count()
    }

    /// Whether the store is empty.
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

impl Default for MeshStore {
    fn default() -> Self {
        Self::new()
    }
}
