use crate::parsers::wasot::{Footnote, Link, MetaLine};

/// An `Emitter` is a source of `Event`s.
pub trait Emitter: Send + Sync {
    /// The specific type of the iterator this emitter produces.
    type Reader: Iterator<Item = Event> + Send;

    /// Subscribes to the event stream, returning a new reader.
    fn subscribe(&self) -> Self::Reader;

    /// Starts the event emission process.
    fn run(self);

    /// Starts the event emission process with a context.
    fn run_with_context(self, _context: &mut crate::context::Context)
    where
        Self: Sized,
    {
        // Default implementation ignores context and calls run
        self.run();
    }
}

/// A `Consumer` processes `Event`s from an event stream.
pub trait Consumer: Send + Sync {
    fn on_start(&mut self) {}

    fn on_finish(&mut self) {}

    /// Handles a single event. This is what implementers will focus on.
    fn handle(&mut self, _event: Event) {}

    /// Handles a single event with a context. This calls the existing handle method by default.
    fn handle_with_context(&mut self, event: Event, _context: &mut crate::context::Context) {
        self.handle(event);
    }

    /// Runs the consumer, processing events from the given stream.
    /// This method has a default implementation and rarely needs to be overridden.
    fn run<I>(&mut self, events: I)
    where
        I: Iterator<Item = Event> + Send,
    {
        self.on_start();
        let mut context = crate::context::Context::new();
        for event in events {
            // The default implementation calls the handle_with_context method.
            self.handle_with_context(event, &mut context);
        }
        self.on_finish();
    }
}

/// Event types for element parsing
#[derive(Debug, Clone, PartialEq)]
pub enum Event {
    /// Fired when a new block is started
    BlockStarted {
        /// The meta-line that defined this block
        meta_line: MetaLine,
    },
    /// Fired when a block is finished
    BlockFinished,
    /// Fired when a text element is finished
    TextFinished {
        /// The actual text lines
        lines: Vec<String>,
        /// Links found in each line (one Vec<Link> per line)
        links: Vec<Vec<Link>>,
        /// Footnotes found in the text
        footnotes: Vec<Footnote>,
    },
    /// Fired when a context line is encountered
    /// Context lines provide metadata without being part of the content hierarchy
    ContextLine {
        /// The meta-line that defines this context line
        meta_line: MetaLine,
    },
    /// Fired when a void element is encountered
    /// Void elements are self-closing and cannot have children (like HTML <br>, <img>)
    /// Syntax: `.hr:` (trailing colon marks void element)
    VoidElement {
        /// The meta-line that defines this void element
        meta_line: MetaLine,
    },
}

