use crate::ecs::mesh::components::Mesh;
use std::collections::HashMap;

#[derive(Default)]
pub struct MeshCache {
    meshes: HashMap<String, Mesh>,
    reference_counts: HashMap<String, usize>,
}

impl MeshCache {
    pub fn new() -> Self {
        Self {
            meshes: HashMap::new(),
            reference_counts: HashMap::new(),
        }
    }

    pub fn insert(&mut self, name: String, mesh: Mesh) {
        if self.meshes.contains_key(&name) {
            return;
        }
        self.meshes.insert(name.clone(), mesh);
        self.reference_counts.insert(name, 1);
    }

    pub fn get(&self, name: &str) -> Option<&Mesh> {
        self.meshes.get(name)
    }

    pub fn contains(&self, name: &str) -> bool {
        self.meshes.contains_key(name)
    }

    pub fn add_reference(&mut self, name: &str) {
        if let Some(count) = self.reference_counts.get_mut(name) {
            *count += 1;
        }
    }

    pub fn remove_reference(&mut self, name: &str) {
        if let Some(count) = self.reference_counts.get_mut(name) {
            *count = count.saturating_sub(1);
        }
    }

    pub fn get_reference_count(&self, name: &str) -> usize {
        self.reference_counts.get(name).copied().unwrap_or(0)
    }

    pub fn remove(&mut self, name: &str) -> Option<Mesh> {
        self.reference_counts.remove(name);
        self.meshes.remove(name)
    }

    pub fn remove_unused(&mut self) -> Vec<String> {
        let unused: Vec<String> = self
            .reference_counts
            .iter()
            .filter(|&(_, count)| *count == 0)
            .map(|(name, _)| name.clone())
            .collect();

        for name in &unused {
            self.meshes.remove(name);
            self.reference_counts.remove(name);
        }

        unused
    }

    pub fn clear(&mut self) {
        self.meshes.clear();
        self.reference_counts.clear();
    }

    pub fn len(&self) -> usize {
        self.meshes.len()
    }

    pub fn is_empty(&self) -> bool {
        self.meshes.is_empty()
    }

    pub fn iter(&self) -> impl Iterator<Item = (&String, &Mesh)> {
        self.meshes.iter()
    }
}
