//! Built-in skills shipped with crab-code.
//!
//! Each skill is defined in its own file and exports a `skill()` function
//! that returns a fully configured [`Skill`] instance. All built-in skills
//! use `SkillSource::Builtin` and `SkillTrigger::Command`.

use super::{
    commit, debug, loop_skill, remember, review_pr, schedule, simplify, stuck, update_config,
    verify,
};
use crate::types::Skill;

/// Names of all built-in skills, for use in help text and listings.
pub const BUILTIN_SKILL_NAMES: &[&str] = &[
    "commit",
    "review-pr",
    "debug",
    "loop",
    "remember",
    "schedule",
    "simplify",
    "stuck",
    "verify",
    "update-config",
];

/// Get all built-in skills.
///
/// Returns a `Vec<Skill>` containing all built-in skills with their prompt
/// content and trigger definitions. These should be registered into the
/// [`SkillRegistry`](crate::registry::SkillRegistry) at startup before
/// user/project skills are loaded (so user skills can override them).
pub fn builtin_skills() -> Vec<Skill> {
    vec![
        commit::skill(),
        review_pr::skill(),
        debug::skill(),
        loop_skill::skill(),
        remember::skill(),
        schedule::skill(),
        simplify::skill(),
        stuck::skill(),
        verify::skill(),
        update_config::skill(),
    ]
}

#[cfg(test)]
mod tests {
    use crate::types::{SkillSource, SkillTrigger};

    use super::*;

    #[test]
    fn builtin_skill_names_not_empty() {
        assert!(!BUILTIN_SKILL_NAMES.is_empty());
        assert!(BUILTIN_SKILL_NAMES.contains(&"commit"));
        assert!(BUILTIN_SKILL_NAMES.contains(&"review-pr"));
    }

    #[test]
    fn builtin_skills_count_matches_names() {
        let skills = builtin_skills();
        assert_eq!(skills.len(), BUILTIN_SKILL_NAMES.len());
    }

    #[test]
    fn all_builtin_skills_are_valid() {
        for skill in builtin_skills() {
            assert!(!skill.name.is_empty(), "skill name must not be empty");
            assert!(
                !skill.description.is_empty(),
                "skill '{}' must have a description",
                skill.name
            );
            assert!(
                !skill.content.is_empty(),
                "skill '{}' must have content",
                skill.name
            );
            assert!(
                matches!(skill.trigger, SkillTrigger::Command { .. }),
                "built-in skill '{}' must have a command trigger",
                skill.name
            );
            assert_eq!(
                skill.source,
                SkillSource::Builtin,
                "built-in skill '{}' must have Builtin source",
                skill.name
            );
            assert!(
                skill.user_invocable,
                "built-in skill '{}' must be user-invocable",
                skill.name
            );
        }
    }

    #[test]
    fn builtin_skill_names_match_actual_skills() {
        let skills = builtin_skills();
        for name in BUILTIN_SKILL_NAMES {
            assert!(
                skills.iter().any(|s| s.name == *name),
                "BUILTIN_SKILL_NAMES contains '{name}' but no skill with that name exists"
            );
        }
    }

    #[test]
    fn each_builtin_skill_has_when_to_use() {
        for skill in builtin_skills() {
            assert!(
                skill.when_to_use.is_some(),
                "built-in skill '{}' should have when_to_use set",
                skill.name
            );
        }
    }
}
