//! Shared keyword definitions derived from the lexer Token enum
//!
//! This module provides structured access to Storybook language keywords
//! without duplicating the keyword strings across different LSP modules.
//! All keywords are defined in the Token enum in lexer.rs using the
//! #[token(...)] attribute.

use crate::syntax::lexer::Token;

/// Top-level declaration keywords that start a new declaration
pub const DECLARATION_KEYWORDS: &[&str] = &[
    "character",
    "template",
    "species",
    "behavior",
    "life_arc",
    "relationship",
    "institution",
    "location",
    "enum",
    "schedule",
];

/// All structural keywords (declarations + use)
pub const STRUCTURAL_KEYWORDS: &[&str] = &[
    "use",
    "character",
    "template",
    "species",
    "behavior",
    "life_arc",
    "relationship",
    "institution",
    "location",
    "enum",
    "schedule",
];

/// Keywords used in behavior tree definitions
pub const BEHAVIOR_KEYWORDS: &[&str] = &[
    "choose",
    "then",
    "if",
    "when",
    "repeat",
    "invert",
    "retry",
    "timeout",
    "cooldown",
    // "guard" removed - use "if" instead
    "succeed_always",
    "fail_always",
];

/// Modifier keywords used in various contexts
pub const MODIFIER_KEYWORDS: &[&str] = &["strict", "include", "from", "as"];

/// State machine keywords
pub const STATE_KEYWORDS: &[&str] = &["state", "on", "enter"];

/// Expression keywords
pub const EXPRESSION_KEYWORDS: &[&str] =
    &["forall", "exists", "in", "where", "and", "or", "not", "is"];

/// Special identifier keywords
pub const IDENTIFIER_KEYWORDS: &[&str] = &["self", "other"];

/// Operation keywords
pub const OPERATION_KEYWORDS: &[&str] = &["remove", "append"];

/// Boolean literals
pub const BOOLEAN_LITERALS: &[&str] = &["true", "false"];

/// Check if a string is a top-level declaration keyword
pub fn is_declaration_keyword(s: &str) -> bool {
    DECLARATION_KEYWORDS.contains(&s)
}

/// Check if a string is any structural keyword (includes 'use')
pub fn is_structural_keyword(s: &str) -> bool {
    STRUCTURAL_KEYWORDS.contains(&s)
}

/// Check if a string is a behavior tree keyword
pub fn is_behavior_keyword(s: &str) -> bool {
    BEHAVIOR_KEYWORDS.contains(&s)
}

/// Check if a token is a declaration keyword token
pub fn token_is_declaration_keyword(token: &Token) -> bool {
    matches!(
        token,
        Token::Character |
            Token::Template |
            Token::Species |
            Token::Behavior |
            Token::LifeArc |
            Token::Relationship |
            Token::Institution |
            Token::Location |
            Token::Schedule
    )
}

/// Check if a token is a structural keyword token (includes Use)
pub fn token_is_structural_keyword(token: &Token) -> bool {
    matches!(
        token,
        Token::Use |
            Token::Character |
            Token::Template |
            Token::Species |
            Token::Behavior |
            Token::LifeArc |
            Token::Relationship |
            Token::Institution |
            Token::Location |
            Token::Schedule
    )
}

/// Get the string representation of a declaration token
pub fn declaration_token_to_str(token: &Token) -> Option<&'static str> {
    match token {
        | Token::Character => Some("character"),
        | Token::Template => Some("template"),
        | Token::Species => Some("species"),
        | Token::Behavior => Some("behavior"),
        | Token::LifeArc => Some("life_arc"),
        | Token::Relationship => Some("relationship"),
        | Token::Institution => Some("institution"),
        | Token::Location => Some("location"),
        | Token::Schedule => Some("schedule"),
        | _ => None,
    }
}

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

    #[test]
    fn test_declaration_keywords() {
        assert!(is_declaration_keyword("character"));
        assert!(is_declaration_keyword("template"));
        assert!(is_declaration_keyword("behavior"));
        assert!(!is_declaration_keyword("use"));
        assert!(!is_declaration_keyword("unknown"));
    }

    #[test]
    fn test_structural_keywords() {
        assert!(is_structural_keyword("character"));
        assert!(is_structural_keyword("use"));
        assert!(!is_structural_keyword("if"));
    }

    #[test]
    fn test_behavior_keywords() {
        assert!(is_behavior_keyword("choose"));
        assert!(is_behavior_keyword("repeat"));
        assert!(!is_behavior_keyword("character"));
    }

    #[test]
    fn test_token_checks() {
        assert!(token_is_declaration_keyword(&Token::Character));
        assert!(token_is_declaration_keyword(&Token::Behavior));
        assert!(!token_is_declaration_keyword(&Token::Use));

        assert!(token_is_structural_keyword(&Token::Use));
        assert!(token_is_structural_keyword(&Token::Character));
        assert!(!token_is_structural_keyword(&Token::If));
    }

    #[test]
    fn test_token_to_str() {
        assert_eq!(
            declaration_token_to_str(&Token::Character),
            Some("character")
        );
        assert_eq!(declaration_token_to_str(&Token::Behavior), Some("behavior"));
        assert_eq!(declaration_token_to_str(&Token::Use), None);
    }
}
