use regex::Regex;

lazy_static::lazy_static! {
    /// Matches wikilinks and display text
    static ref WIKILINK_RE: Regex = Regex::new(r"\[\[([^\]|]+)(?:\|[^\]]+)?\]\]").unwrap();
}

/// Extract all wikilink targets from markdown content.
/// Returns raw page names (not slugified).
pub fn collect_wikilinks(content: &str) -> Vec<String> {
    let mut links = Vec::new();

    for caps in WIKILINK_RE.captures_iter(content) {
        if let Some(target) = caps.get(1) {
            let name = target.as_str().trim().to_string();
            if !name.is_empty() && !links.contains(&name) {
                links.push(name);
            }
        }
    }

    links
}

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

    #[test]
    fn test_simple_wikilink() {
        let links = collect_wikilinks("This links to My Page here.");
        assert_eq!(links, vec!["My Page"]);
    }

    #[test]
    fn test_wikilink_with_display_text() {
        let links = collect_wikilinks("See display text for more.");
        assert_eq!(links, vec!["Target Page"]);
    }

    #[test]
    fn test_multiple_wikilinks() {
        let links = collect_wikilinks("Both Page A and Page B are referenced.");
        assert_eq!(links, vec!["Page A", "Page B"]);
    }

    #[test]
    fn test_no_duplicates() {
        let links = collect_wikilinks("Same Page and Same Page again.");
        assert_eq!(links, vec!["Same Page"]);
    }

    #[test]
    fn test_namespace_wikilink() {
        let links = collect_wikilinks("See Cyber Valley.");
        assert_eq!(links, vec!["projects/Cyber Valley"]);
    }

    #[test]
    fn test_no_wikilinks() {
        let links = collect_wikilinks("No links here, just [regular](links).");
        assert!(links.is_empty());
    }

    #[test]
    fn test_wikilink_in_list() {
        let links = collect_wikilinks("- Item with Link One\n  - Sub-item with Link Two");
        assert_eq!(links, vec!["Link One", "Link Two"]);
    }
}

Local Graph