use super::*;

pub struct Ast {}

impl Ast {
    pub fn new() -> Self {
        Self {}
    }
}

impl Generator for Ast {
    fn word_stream<'a>(
        &'a self,
        approx_len: usize,
        rng: &'a mut crate::Rng,
    ) -> Box<dyn Iterator<Item = Cow<'a, str>> + 'a> {
        fn gen_adjective(words: &mut Vec<&'static str>, rng: &mut crate::Rng, len: usize) {
            if len > 1 && rng.random_bool(0.15) {
                words.extend(*[&["very"][..], &["not", "very"][..]].choose(rng).unwrap());
            }

            words.extend(
                *[
                    &["blue"][..],
                    &["red"][..],
                    &["big"][..],
                    &["nice"][..],
                    &["happy"][..],
                    &["small"][..],
                    &["angry"][..],
                    &["stupid"][..],
                    &["terrible"][..],
                    &["anti-capitalist"][..],
                    &["hateful"][..],
                    &["beautiful"][..],
                    &["spammy"][..],
                    &["funny"][..],
                    &["bald"][..],
                    &["long"][..],
                    &["short"][..],
                    &["enviable"][..],
                    &["articulate"][..],
                    &["fraudulent"][..],
                    &["communist"][..],
                    &["rotund"][..],
                ]
                .choose(rng)
                .unwrap(),
            );
        }

        fn gen_noun(words: &mut Vec<&'static str>, rng: &mut crate::Rng, len: usize) {
            if len > 1 && rng.random_bool(0.25) {
                words.extend(
                    *[
                        &["my"][..],
                        &["your"][..],
                        &["my friend's"][..],
                        &["our"][..],
                        &["their"][..],
                    ]
                    .choose(rng)
                    .unwrap(),
                );
            }

            if len > 2 && rng.random_bool(0.25) {
                gen_adjective(words, rng, len - 1);
            }

            words.extend(
                *[
                    &["me"][..],
                    &["kangaroos"][..],
                    &["chips"][..],
                    &["carrots"][..],
                    &["weather"][..],
                    &["dogs"][..],
                    &["cats"][..],
                    &["salami"][..],
                    &["cabbage"][..],
                    &["computer"][..],
                    &["onion"][..],
                    &["Sam Altman"][..],
                    &["goblin"][..],
                    &["eagle"][..],
                    &["democracy"][..],
                    &["america"][..],
                ]
                .choose(rng)
                .unwrap(),
            );
        }

        fn gen_qualifier(words: &mut Vec<&'static str>, rng: &mut crate::Rng, _len: usize) {
            words.extend(
                *[&["quickly"][..], &["slowly"][..], &["joyfully"][..]]
                    .choose(rng)
                    .unwrap(),
            );
        }

        fn gen_verb(words: &mut Vec<&'static str>, rng: &mut crate::Rng, len: usize) {
            words.extend(
                *[
                    &["eats"][..],
                    &["runs"][..],
                    &["walks"][..],
                    &["speaks"][..],
                    &["speaks"][..],
                ]
                .choose(rng)
                .unwrap(),
            );

            if len > 1 && rng.random_bool(0.25) {
                gen_qualifier(words, rng, len - 1);
            }
        }

        fn gen_action(words: &mut Vec<&'static str>, rng: &mut crate::Rng, len: usize) {
            if len > 1 && rng.random_bool(0.25) {
                gen_qualifier(words, rng, len - 1);
            }

            words.extend(*[&["eats"][..], &["kills"][..]].choose(rng).unwrap());
        }

        fn gen_clause(words: &mut Vec<&'static str>, rng: &mut crate::Rng, len: usize) {
            if len > 5 {
                gen_clause(words, rng, len / 2);
                words.extend(
                    *[
                        &["because"][..],
                        &["and", "also"][..],
                        &["when"][..],
                        &["if"][..],
                        &["or"][..],
                        &["and"][..],
                        &["then"][..],
                    ]
                    .choose(rng)
                    .unwrap(),
                );
                gen_clause(words, rng, len - len / 2);
            } else {
                enum Kind {
                    Gen(fn(&mut Vec<&'static str>, &mut crate::Rng, usize)),
                    Word(&'static str),
                }

                let clauses = [
                    &[Kind::Gen(gen_noun), Kind::Gen(gen_verb)][..],
                    &[
                        Kind::Gen(gen_noun),
                        Kind::Gen(gen_action),
                        Kind::Gen(gen_noun),
                    ][..],
                ];
                let clause = clauses.choose(rng).unwrap();
                for k in *clause {
                    match k {
                        Kind::Word(w) => words.push(w),
                        Kind::Gen(f) => f(words, rng, len / clause.len()),
                    }
                }
            }
        }

        let mut words = Vec::new();
        gen_clause(&mut words, rng, approx_len);
        Box::new(words.into_iter().map(|word| word.into()))
    }
}
