use regex::Regex;
use unicode_normalization::UnicodeNormalization;

fn collapse_whitespace(text: &str) -> String {
    text.split_whitespace().collect::<Vec<_>>().join(" ")
}

fn non_word_re() -> Regex {
    Regex::new(r"[^a-z0-9\s]").expect("valid regex")
}

fn latex_command_with_arg_re() -> Regex {
    Regex::new(r"\\[a-zA-Z]+\*?\{([^}]*)\}").expect("valid regex")
}

fn latex_command_re() -> Regex {
    Regex::new(r"\\[a-zA-Z]+\*?(?:\[[^\]]*\])?").expect("valid regex")
}

pub fn normalize_title(title: &str) -> String {
    if title.is_empty() {
        return String::new();
    }
    let latex_with_arg = latex_command_with_arg_re();
    let mut cleaned = latex_with_arg.replace_all(title, "$1").to_string();
    cleaned = cleaned.replace('{', "").replace('}', "");
    let latex_re = latex_command_re();
    cleaned = latex_re.replace_all(&cleaned, " ").to_string();
    let normalized = cleaned.nfkc().collect::<String>().to_lowercase();
    let non_word = non_word_re();
    collapse_whitespace(&non_word.replace_all(&normalized, " "))
}

pub fn normalize_venue(venue: &str) -> String {
    if venue.is_empty() {
        return String::new();
    }
    let normalized = venue.nfkc().collect::<String>().to_lowercase();
    let non_word = non_word_re();
    collapse_whitespace(&non_word.replace_all(&normalized, " "))
}

pub fn normalize_author_name(name: &str) -> String {
    if name.is_empty() {
        return String::new();
    }
    let cleaned = name.replace('{', "").replace('}', "");
    let normalized = cleaned.nfkc().collect::<String>().to_lowercase();
    let non_word = non_word_re();
    collapse_whitespace(&non_word.replace_all(&normalized, " "))
}

pub fn author_family_names(authors: &[String]) -> Vec<String> {
    let mut families = Vec::new();
    for author in authors {
        let normalized = normalize_author_name(author);
        if normalized.is_empty() {
            continue;
        }
        if let Some(last) = normalized.split_whitespace().last() {
            if !families.contains(&last.to_string()) {
                families.push(last.to_string());
            }
        }
    }
    families
}
