use crate::events::{Emitter, Event};
use crate::parsers::wasot::{Id, MetaLine, ParsedArguments, QuotedString};
use rand::prelude::*;

pub struct RandomEmitter {
    event_count: usize,
    seed: Option<u64>,
}

pub struct RandomEmitterIterator {
    rng: StdRng,
    events_generated: usize,
    total_events: usize,
    open_blocks: usize,
    finished: bool,
}

impl RandomEmitter {
    pub fn new(event_count: usize) -> Self {
        Self {
            event_count,
            seed: None,
        }
    }

    pub fn with_seed(event_count: usize, seed: u64) -> Self {
        Self {
            event_count,
            seed: Some(seed),
        }
    }
}

impl RandomEmitterIterator {
    fn new(event_count: usize, seed: Option<u64>) -> Self {
        let rng = if let Some(seed) = seed {
            StdRng::seed_from_u64(seed)
        } else {
            StdRng::from_entropy()
        };

        Self {
            rng,
            events_generated: 0,
            total_events: event_count,
            open_blocks: 0,
            finished: false,
        }
    }

    fn generate_random_meta_line(&mut self) -> MetaLine {
        // Random level (1-4)
        let level = self.rng.gen_range(1..=4);

        // Random type name
        let type_name = self.generate_random_type_name();

        // Random inline text (50% chance)
        let inline_text = if self.rng.gen_bool(0.5) {
            QuotedString::new(
                self.generate_random_sentence(),
                self.rng.gen_bool(0.2), // 20% chance of being quoted
            )
        } else {
            QuotedString::new(String::new(), false)
        };

        // Random ID (30% chance)
        let id = if self.rng.gen_bool(0.3) {
            Id::new(self.generate_random_id())
        } else {
            Id::empty()
        };

        // Random arguments
        let arguments = self.generate_random_arguments();

        MetaLine {
            type_name,
            inline_text,
            level,
            id,
            line_index: None,
            arguments,
            is_void: false,
        }
    }

    fn generate_random_type_name(&mut self) -> String {
        let types = vec![
            "p",
            "div",
            "section",
            "heading",
            "code",
            "quote",
            "list",
            "item",
            "image",
            "link",
            "table",
            "row",
            "cell",
            "footer",
            "header",
            "nav",
            "article",
            "aside",
            "block",
            "container",
            "wrapper",
            "widget",
            "component",
            "#",
            "##",
            "###",
            "custom",
            "data",
            "meta",
            "config",
        ];

        if self.rng.gen_bool(0.1) {
            // 10% chance of empty type (heading)
            String::new()
        } else if self.rng.gen_bool(0.1) {
            // 10% chance of quoted type with spaces
            format!("custom {} type", types.choose(&mut self.rng).unwrap())
        } else {
            // 80% chance of normal type
            types.choose(&mut self.rng).unwrap().to_string()
        }
    }

    fn generate_random_id(&mut self) -> String {
        let parts: Vec<String> = (0..self.rng.gen_range(1..=3))
            .map(|_| self.generate_random_word(3, 10))
            .collect();
        parts.join(".")
    }

    fn generate_random_arguments(&mut self) -> ParsedArguments {
        let num_args = self.rng.gen_range(0..=3);
        let num_kwargs = self.rng.gen_range(0..=3);

        let args: Vec<QuotedString> = (0..num_args)
            .map(|_| {
                if self.rng.gen_bool(0.2) {
                    // 20% chance of quoted arg with spaces
                    QuotedString::new(self.generate_random_sentence(), true)
                } else {
                    QuotedString::new(self.generate_random_word(3, 12), false)
                }
            })
            .collect();

        let kwargs: Vec<(QuotedString, QuotedString)> = (0..num_kwargs)
            .map(|_| {
                let key = QuotedString::new(self.generate_random_word(3, 10), false);
                let value = if self.rng.gen_bool(0.3) {
                    // 30% chance of quoted value
                    QuotedString::new(self.generate_random_sentence(), true)
                } else {
                    QuotedString::new(self.generate_random_word(3, 15), false)
                };
                (key, value)
            })
            .collect();

        ParsedArguments { args, kwargs }
    }