impl Event {
    /// Validate that the event contains reasonable data
    pub fn validate(&self) -> bool {
        match self {
            Event::BlockStarted { meta_line } => {
                debug_assert!(meta_line.level <= 100, "Block level should be reasonable");
                true
            }
            Event::BlockFinished => true,
            Event::TextFinished {
                lines,
                links,
                footnotes: _,
            } => {
                debug_assert!(
                    !lines.is_empty(),
                    "Text event should have at least one line"
                );
                debug_assert!(
                    lines.len() == links.len(),
                    "Should have equal number of lines and link vectors"
                );
                true
            }
            Event::ContextLine { meta_line } => {
                debug_assert!(
                    meta_line.level <= 100,
                    "Context line level should be reasonable"
                );
                true
            }
            Event::VoidElement { meta_line } => {
                debug_assert!(
                    meta_line.level <= 100,
                    "Void element level should be reasonable"
                );
                debug_assert!(
                    meta_line.is_void,
                    "VoidElement event should have is_void=true"
                );
                true
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::parsers::wasot::arguments::ParsedArguments;
    use crate::parsers::wasot::parser::{Id, QuotedString};

    // Mock Consumer to test the trait methods
    struct MockConsumer {
        start_called: bool,
        finish_called: bool,
        events_received: Vec<Event>,
    }

    impl MockConsumer {
        fn new() -> Self {
            Self {
                start_called: false,
                finish_called: false,
                events_received: Vec::new(),
            }
        }
    }

    impl Consumer for MockConsumer {
        fn on_start(&mut self) {
            self.start_called = true;
        }

        fn on_finish(&mut self) {
            self.finish_called = true;
        }

        fn handle(&mut self, event: Event) {
            self.events_received.push(event);
        }
    }

    #[test]
    fn test_consumer_on_start() {
        // Test line 17 in function on_start
        let mut consumer = MockConsumer::new();
        consumer.on_start();
        assert!(consumer.start_called);
    }

    #[test]
    fn test_consumer_on_finish() {
        // Test line 19 in function on_finish
        let mut consumer = MockConsumer::new();
        consumer.on_finish();
        assert!(consumer.finish_called);
    }

    #[test]
    fn test_consumer_run_with_events() {
        // Test lines 26, 30-31, 33, 35 in function run<I>
        let mut consumer = MockConsumer::new();

        // Create test events
        let meta_line = MetaLine {
            level: 1,
            type_name: "test".to_string(),
            id: Id::empty(),
            arguments: ParsedArguments {
                args: vec![],
                kwargs: vec![],
            },
            inline_text: QuotedString::new("".to_string(), false),
            line_index: Some(1),
            is_void: false,
        };

        let events = vec![
            Event::BlockStarted { meta_line },
            Event::TextFinished {
                lines: vec!["test line".to_string()],
                links: vec![vec![]],
                footnotes: vec![],
            },
            Event::BlockFinished,
        ];

        // Test the run method
        consumer.run(events.into_iter());

        // Verify all methods were called correctly
        assert!(consumer.start_called, "on_start should have been called");
        assert!(consumer.finish_called, "on_finish should have been called");
        assert_eq!(
            consumer.events_received.len(),
            3,
            "Should have received 3 events"
        );
    }

    #[test]
    fn test_consumer_run_with_empty_iterator() {
        // Test that run works with empty iterator
        let mut consumer = MockConsumer::new();
        let empty_events: Vec<Event> = vec![];

        consumer.run(empty_events.into_iter());

        assert!(
            consumer.start_called,
            "on_start should have been called even with empty iterator"
        );
        assert!(
            consumer.finish_called,
            "on_finish should have been called even with empty iterator"
        );
        assert_eq!(
            consumer.events_received.len(),
            0,
            "Should have received no events"
        );
    }

    #[test]
    fn test_event_validate_block_started() {
        // Test lines 62-66 in function validate for BlockStarted
        let meta_line = MetaLine {
            level: 1,
            type_name: "test".to_string(),
            id: Id::empty(),
            arguments: ParsedArguments {
                args: vec![],
                kwargs: vec![],
            },
            inline_text: QuotedString::new("".to_string(), false),
            line_index: Some(1),
            is_void: false,
        };

        let event = Event::BlockStarted { meta_line };
        assert!(
            event.validate(),
            "BlockStarted event should validate successfully"
        );
    }

    #[test]
    fn test_event_validate_block_finished() {
        // Test lines 68-69 in function validate for BlockFinished
        let event = Event::BlockFinished;
        assert!(
            event.validate(),
            "BlockFinished event should validate successfully"
        );
    }

    #[test]
    fn test_event_validate_text_finished() {
        // Test line 74 and 78 in function validate for TextFinished
        let event = Event::TextFinished {
            lines: vec!["line1".to_string(), "line2".to_string()],
            links: vec![vec![], vec![]], // Equal number of link vectors as lines
            footnotes: vec![],
        };
        assert!(
            event.validate(),
            "TextFinished event should validate successfully"
        );
    }

    #[test]
    fn test_event_validate_text_finished_single_line() {
        // Test line 82 - single line case
        let event = Event::TextFinished {
            lines: vec!["single line".to_string()],
            links: vec![vec![]], // One link vector for one line
            footnotes: vec![],
        };
        assert!(
            event.validate(),
            "Single line TextFinished event should validate successfully"
        );
    }

    #[test]
    fn test_event_clone() {
        // Test that events can be cloned (derives Clone)
        let meta_line = MetaLine {
            level: 1,
            type_name: "test".to_string(),
            id: Id::empty(),
            arguments: ParsedArguments {
                args: vec![],
                kwargs: vec![],
            },
            inline_text: QuotedString::new("".to_string(), false),
            line_index: Some(1),
            is_void: false,
        };

        let event = Event::BlockStarted { meta_line };
        let cloned_event = event.clone();

        assert_eq!(
            event, cloned_event,
            "Cloned event should be equal to original"
        );
    }

    #[test]
    fn test_event_debug() {
        // Test that events can be debug printed (derives Debug)
        let event = Event::BlockFinished;
        let debug_string = format!("{event:?}");
        assert!(
            debug_string.contains("BlockFinished"),
            "Debug string should contain event type"
        );
    }

    #[test]
    fn test_event_partial_eq() {
        // Test that events can be compared (derives PartialEq)
        let event1 = Event::BlockFinished;
        let event2 = Event::BlockFinished;

        assert_eq!(event1, event2, "Identical events should be equal");

        let meta_line = MetaLine {
            level: 1,
            type_name: "test".to_string(),
            id: Id::empty(),
            arguments: ParsedArguments {
                args: vec![],
                kwargs: vec![],
            },
            inline_text: QuotedString::new("".to_string(), false),
            line_index: Some(1),
            is_void: false,
        };

        let event3 = Event::BlockStarted {
            meta_line: meta_line.clone(),
        };
        let event4 = Event::BlockStarted { meta_line };

        assert_eq!(
            event3, event4,
            "Events with identical meta_lines should be equal"
        );
        assert_ne!(event1, event3, "Different event types should not be equal");
    }
}
