//! [`LayerRegistry`]: human-readable names for the 32 layers.

use serde::{Deserialize, Serialize};

use super::{LayerMask, MAX_LAYERS};

/// Maps layer indices (`0..32`) to project-defined names.
///
/// A [`LayerMask`] is just bits; the registry is what lets a project, the
/// editor, and scripts talk about layer **3** as `"Enemy"` instead of a magic
/// number. It is project-level data (serialized with the project, later stages)
/// and changing a name never moves an entity between layers — only the label
/// changes.
///
/// Index `0` is seeded with the name `"Default"`, the layer every entity starts
/// on (see [`Layer`](super::Layer)). The remaining slots are unnamed until a
/// project assigns them.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct LayerRegistry {
    /// One slot per layer; `None` means the layer has no assigned name.
    names: Vec<Option<String>>,
}

impl LayerRegistry {
    /// A registry with only layer 0 named (`"Default"`).
    pub fn new() -> Self {
        let mut names = vec![None; MAX_LAYERS as usize];
        names[0] = Some("Default".to_string());
        Self { names }
    }

    /// Assigns `name` to layer `index`.
    ///
    /// # Panics
    /// Panics if `index >= 32`.
    pub fn set(&mut self, index: u32, name: impl Into<String>) {
        assert!(
            index < MAX_LAYERS,
            "layer index out of range (must be 0..32)"
        );
        self.names[index as usize] = Some(name.into());
    }

    /// Clears the name of layer `index`, leaving it unnamed.
    ///
    /// # Panics
    /// Panics if `index >= 32`.
    pub fn clear(&mut self, index: u32) {
        assert!(
            index < MAX_LAYERS,
            "layer index out of range (must be 0..32)"
        );
        self.names[index as usize] = None;
    }

    /// The name of layer `index`, or `None` if it is out of range or unnamed.
    pub fn name(&self, index: u32) -> Option<&str> {
        self.names.get(index as usize).and_then(|n| n.as_deref())
    }

    /// The index of the layer named `name`, or `None` if no layer has it.
    ///
    /// Names are not required to be unique; the lowest matching index wins.
    pub fn index_of(&self, name: &str) -> Option<u32> {
        self.names
            .iter()
            .position(|n| n.as_deref() == Some(name))
            .map(|i| i as u32)
    }

    /// A [`LayerMask`] built from layer names, skipping any that are unknown.
    ///
    /// Convenient for authoring filters by name, e.g.
    /// `registry.mask_of(["Player", "NPC"])`.
    pub fn mask_of<'a, I>(&self, names: I) -> LayerMask
    where
        I: IntoIterator<Item = &'a str>,
    {
        names.into_iter().filter_map(|n| self.index_of(n)).collect()
    }

    /// Iterates `(index, name)` for every *named* layer, ascending by index.
    pub fn iter(&self) -> impl Iterator<Item = (u32, &str)> {
        self.names
            .iter()
            .enumerate()
            .filter_map(|(i, n)| n.as_deref().map(|name| (i as u32, name)))
    }

    /// The number of named layers.
    pub fn named_count(&self) -> usize {
        self.names.iter().filter(|n| n.is_some()).count()
    }
}

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

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn default_names_only_layer_zero() {
        let reg = LayerRegistry::new();
        assert_eq!(reg.name(0), Some("Default"));
        assert_eq!(reg.name(1), None);
        assert_eq!(reg.named_count(), 1);
    }

    #[test]
    fn set_and_look_up_by_name() {
        let mut reg = LayerRegistry::new();
        reg.set(1, "Player");
        reg.set(2, "NPC");
        reg.set(5, "Water");
        assert_eq!(reg.name(2), Some("NPC"));
        assert_eq!(reg.index_of("Water"), Some(5));
        assert_eq!(reg.index_of("Missing"), None);
        assert_eq!(reg.named_count(), 4);
    }

    #[test]
    fn mask_of_names_builds_a_filter() {
        let mut reg = LayerRegistry::new();
        reg.set(1, "Player");
        reg.set(2, "NPC");
        let mask = reg.mask_of(["Player", "NPC", "Unknown"]);
        assert_eq!(mask, LayerMask::NONE.with(1).with(2));
    }

    #[test]
    fn clear_unsets_a_name() {
        let mut reg = LayerRegistry::new();
        reg.set(3, "Trigger");
        assert_eq!(reg.index_of("Trigger"), Some(3));
        reg.clear(3);
        assert_eq!(reg.name(3), None);
        assert_eq!(reg.index_of("Trigger"), None);
    }

    #[test]
    fn iter_visits_named_layers_in_order() {
        let mut reg = LayerRegistry::new();
        reg.set(4, "B");
        reg.set(2, "A");
        let pairs: Vec<_> = reg.iter().collect();
        assert_eq!(pairs, vec![(0, "Default"), (2, "A"), (4, "B")]);
    }

    #[test]
    fn round_trips_through_ron() {
        let mut reg = LayerRegistry::new();
        reg.set(1, "Player");
        reg.set(7, "Foliage");
        let ron = ron::to_string(&reg).unwrap();
        let back: LayerRegistry = ron::from_str(&ron).unwrap();
        assert_eq!(reg, back);
    }
}