    fn generate_random_text_lines(&mut self) -> Vec<String> {
        let num_lines = self.rng.gen_range(1..=5);
        (0..num_lines)
            .map(|_| self.generate_random_text_line())
            .collect()
    }

    fn generate_random_text_line(&mut self) -> String {
        let num_words = self.rng.gen_range(3..=15);
        let words: Vec<String> = (0..num_words)
            .map(|_| self.generate_random_word(2, 12))
            .collect();
        words.join(" ")
    }

    fn generate_random_sentence(&mut self) -> String {
        let num_words = self.rng.gen_range(3..=8);
        let words: Vec<String> = (0..num_words)
            .map(|_| self.generate_random_word(3, 10))
            .collect();
        let mut sentence = words.join(" ");
        if !sentence.is_empty() {
            // Capitalize first letter
            let mut chars = sentence.chars();
            if let Some(first) = chars.next() {
                sentence = first.to_uppercase().collect::<String>() + chars.as_str();
            }
        }
        sentence
    }

    fn generate_random_word(&mut self, min_len: usize, max_len: usize) -> String {
        let length = self.rng.gen_range(min_len..=max_len);
        let consonants = [
            'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v',
            'w', 'x', 'y', 'z',
        ];
        let vowels = ['a', 'e', 'i', 'o', 'u'];

        let mut word = String::new();
        let start_with_vowel = self.rng.gen_bool(0.3);

        for i in 0..length {
            if (i + start_with_vowel as usize).is_multiple_of(2) {
                word.push(*consonants.choose(&mut self.rng).unwrap());
            } else {
                word.push(*vowels.choose(&mut self.rng).unwrap());
            }
        }

        word
    }
}

impl Iterator for RandomEmitterIterator {
    type Item = Event;

    fn next(&mut self) -> Option<Self::Item> {
        if self.finished {
            return None;
        }

        // If we've generated all requested events, start closing blocks
        if self.events_generated >= self.total_events {
            if self.open_blocks > 0 {
                self.open_blocks -= 1;
                return Some(Event::BlockFinished);
            } else {
                self.finished = true;
                return None;
            }
        }

        // Generate a new event
        let event_type = self.rng.gen_range(0..10);

        let event = match event_type {
            0..=4 => {
                // Generate BlockStarted event (50% chance)
                let meta_line = self.generate_random_meta_line();
                self.open_blocks += 1;
                Event::BlockStarted { meta_line }
            }
            5..=7 => {
                // Generate TextFinished event (30% chance)
                let lines = self.generate_random_text_lines();
                if !lines.is_empty() {
                    // Generate empty links for each line (no links in random text)
                    let links = vec![Vec::new(); lines.len()];
                    Event::TextFinished {
                        lines,
                        links,
                        footnotes: vec![],
                    }
                } else {
                    // If no text was generated, generate a simple text event
                    Event::TextFinished {
                        lines: vec!["Empty text line".to_string()],
                        links: vec![Vec::new()],
                        footnotes: vec![],
                    }
                }
            }
            8..=9 => {
                // Generate BlockFinished event (20% chance)
                if self.open_blocks > 0 {
                    self.open_blocks -= 1;
                    Event::BlockFinished
                } else {
                    // Can't close a block if none are open, generate text instead
                    let lines = self.generate_random_text_lines();
                    let links = vec![Vec::new(); lines.len()];
                    Event::TextFinished {
                        lines,
                        links,
                        footnotes: vec![],
                    }
                }
            }
            _ => unreachable!(),
        };

        self.events_generated += 1;
        Some(event)
    }
}

impl Emitter for RandomEmitter {
    type Reader = RandomEmitterIterator;

    fn subscribe(&self) -> Self::Reader {
        RandomEmitterIterator::new(self.event_count, self.seed)
    }

