use std::collections::HashMap;
use std::hash::Hash;

pub(crate) fn get_majority_combination(
    outcomes: &[(usize, &Vec<String>)],
) -> Option<(Vec<String>, Vec<usize>)> {
    let mut hash_set: HashMap<&Vec<String>, Vec<usize>> = HashMap::new();

    for outcome in outcomes {
        let index = outcome.0;
        let outcome_value = outcome.1;

        let index_set = hash_set.entry(outcome_value).or_default();
        index_set.push(index);
    }

    if hash_set.is_empty() {
        return None;
    }

    let mut values: Vec<_> = hash_set.into_iter().collect();
    values.sort_by(|x, y| x.1.len().partial_cmp(&y.1.len()).unwrap());
    let (last_outcomes, last_indexes) = values.pop().expect("to have at least one element.");
    Some((last_outcomes.to_vec(), last_indexes))
}

pub(super) fn unordered_equal<T: Eq + Hash>(a: &[T], b: &[T]) -> bool {
    fn count<T>(items: &[T]) -> HashMap<&T, usize>
    where
        T: Eq + Hash,
    {
        let mut cnt = HashMap::new();
        for i in items {
            *cnt.entry(i).or_insert(0) += 1
        }
        cnt
    }

    count(a) == count(b)
}

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

    #[test]
    fn get_majority_combination_test() {
        let outcomes_a = vec!["a".to_string(), "b".to_string(), "c".to_string()];
        let outcomes_b = vec!["d".to_string(), "e".to_string(), "f".to_string()];

        let input = vec![
            (0_usize, &outcomes_a),
            (1, &outcomes_a),
            (2, &outcomes_b),
            (3, &outcomes_a),
            (5, &outcomes_a),
            (10, &outcomes_b),
            (14, &outcomes_b),
            (17, &outcomes_a),
        ];

        let actual_combination = get_majority_combination(&input);

        let expected_majority = Some((outcomes_a, vec![0, 1, 3, 5, 17]));

        assert_eq!(expected_majority, actual_combination);
    }

    #[test]
    fn unordered_equal_test() {
        let a = vec![4, 7, 2, 9, 12];
        let b = vec![7, 12, 9, 2, 4];
        let c = vec![12, 2, 9, 4, 7];
        let d = vec![4, 7, 3, 9, 12];

        assert!(unordered_equal(&a, &b));
        assert!(unordered_equal(&a, &c));
        assert!(unordered_equal(&b, &c));
        assert!(!unordered_equal(&a, &d));
    }
}
