use std::collections::HashSet;

use petname::{Alliterations, Petnames};

mod mocks;

#[test]
fn alliterations_from_petnames() {
    let petnames = Petnames::new("able bold", "burly curly", "ant bee cow");
    let alliterations: Alliterations = petnames.into();
    let alliterations_expected: Alliterations = [
        ('a', Petnames::new("able", "", "ant")),
        ('b', Petnames::new("bold", "burly", "bee")),
        ('c', Petnames::new("", "curly", "cow")),
    ]
    .into();
    assert_eq!(alliterations_expected, alliterations);
}

#[test]
fn alliterations_retain_applies_given_predicate() {
    let petnames = Petnames::new("able bold", "burly curly", "ant bee cow");
    let mut alliterations: Alliterations = petnames.into();
    alliterations.retain(|first_letter, _petnames| *first_letter != 'b');
    let alliterations_expected: Alliterations =
        [('a', Petnames::new("able", "", "ant")), ('c', Petnames::new("", "curly", "cow"))].into();
    assert_eq!(alliterations_expected, alliterations);
}

#[test]
#[cfg(feature = "default-words")]
fn alliterations_default_has_non_zero_cardinality() {
    let alliterations = Alliterations::default();
    // This test will need to be adjusted when word lists change.
    assert_eq!(0, alliterations.cardinality(0));
    assert_eq!(1052, alliterations.cardinality(1));
    assert_eq!(69396, alliterations.cardinality(2));
    assert_eq!(8104623, alliterations.cardinality(3));
    assert_eq!(1132457407, alliterations.cardinality(4));
}

#[test]
fn alliterations_generate_uses_adverb_adjective_name() {
    let petnames = Petnames::new("able bold", "burly curly", "ant bee cow");
    let alliterations: Alliterations = petnames.into();
    assert_eq!(
        alliterations.namer(3, "-").iter(&mut mocks::StepRng::new(6234567891, 1)).next(),
        Some("burly-bold-bee".into())
    );
}

#[test]
fn alliterations_iter_yields_names() {
    let mut rng = mocks::StepRng::new(1234567890, 1234567890);
    let petnames = Petnames::new("able bold", "burly curly", "ant bee cow");
    let alliterations: Alliterations = petnames.into();
    let namer = alliterations.namer(3, " ");
    let names = namer.iter(&mut rng);
    let expected: HashSet<String> = ["able ant", "burly bold bee", "curly cow"].map(String::from).into();
    let observed: HashSet<String> = names.take(10).collect::<HashSet<String>>();
    assert_eq!(expected, observed);
}

#[test]
fn alliterations_iter_yields_nothing_when_empty() {
    let mut rng = mocks::StepRng::new(0, 1);
    let alliteration: Alliterations = [].into();
    assert_eq!(0, alliteration.cardinality(3));
    let namer = alliteration.namer(3, ".");
    let mut names = namer.iter(&mut rng);
    assert_eq!(None, names.next());
}
