//! Age of Empires 2 civilization names for random session titles

use rand::seq::IndexedRandom;

pub const CIVILIZATIONS: &[&str] = &[
    "Armenians",
    "Aztecs",
    "Bengalis",
    "Berbers",
    "Bohemians",
    "Britons",
    "Bulgarians",
    "Burgundians",
    "Burmese",
    "Byzantines",
    "Celts",
    "Chinese",
    "Cumans",
    "Dravidians",
    "Ethiopians",
    "Franks",
    "Georgians",
    "Goths",
    "Gurjaras",
    "Hindustanis",
    "Huns",
    "Incas",
    "Italians",
    "Japanese",
    "Jurchens",
    "Khitans",
    "Khmer",
    "Koreans",
    "Lithuanians",
    "Magyars",
    "Malay",
    "Malians",
    "Mayans",
    "Mongols",
    "Persians",
    "Poles",
    "Portuguese",
    "Romans",
    "Saracens",
    "Shu",
    "Sicilians",
    "Slavs",
    "Spanish",
    "Tatars",
    "Teutons",
    "Turks",
    "Vietnamese",
    "Vikings",
    "Wei",
    "Wu",
];

fn to_roman(n: u32) -> String {
    let numerals = [
        (1000, "M"),
        (900, "CM"),
        (500, "D"),
        (400, "CD"),
        (100, "C"),
        (90, "XC"),
        (50, "L"),
        (40, "XL"),
        (10, "X"),
        (9, "IX"),
        (5, "V"),
        (4, "IV"),
        (1, "I"),
    ];

    let mut result = String::new();
    let mut remaining = n;

    for (value, numeral) in numerals {
        while remaining >= value {
            result.push_str(numeral);
            remaining -= value;
        }
    }

    result
}

pub fn generate_random_title(existing_titles: &[&str]) -> String {
    let mut rng = rand::rng();

    let available: Vec<&str> = CIVILIZATIONS
        .iter()
        .filter(|civ| !existing_titles.contains(*civ))
        .copied()
        .collect();

    if let Some(&civ) = available.choose(&mut rng) {
        return civ.to_string();
    }

    let base = CIVILIZATIONS.choose(&mut rng).unwrap_or(&"Session");
    for n in 2..=1000 {
        let candidate = format!("{} {}", base, to_roman(n));
        if !existing_titles.contains(&candidate.as_str()) {
            return candidate;
        }
    }

    format!("{} {}", base, chrono::Utc::now().timestamp())
}

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

    #[test]
    fn test_to_roman() {
        assert_eq!(to_roman(1), "I");
        assert_eq!(to_roman(2), "II");
        assert_eq!(to_roman(3), "III");
        assert_eq!(to_roman(4), "IV");
        assert_eq!(to_roman(5), "V");
        assert_eq!(to_roman(9), "IX");
        assert_eq!(to_roman(10), "X");
        assert_eq!(to_roman(49), "XLIX");
        assert_eq!(to_roman(50), "L");
        assert_eq!(to_roman(100), "C");
        assert_eq!(to_roman(500), "D");
        assert_eq!(to_roman(1000), "M");
    }

    #[test]
    fn test_generate_random_title_returns_civ() {
        let title = generate_random_title(&[]);
        assert!(CIVILIZATIONS.contains(&title.as_str()));
    }

    #[test]
    fn test_generate_random_title_avoids_existing() {
        let existing = vec!["Britons", "Franks", "Vikings"];
        let title = generate_random_title(&existing);
        assert!(!existing.contains(&title.as_str()));
    }

    #[test]
    fn test_generate_random_title_with_all_taken_uses_roman_numerals() {
        let existing: Vec<&str> = CIVILIZATIONS.to_vec();
        let title = generate_random_title(&existing);
        assert!(title.contains(" II"));
    }
}