    fn run(self) {
        // For the run method, we can just consume the iterator
        let _events: Vec<_> = self.subscribe().collect();
    }
}

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

    #[test]
    fn test_random_emitter_generates_events() {
        let emitter = RandomEmitter::new(10);
        let events: Vec<_> = emitter.subscribe().collect();
        assert!(!events.is_empty());
        assert!(events.len() >= 10); // At least the requested number
    }

    #[test]
    fn test_random_emitter_with_seed_is_deterministic() {
        let emitter1 = RandomEmitter::with_seed(20, 42);
        let emitter2 = RandomEmitter::with_seed(20, 42);

        let events1: Vec<_> = emitter1.subscribe().collect();
        let events2: Vec<_> = emitter2.subscribe().collect();

        assert_eq!(events1, events2);
    }

    #[test]
    fn test_all_blocks_are_closed() {
        let emitter = RandomEmitter::new(100);
        let events: Vec<_> = emitter.subscribe().collect();

        let mut open_blocks = 0;
        for event in &events {
            match event {
                Event::BlockStarted { .. } => open_blocks += 1,
                Event::BlockFinished => {
                    assert!(
                        open_blocks > 0,
                        "BlockFinished without matching BlockStarted"
                    );
                    open_blocks -= 1;
                }
                Event::TextFinished { .. }
                | Event::ContextLine { .. }
                | Event::VoidElement { .. } => {}
            }
        }
        assert_eq!(open_blocks, 0, "All blocks should be closed");
    }

    #[test]
    fn test_meta_line_validation() {
        let emitter = RandomEmitter::new(50);
        let events: Vec<_> = emitter.subscribe().collect();

        for event in &events {
            if let Event::BlockStarted { meta_line } = event {
                assert!(meta_line.level >= 1 && meta_line.level <= 4);
                assert!(event.validate());
            }
        }
    }

    #[test]
    fn test_text_events_have_content() {
        let emitter = RandomEmitter::new(50);
        let events: Vec<_> = emitter.subscribe().collect();

        for event in &events {
            if let Event::TextFinished {
                lines, links: _, ..
            } = event
            {
                assert!(!lines.is_empty());
                for line in lines {
                    assert!(!line.is_empty());
                }
                assert!(event.validate());
            }
        }
    }

    #[test]
    fn test_random_word_generation() {
        let mut iterator = RandomEmitterIterator::new(1, Some(42));

        for _ in 0..100 {
            let word = iterator.generate_random_word(3, 10);
            assert!(word.len() >= 3 && word.len() <= 10);
            assert!(word.chars().all(|c| c.is_alphabetic()));
        }
    }

    #[test]
    fn test_random_id_generation() {
        let mut iterator = RandomEmitterIterator::new(1, Some(42));

        for _ in 0..50 {
            let id = iterator.generate_random_id();
            assert!(!id.is_empty());
            // ID should contain only lowercase letters and dots
            assert!(id.chars().all(|c| c.is_lowercase() || c == '.'));
        }
    }

    #[test]
    fn test_event_distribution() {
        let emitter = RandomEmitter::with_seed(1000, 42);
        let events: Vec<_> = emitter.subscribe().collect();

        let mut block_started = 0;
        let mut block_finished = 0;
        let mut text_finished = 0;

        for event in &events {
            match event {
                Event::BlockStarted { .. } => block_started += 1,
                Event::BlockFinished => block_finished += 1,
                Event::TextFinished { .. } => text_finished += 1,
                Event::ContextLine { .. } | Event::VoidElement { .. } => {}
            }
        }

        // Should have a reasonable distribution
        assert!(block_started > 0);
        assert!(text_finished > 0);
        assert_eq!(block_started, block_finished); // All blocks closed
    }

    #[test]
    fn test_new_constructor() {
        let emitter = RandomEmitter::new(50);
        assert_eq!(emitter.event_count, 50);
        assert!(emitter.seed.is_none());
    }

    #[test]
    fn test_with_seed_constructor() {
        let emitter = RandomEmitter::with_seed(25, 12345);
        assert_eq!(emitter.event_count, 25);
        assert_eq!(emitter.seed, Some(12345));
    }

    #[test]
    fn test_iterator_new_with_seed() {
        let iterator = RandomEmitterIterator::new(10, Some(42));
        assert_eq!(iterator.events_generated, 0);
        assert_eq!(iterator.total_events, 10);
        assert_eq!(iterator.open_blocks, 0);
        assert!(!iterator.finished);
    }

    #[test]
    fn test_iterator_new_without_seed() {
        let iterator = RandomEmitterIterator::new(5, None);
        assert_eq!(iterator.events_generated, 0);
        assert_eq!(iterator.total_events, 5);
        assert_eq!(iterator.open_blocks, 0);
        assert!(!iterator.finished);
    }

    #[test]
    fn test_generate_random_meta_line_components() {
        let mut iterator = RandomEmitterIterator::new(1, Some(42));

        for _ in 0..20 {
            let meta_line = iterator.generate_random_meta_line();

            // Test level range
            assert!(meta_line.level >= 1 && meta_line.level <= 4);

            // Test type name is not null
            // Note: type_name can be empty for headings

            // Test arguments exist
            assert!(meta_line.arguments.args.len() <= 3);
            assert!(meta_line.arguments.kwargs.len() <= 3);

            // Test line_index is None as expected
            assert!(meta_line.line_index.is_none());
        }
    }

    #[test]
    fn test_generate_random_type_name_variations() {
        let mut iterator = RandomEmitterIterator::new(1, Some(42));
        let mut empty_count = 0;
        let mut _custom_count = 0;
        let mut normal_count = 0;

        // Generate many type names to test different cases
        for _ in 0..200 {
            let type_name = iterator.generate_random_type_name();

            if type_name.is_empty() {
                empty_count += 1;
            } else if type_name.contains("custom") && type_name.contains(" ") {
                _custom_count += 1;
            } else {
                normal_count += 1;
            }
        }

        // Should have some of each type with these probabilities
        assert!(empty_count > 0, "Should generate some empty type names");
        assert!(normal_count > 0, "Should generate some normal type names");
        // Custom types are rare (1% chance), might not appear in 200 trials
    }

    #[test]
    fn test_generate_random_id_format() {
        let mut iterator = RandomEmitterIterator::new(1, Some(42));

        for _ in 0..50 {
            let id = iterator.generate_random_id();

            // ID should be non-empty
            assert!(!id.is_empty());

            // Should contain 1-3 parts separated by dots
            let parts: Vec<&str> = id.split('.').collect();
            assert!(!parts.is_empty() && parts.len() <= 3);

            // Each part should be a valid word
            for part in parts {
                assert!(!part.is_empty());
                assert!(part.len() >= 3 && part.len() <= 10);
            }
        }
    }

    #[test]
    fn test_generate_random_arguments_structure() {
        let mut iterator = RandomEmitterIterator::new(1, Some(42));

        for _ in 0..30 {
            let args = iterator.generate_random_arguments();

            // Should respect the limits
            assert!(args.args.len() <= 3);
            assert!(args.kwargs.len() <= 3);

            // Test argument structure
            for arg in &args.args {
                assert!(!arg.content.is_empty());
            }

            // Test keyword argument structure
            for (key, value) in &args.kwargs {
                assert!(!key.content.is_empty());
                assert!(!value.content.is_empty());
            }
        }
    }

    #[test]
    fn test_generate_random_text_lines_count() {
        let mut iterator = RandomEmitterIterator::new(1, Some(42));

        for _ in 0..20 {
            let lines = iterator.generate_random_text_lines();

            // Should generate 1-5 lines
            assert!(!lines.is_empty() && lines.len() <= 5);

            // Each line should be non-empty
            for line in &lines {
                assert!(!line.is_empty());
                // Should have multiple words
                assert!(line.contains(' '));
            }
        }
    }

    #[test]
    fn test_generate_random_text_line_content() {
        let mut iterator = RandomEmitterIterator::new(1, Some(42));

        for _ in 0..20 {
            let line = iterator.generate_random_text_line();

            // Should be non-empty
            assert!(!line.is_empty());

            // Should have 3-15 words
            let word_count = line.split_whitespace().count();
            assert!((3..=15).contains(&word_count));

            // All characters should be alphabetic or spaces
            assert!(line.chars().all(|c| c.is_alphabetic() || c.is_whitespace()));
        }
    }

    #[test]
    fn test_generate_random_sentence_capitalization() {
        let mut iterator = RandomEmitterIterator::new(1, Some(42));

        for _ in 0..20 {
            let sentence = iterator.generate_random_sentence();

            if !sentence.is_empty() {
                // Should start with capital letter
                let first_char = sentence.chars().next().unwrap();
                assert!(
                    first_char.is_uppercase(),
                    "Sentence should start with capital: '{sentence}'"
                );

                // Should have 3-8 words
                let word_count = sentence.split_whitespace().count();
                assert!((3..=8).contains(&word_count));
            }
        }
    }

    #[test]
    fn test_generate_random_word_length_and_pattern() {
        let mut iterator = RandomEmitterIterator::new(1, Some(42));

        // Test different length ranges
        for min_len in 2..=5 {
            for max_len in min_len..=10 {
                let word = iterator.generate_random_word(min_len, max_len);

                assert!(word.len() >= min_len && word.len() <= max_len);
                assert!(word.chars().all(|c| c.is_alphabetic() && c.is_lowercase()));

                // Test consonant-vowel pattern (approximately)
                if word.len() > 1 {
                    let consonants = [
                        'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's',
                        't', 'v', 'w', 'x', 'y', 'z',
                    ];
                    let vowels = ['a', 'e', 'i', 'o', 'u'];

                    let chars: Vec<char> = word.chars().collect();

                    // Check that we have both consonants and vowels in reasonable words
                    let has_consonant = chars.iter().any(|c| consonants.contains(c));
                    let has_vowel = chars.iter().any(|c| vowels.contains(c));

                    // For longer words, expect both types
                    if word.len() >= 3 {
                        assert!(
                            has_consonant || has_vowel,
                            "Word should have consonants or vowels: '{word}'"
                        );
                    }
                }
            }
        }
    }

    #[test]
    fn test_iterator_finished_state() {
        let mut iterator = RandomEmitterIterator::new(2, Some(42));

        // Generate events until finished
        let mut count = 0;
        for _ in iterator.by_ref() {
            count += 1;
            // Prevent infinite loop
            assert!(count < 100, "Iterator should finish eventually");
        }

        // Should be finished now
        assert!(iterator.finished);

        // Should return None consistently after finishing
        assert!(iterator.next().is_none());
        assert!(iterator.next().is_none());
    }

    #[test]
    fn test_emitter_run_method() {
        let emitter = RandomEmitter::new(5);
        // Just verify run doesn't panic - it consumes the iterator
        emitter.run();
    }

    #[test]
    fn test_zero_events() {
        let emitter = RandomEmitter::new(0);
        let events: Vec<_> = emitter.subscribe().collect();

        // With 0 events requested, should only get BlockFinished events for cleanup
        for event in events {
            assert!(matches!(event, Event::BlockFinished));
        }
    }

    #[test]
    fn test_iterator_block_closing_logic() {
        let iterator = RandomEmitterIterator::new(3, Some(42));

        // Manually track events to test block closing
        let mut events = Vec::new();
        for event in iterator {
            events.push(event);
        }

        // Count blocks
        let mut open_blocks = 0;
        for event in &events {
            match event {
                Event::BlockStarted { .. } => open_blocks += 1,
                Event::BlockFinished => {
                    assert!(open_blocks > 0, "Cannot close block that wasn't opened");
                    open_blocks -= 1;
                }
                Event::TextFinished { .. }
                | Event::ContextLine { .. }
                | Event::VoidElement { .. } => {}
            }
        }

        // All blocks should be closed
        assert_eq!(open_blocks, 0);
    }

    #[test]
    fn test_text_event_links_structure() {
        let emitter = RandomEmitter::with_seed(20, 42);
        let events: Vec<_> = emitter.subscribe().collect();

        for event in events {
            if let Event::TextFinished {
                lines,
                links,
                footnotes,
            } = event
            {
                // Links should match number of lines
                assert_eq!(lines.len(), links.len());

                // Each line should have an empty links vector (no links in random text)
                for line_links in &links {
                    assert!(line_links.is_empty());
                }

                // Footnotes should be empty
                assert!(footnotes.is_empty());
            }
        }
    }
}
