use crate::data;

/// Returns all words that match the provided length, sorted lexicographically.
pub fn by_length(len: usize) -> impl Iterator<Item = &'static str> {
    data::combined(len, len)
}

/// Iterates words grouped by length from `min_len` to `max_len`, each bucket sorted lexicographically.
pub fn iter_ordered(min_len: usize, max_len: usize) -> impl Iterator<Item = &'static str> {
    data::combined(min_len, max_len)
}

#[cfg(test)]
mod tests {
    use super::{by_length, iter_ordered};

    #[test]
    fn by_length_filters_and_sorts() {
        let collected: Vec<&'static str> = by_length(4).take(8).collect();
        assert!(!collected.is_empty(), "expected entries for length 4");
        assert!(by_length(4).count() > 1000, "expected thousands of four-letter words");
        assert!(collected.iter().all(|word| word.len() == 4));
        assert!(collected.windows(2).all(|pair| pair[0] <= pair[1]));
    }

    #[test]
    fn iter_ordered_respects_length_and_ordering() {
        let collected: Vec<&'static str> = iter_ordered(3, 5).collect();
        assert!(!collected.is_empty(), "iter_ordered should produce entries");

        let lengths: Vec<usize> = collected.iter().map(|word| word.len()).collect();
        assert!(lengths.windows(2).all(|pair| pair[0] <= pair[1]));
        assert!(collected.len() > 1500, "expected a broad slice of dictionary data");
        let total: usize = iter_ordered(1, 30).count();
        assert!(total >= 10_000, "expected a massive dictionary, got {total} entries");

        // Ordering should reset within each length bucket.
        for len in 3..=5 {
            let bucket: Vec<&'static str> =
                collected.iter().copied().filter(|word| word.len() == len).collect();
            assert!(bucket.windows(2).all(|pair| pair[0] <= pair[1]));
        }
    }

    #[test]
    fn iter_ordered_handles_empty_range() {
        let collected: Vec<&'static str> = iter_ordered(8, 7).collect();
        assert!(collected.is_empty());
    }
}
