//! Lazy-compiled regex patterns for the KOGRAL knowledge base engine
//!
//! All regex patterns are compiled once at startup using
//! `once_cell::sync::Lazy` to avoid recompilation overhead during normal
//! operation.

use once_cell::sync::Lazy;
use regex::Regex;

/// Wikilink pattern: `[[target]]` or `[[target|display]]`
pub static WIKILINK_PATTERN: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"\[\[([^\]|]+)(?:\|[^\]]+)?\]\]").unwrap());

/// Code reference pattern: `@path/to/file.rs:42`
pub static CODE_REF_PATTERN: Lazy<Regex> = Lazy::new(|| Regex::new(r"@([\w/.-]+:\d+)").unwrap());

/// Tag pattern: `#tagname`
pub static TAG_PATTERN: Lazy<Regex> = Lazy::new(|| Regex::new(r"#(\w+)").unwrap());

/// Property pattern at start of line: `property:: value`
pub static PROPERTY_START_PATTERN: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"^(\w+)::\s*(\S+)$").unwrap());

/// Property pattern inline: `property:: value` anywhere in text
pub static PROPERTY_INLINE_PATTERN: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(\w+)::\s*(\S+)").unwrap());

/// UUID pattern in double parentheses: `((uuid))`
pub static UUID_REF_PATTERN: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"\(\(([a-f0-9-]{36})\)\)").unwrap());

/// Logseq property pattern with dashes: `property-name:: value`
pub static LOGSEQ_PROPERTY_PATTERN: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"^(\w[\w-]*)::\s*(.+)$").unwrap());

/// Logseq wikilink pattern
pub static LOGSEQ_WIKILINK_PATTERN: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"\[\[([^\]]+)\]\]").unwrap());

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

    #[test]
    fn test_wikilink_pattern() {
        let re = &WIKILINK_PATTERN;
        assert!(re.is_match("[[target]]"));
        assert!(re.is_match("[[target|display]]"));
        assert!(!re.is_match("[[incomplete"));
    }

    #[test]
    fn test_code_ref_pattern() {
        let re = &CODE_REF_PATTERN;
        assert!(re.is_match("@src/main.rs:42"));
        assert!(re.is_match("@crates/core/lib.rs:100"));
        assert!(!re.is_match("@no-colon.rs"));
    }

    #[test]
    fn test_tag_pattern() {
        let re = &TAG_PATTERN;
        assert!(re.is_match("#rust"));
        assert!(re.is_match("#api-design"));
        assert!(!re.is_match("#"));
    }

    #[test]
    fn test_property_start_pattern() {
        let re = &PROPERTY_START_PATTERN;
        assert!(re.is_match("author:: john"));
        assert!(re.is_match("status:: active"));
        assert!(!re.is_match("inline author:: john"));
    }

    #[test]
    fn test_property_inline_pattern() {
        let re = &PROPERTY_INLINE_PATTERN;
        assert!(re.is_match("author:: John"));
        assert!(re.is_match("Contains author:: John in text"));
    }

    #[test]
    fn test_uuid_ref_pattern() {
        let re = &UUID_REF_PATTERN;
        assert!(re.is_match("((550e8400-e29b-41d4-a716-446655440000))"));
        assert!(!re.is_match("((invalid))"));
    }

    #[test]
    fn test_logseq_property_pattern() {
        let re = &LOGSEQ_PROPERTY_PATTERN;
        assert!(re.is_match("author:: John Doe"));
        assert!(re.is_match("created-at:: 2024-01-01"));
        assert!(!re.is_match("::missing-prefix"));
    }
}
