use crate::skill::Skill;
use std::collections::HashMap;

pub struct SkillRegistry {
    skills: HashMap<String, Box<dyn Skill>>,
}

impl SkillRegistry {
    pub fn new() -> Self {
        Self {
            skills: HashMap::new(),
        }
    }

    pub fn register(&mut self, skill: Box<dyn Skill>) {
        self.skills.insert(skill.id().0.to_string(), skill);
    }

    pub fn get(&self, id: &str) -> Option<&dyn Skill> {
        self.skills.get(id).map(|s| s.as_ref())
    }

    pub fn all_ids(&self) -> Vec<&str> {
        self.skills.keys().map(|s| s.as_str()).collect()
    }

    pub fn default_registry() -> Self {
        let mut reg = Self::new();
        use crate::skills::*;
        // Original 15 skills
        reg.register(Box::new(SieveSkill));
        reg.register(Box::new(CartographSkill));
        reg.register(Box::new(ChiselSkill));
        reg.register(Box::new(SedimentSkill));
        reg.register(Box::new(PrismSkill));
        reg.register(Box::new(CompassSkill));
        reg.register(Box::new(CondenserSkill));
        reg.register(Box::new(ArchivistSkill));
        reg.register(Box::new(ScoutSkill));
        reg.register(Box::new(ChroniclerSkill));
        reg.register(Box::new(AlchemistSkill));
        reg.register(Box::new(SentinelSkill));
        reg.register(Box::new(CartridgeSkill));
        reg.register(Box::new(ResonatorSkill));
        reg.register(Box::new(SurveyorSkill));
        // Wave 2 — 21 new skills
        reg.register(Box::new(ParallaxSkill));
        reg.register(Box::new(BlueprintSkill));
        reg.register(Box::new(PinpointSkill));
        reg.register(Box::new(CrossroadsSkill));
        reg.register(Box::new(DriftSkill));
        reg.register(Box::new(PanoramaSkill));
        reg.register(Box::new(RippleSkill));
        reg.register(Box::new(MeridianSkill));
        reg.register(Box::new(ForecastSkill));
        reg.register(Box::new(UnfoldSkill));
        reg.register(Box::new(ThermalSkill));
        reg.register(Box::new(EchoSkill));
        reg.register(Box::new(LedgerSkill));
        reg.register(Box::new(StewardSkill));
        reg.register(Box::new(DispatchSkill));
        reg.register(Box::new(ArbiterSkill));
        reg.register(Box::new(DivinerSkill));
        reg.register(Box::new(CrucibleSkill));
        reg.register(Box::new(ScannerSkill));
        reg.register(Box::new(RelayCtxSkill));
        reg.register(Box::new(WitnessSkill));
        // Wave 3 — 5 new skills
        reg.register(Box::new(ScribeSkill));
        reg.register(Box::new(FluxSkill));
        reg.register(Box::new(PathfinderSkill));
        reg.register(Box::new(HarvestSkill));
        reg.register(Box::new(RenderSkill));
        reg
    }
}

impl Default for SkillRegistry {
    fn default() -> Self {
        Self::default_registry()
    }
}

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

    #[test]
    fn default_registry_has_41_skills() {
        let reg = SkillRegistry::default_registry();
        assert_eq!(
            reg.all_ids().len(),
            41,
            "expected 41 skills, got: {:?}",
            reg.all_ids()
        );
    }

    #[test]
    fn original_15_skills_present() {
        let reg = SkillRegistry::default_registry();
        for name in &[
            "sieve",
            "cartograph",
            "chisel",
            "sediment",
            "prism",
            "compass",
            "condenser",
            "archivist",
            "scout",
            "chronicler",
            "alchemist",
            "sentinel",
            "cartridge",
            "resonator",
            "surveyor",
        ] {
            assert!(reg.get(name).is_some(), "missing skill: {name}");
        }
    }

    #[test]
    fn wave_2_skills_present() {
        let reg = SkillRegistry::default_registry();
        for name in &[
            "parallax",
            "blueprint",
            "pinpoint",
            "crossroads",
            "drift",
            "panorama",
            "ripple",
            "meridian",
            "forecast",
            "unfold",
            "thermal",
            "echo",
            "ledger",
            "steward",
            "dispatch",
            "arbiter",
            "diviner",
            "crucible",
            "scanner",
            "relay_ctx",
            "witness",
        ] {
            assert!(reg.get(name).is_some(), "missing skill: {name}");
        }
    }
}
