use super::block::BlockContainer;
use super::element_parser::ElementParser;
use super::parser::{is_meta_line, MetaLine};
use super::{parse_footnotes, Footnote};
use crate::events::events::Emitter;
use crate::events::{BusReaderIterator, Event};
use bus::Bus;
use std::fs::File;
use std::io::{self, BufRead, BufReader, Read};
use std::path::Path;
use std::sync::{Arc, Mutex};

/// Document parser that processes Wasot files and builds hierarchical block structures
/// Can also emit events via the Emitter trait for stream processing
pub struct DocumentParser {
    /// Path to the Wasot file to read (for emitter mode)
    file_path: Option<String>,
    /// Optional reader for stdin or other sources (for emitter mode)
    reader: Option<Box<dyn Read + Send + Sync>>,
    /// Bus for events (for emitter mode)
    bus: Arc<Mutex<Bus<Event>>>,
    /// Accumulated text lines for batching
    accumulated_text_lines: Vec<String>,
    /// Line index of the first accumulated text line
    first_text_line_index: Option<usize>,
    /// Whether to automatically convert inline links to footnotes
    auto_convert_links_to_footnotes: bool,
}

impl DocumentParser {
    /// Create a new document parser for direct parsing
    #[must_use]
    pub fn new() -> Self {
        let bus = Arc::new(Mutex::new(Bus::new(1000)));
        DocumentParser {
            file_path: None,
            reader: None,
            bus,
            accumulated_text_lines: Vec::new(),
            first_text_line_index: None,
            auto_convert_links_to_footnotes: true,
        }
    }

    /// Create a document parser emitter from a file path
    #[must_use]
    pub fn from_file<P: AsRef<Path>>(file_path: P) -> Self {
        let bus = Arc::new(Mutex::new(Bus::new(1000)));
        Self {
            file_path: Some(file_path.as_ref().to_string_lossy().into_owned()),
            reader: None,
            bus,
            accumulated_text_lines: Vec::new(),
            first_text_line_index: None,
            auto_convert_links_to_footnotes: true,
        }
    }

    /// Create a document parser emitter from a reader (e.g., stdin)
    #[must_use]
    pub fn from_reader<R: Read + Send + Sync + 'static>(reader: R) -> Self {
        let bus = Arc::new(Mutex::new(Bus::new(1000)));
        Self {
            file_path: None,
            reader: Some(Box::new(reader)),
            bus,
            accumulated_text_lines: Vec::new(),
            first_text_line_index: None,
            auto_convert_links_to_footnotes: true,
        }
    }

    /// Create a document parser emitter from stdin
    #[must_use]
    pub fn from_stdin() -> Self {
        Self::from_reader(io::stdin())
    }

    /// Create a document parser emitter from a string
    #[must_use]
    pub fn from_string(content: String) -> Self {
        Self::from_reader(io::Cursor::new(content))
    }

    /// Set whether to automatically convert inline links to footnotes
    pub fn with_auto_convert_links_to_footnotes(mut self, auto_convert: bool) -> Self {
        self.auto_convert_links_to_footnotes = auto_convert;
        self
    }

    /// Parse a Wasot document from a file path (direct mode)
    pub fn parse_file<P: AsRef<Path>>(file_path: P) -> io::Result<BlockContainer> {
        let mut element_parser = ElementParser::new();
        let file = File::open(file_path)?;
        let buf_reader = BufReader::new(file);

        for (line_index, line_result) in buf_reader.lines().enumerate() {
            let line = line_result?;
            let _closed_count = element_parser
                .process_line(&line, line_index)
                .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
        }

        element_parser
            .finish()
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;

        Ok(element_parser.container().clone())
    }

    /// Parse a Wasot document from any reader (direct mode)
    pub fn parse_reader<R: Read>(reader: R) -> io::Result<BlockContainer> {
        let mut element_parser = ElementParser::new();
        let buf_reader = BufReader::new(reader);

        for (line_index, line_result) in buf_reader.lines().enumerate() {
            let line = line_result?;
            let _closed_count = element_parser
                .process_line(&line, line_index)
                .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
        }

        element_parser
            .finish()
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;

        Ok(element_parser.container().clone())
    }

    /// Parse a Wasot document from a string (direct mode)
    pub fn parse_string(content: &str) -> Result<BlockContainer, String> {
        let mut element_parser = ElementParser::new();

        for (line_index, line) in content.lines().enumerate() {
            let _closed_count = element_parser.process_line(line, line_index)?;
        }

        let _closed_count = element_parser.finish()?;
        Ok(element_parser.container().clone())
    }

    /// Flush any accumulated text lines as a TextFinished event
    fn flush_accumulated_text(&mut self) {
        if !self.accumulated_text_lines.is_empty() {
            // Convert links to footnotes if enabled
            let (processed_lines, generated_footnotes) = if self.auto_convert_links_to_footnotes {
                self.convert_links_to_footnotes(&self.accumulated_text_lines)
            } else {
                (self.accumulated_text_lines.clone(), Vec::new())
            };

            // Parse links from each processed text line
            let links: Vec<Vec<super::Link>> = processed_lines
                .iter()
                .map(|line| {
                    let spans = super::detect_links(line);
                    spans
                        .into_iter()
                        .map(|span| super::parse_link(&span.content, span.start_index, span.length))
                        .collect()
                })
                .collect();

            // Parse existing footnotes from all processed text lines
            let mut footnotes = parse_footnotes(&processed_lines);

            // Add generated footnotes from link conversion
            footnotes.extend(generated_footnotes);

            let event = Event::TextFinished {
                lines: processed_lines,
                links,
                footnotes,
            };
            if let Ok(mut bus) = self.bus.lock() {
                bus.broadcast(event);
            }
            self.accumulated_text_lines.clear();
            self.first_text_line_index = None;
        }
    }

    /// Convert inline links in text lines to footnotes
    /// Returns (processed_lines, generated_footnotes)
    fn convert_links_to_footnotes(&self, lines: &[String]) -> (Vec<String>, Vec<Footnote>) {
        let mut processed_lines = Vec::new();
        let mut generated_footnotes = Vec::new();
        // Find the highest existing footnote marker to continue numbering
        let existing_footnotes = parse_footnotes(lines);
        let max_existing_marker = existing_footnotes
            .iter()
            .map(|f| f.marker)
            .max()
            .unwrap_or(0);
        let mut footnote_counter = max_existing_marker + 1;

        for line in lines {
            let spans = super::detect_links(line);

            if spans.is_empty() {
                // No links in this line, keep as-is
                processed_lines.push(line.clone());
            } else {
                // Process links in this line
                let mut processed_line = line.clone();
                let mut offset = 0i32; // Track character offset changes due to replacements

                for span in spans {
                    let link = super::parse_link(&span.content, span.start_index, span.length);

                    // Only convert links that have a target (URI or other)
                    if let Some(target) = &link.target {
                        // Create footnote marker
                        let marker_text = format!("*{footnote_counter}");

                        // Calculate adjusted positions based on previous replacements
                        let start_pos = (span.start_index as i32 + offset) as usize;
                        let end_pos = start_pos + span.length;

                        // Replace the link with the footnote marker
                        if start_pos <= processed_line.len() && end_pos <= processed_line.len() {
                            processed_line.replace_range(start_pos..end_pos, &marker_text);

                            // Update offset for next replacements
                            offset += marker_text.len() as i32 - span.length as i32;
                        }

                        // Create footnote entry
                        generated_footnotes.push(Footnote {
                            marker: footnote_counter,
                            link: target.clone(),
                        });

                        footnote_counter += 1;
                    }
                }

                processed_lines.push(processed_line);
            }
        }

        (processed_lines, generated_footnotes)
    }

    /// Add a text line to the accumulator
    fn accumulate_text_line(&mut self, line: String, line_index: usize) {
        if self.first_text_line_index.is_none() {
            self.first_text_line_index = Some(line_index);
        }
        self.accumulated_text_lines.push(line);
    }

    /// Process a single line and emit events to the bus
    fn process_line_with_events(
        &mut self,
        element_parser: &mut ElementParser,
        line: &str,
        line_index: usize,
    ) -> Result<(), String> {
        // Emit appropriate events based on line type
        if is_meta_line(line) {
            // Flush any accumulated text before processing meta line
            self.flush_accumulated_text();

            if let Some(mut meta_line) = MetaLine::parse(line, line_index) {
                // Check if this is a context line (type_name starts with '/')
                // Context lines use syntax: ./mytag or ../mytag
                if meta_line.type_name.starts_with('/') {
                    // Strip the leading '/' from type_name
                    meta_line.type_name = meta_line.type_name[1..].to_string();

                    // Emit ContextLine event (context lines don't affect block structure)
                    let event = Event::ContextLine { meta_line };
                    if let Ok(mut bus) = self.bus.lock() {
                        bus.broadcast(event);
                    }
                } else {
                    // Regular block or heading
                    // Check if this is a heading (empty type_name means heading)
                    let is_heading = meta_line.type_name.is_empty();

                    // Emit BlockStarted event
                    let event = Event::BlockStarted {
                        meta_line: meta_line.clone(),
                    };
                    if let Ok(mut bus) = self.bus.lock() {
                        bus.broadcast(event);
                    }

                    // If it's a heading, immediately emit BlockFinished since headings are self-closing
                    if is_heading {
                        let event = Event::BlockFinished;
                        if let Ok(mut bus) = self.bus.lock() {
                            bus.broadcast(event);
                        }
                    }
                }
            }
        } else {
            // This is text content - accumulate it
            self.accumulate_text_line(line.to_string(), line_index);
        }

        // Process with ElementParser and emit BlockFinished events
        let closed_count = element_parser.process_line(line, line_index)?;

        // Emit BlockFinished events for each block that was closed
        for _ in 0..closed_count {
            let event = Event::BlockFinished;
            if let Ok(mut bus) = self.bus.lock() {
                bus.broadcast(event);
            }
        }

        Ok(())
    }
}

impl Default for DocumentParser {
    fn default() -> Self {
        Self::new()
    }
}

impl Emitter for DocumentParser {
    type Reader = BusReaderIterator;

    fn subscribe(&self) -> Self::Reader {
        let bus_reader = self.bus.lock().unwrap().add_rx();
        BusReaderIterator::new(bus_reader)
    }

    fn run(mut self) {
        // Create an element parser in streaming mode (memory-efficient)
        let mut element_parser = ElementParser::new_streaming();

        // Get the reader
        let reader: Box<dyn Read + Send + Sync> = match (&self.file_path, &mut self.reader) {
            (Some(path), _) => match File::open(path) {
                Ok(file) => Box::new(file),
                Err(e) => {
                    eprintln!("Error opening file: {e}");
                    return;
                }
            },
            (None, Some(reader)) => {
                // We need to take ownership of the reader to avoid double-borrow
                let mut buffer = Vec::new();
                match reader.read_to_end(&mut buffer) {
                    Ok(_) => Box::new(io::Cursor::new(buffer)),
                    Err(e) => {
                        eprintln!("Error reading from reader: {e}");
                        return;
                    }
                }
            }
            (None, None) => {
                eprintln!("No file path or reader provided");
                return;
            }
        };

        let buf_reader = BufReader::new(reader);

        // Process each line and emit events
        for (line_index, line_result) in buf_reader.lines().enumerate() {
            let line = match line_result {
                Ok(line) => line,
                Err(e) => {
                    eprintln!("Error reading line: {e}");
                    break;
                }
            };

            // Process line with custom event emission
            if let Err(e) = self.process_line_with_events(&mut element_parser, &line, line_index) {
                eprintln!("Error processing line: {e}");
                break;
            }
        }

        // Flush any remaining accumulated text
        self.flush_accumulated_text();

        // Finish parsing and emit BlockFinished events
        match element_parser.finish() {
            Ok(closed_count) => {
                // Emit BlockFinished events for each block that was closed during finish
                for _ in 0..closed_count {
                    let event = Event::BlockFinished;
                    if let Ok(mut bus) = self.bus.lock() {
                        bus.broadcast(event);
                    }
                }
            }
            Err(e) => {
                eprintln!("Error finishing parsing: {e}");
            }
        }
    }
}

/// Convenience function to parse a file and return the block container
#[allow(dead_code)]
pub fn parse_file<P: AsRef<Path>>(file_path: P) -> io::Result<BlockContainer> {
    DocumentParser::parse_file(file_path)
}

/// Convenience function to parse a string and return the block container
#[allow(dead_code)]
pub fn parse_string(content: &str) -> Result<BlockContainer, String> {
    DocumentParser::parse_string(content)
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::Element;
    use std::io::Cursor;
    use std::thread;

    #[test]
    fn test_document_parser_creation() {
        let _parser = DocumentParser::new();
        // Parser is now stateless for emitter mode
    }

    #[test]
    fn test_parse_simple_string() {
        let content = ".p\nHello world\nSecond line";

        let container = DocumentParser::parse_string(content).unwrap();
        assert_eq!(container.len(), 1);

        let block = container.get_block(0).unwrap();
        assert_eq!(block.block_type(), "p");
        let mut text_content = Vec::new();
        for child in &block.children {
            if let Element::Text(text) = child {
                text_content.extend(text.lines.clone());
            }
        }
        assert_eq!(text_content.len(), 2);
        assert_eq!(text_content[0], "Hello world");
        assert_eq!(text_content[1], "Second line");
    }

    #[test]
    fn test_parse_nested_blocks() {
        let content = r".div
Content for div
..p
Content for paragraph
...span
Content for span";

        let container = DocumentParser::parse_string(content).unwrap();
        assert_eq!(container.len(), 3); // All blocks are flattened in container

        // Check the blocks were created with correct types and levels
        let div_block = container.get_block(2).unwrap(); // Last to be finished
        assert_eq!(div_block.block_type(), "div");
        assert_eq!(div_block.level(), 1);
        let mut div_content = Vec::new();
        for child in &div_block.children {
            if let Element::Text(text) = child {
                div_content.extend(text.lines.clone());
            }
        }
        assert_eq!(div_content.join("\n"), "Content for div");

        let p_block = container.get_block(1).unwrap();
        assert_eq!(p_block.block_type(), "p");
        assert_eq!(p_block.level(), 2);
        let mut p_content = Vec::new();
        for child in &p_block.children {
            if let Element::Text(text) = child {
                p_content.extend(text.lines.clone());
            }
        }
        assert_eq!(p_content.join("\n"), "Content for paragraph");

        let span_block = container.get_block(0).unwrap(); // First to be finished
        assert_eq!(span_block.block_type(), "span");
        assert_eq!(span_block.level(), 3);
        let mut span_content = Vec::new();
        for child in &span_block.children {
            if let Element::Text(text) = child {
                span_content.extend(text.lines.clone());
            }
        }
        assert_eq!(span_content.join("\n"), "Content for span");
    }

    #[test]
    fn test_parse_with_headings() {
        let content = r".. Main Heading
.p
Some content
... Sub Heading
More content";

        let container = DocumentParser::parse_string(content).unwrap();

        // We should have: heading, p block, sub-heading, text after sub-heading
        assert_eq!(container.len(), 4);

        // Check heading block (first in container)
        let heading = container.get_block(0).unwrap();
        assert_eq!(heading.block_type(), "##");
        assert!(heading.is_heading());
        assert_eq!(heading.inline_text().content, "Main Heading");

        // Check p block
        let p_block = container.get_block(1).unwrap();
        assert_eq!(p_block.block_type(), "p");
        let mut p_content = Vec::new();
        for child in &p_block.children {
            if let Element::Text(text) = child {
                p_content.extend(text.lines.clone());
            }
        }
        assert_eq!(p_content.join("\n"), "Some content");

        // Check sub-heading
        let sub_heading = container.get_block(2).unwrap();
        assert_eq!(sub_heading.block_type(), "###");
        assert!(sub_heading.is_heading());
        assert_eq!(sub_heading.inline_text().content, "Sub Heading");

        // Check text after sub-heading (implicit text block)
        let text_block = container.get_block(3).unwrap();
        assert_eq!(text_block.block_type(), "text");
        assert!(text_block.is_implicit_text());
        let mut text_content = Vec::new();
        for child in &text_block.children {
            if let Element::Text(text) = child {
                text_content.extend(text.lines.clone());
            }
        }
        assert_eq!(text_content.join("\n"), "More content");
    }

    #[test]
    fn test_parse_with_implicit_text() {
        let content = r"This is implicit text
More implicit text

.p
Block content";

        let container = DocumentParser::parse_string(content).unwrap();
        assert_eq!(container.len(), 2);

        // Check implicit text block
        let text_block = container.get_block(0).unwrap();
        assert_eq!(text_block.block_type(), "text");
        assert!(text_block.is_implicit_text());
        // Check that we have the correct number of lines (including empty lines)
        // Access the actual Text element to get the raw lines
        if let Some(text_element) = text_block.children.first() {
            if let Some(text) = text_element.as_text() {
                assert_eq!(text.lines.len(), 3);
                assert_eq!(text.lines[0], "This is implicit text");
                assert_eq!(text.lines[1], "More implicit text");
                assert_eq!(text.lines[2], ""); // Empty line
            } else {
                panic!("Expected Text element");
            }
        } else {
            panic!("Expected at least one child element");
        }

        // Check explicit block
        let p_block = container.get_block(1).unwrap();
        assert_eq!(p_block.block_type(), "p");
        let mut p_content = Vec::new();
        for child in &p_block.children {
            if let Element::Text(text) = child {
                p_content.extend(text.lines.clone());
            }
        }
        assert_eq!(p_content.join("\n"), "Block content");
    }

    #[test]
    fn test_document_parser_as_emitter() {
        let content = ".div\nContent\n..p\nNested content";
        let emitter = DocumentParser::from_string(content.to_string());
        let receiver = emitter.subscribe();

        // Run the emitter in a background thread
        let handle = thread::spawn(move || {
            emitter.run();
        });

        let mut collected_events = Vec::new();

        // Collect events (should get at least a few)
        for event in receiver.take(6) {
            collected_events.push(event);
        }

        // Wait for the emitter to finish
        let _ = handle.join();

        assert!(!collected_events.is_empty());
        // Should have various block and text events
    }

    #[test]
    fn test_parse_reader() {
        let content = ".p\nHello from reader";
        let cursor = Cursor::new(content.as_bytes());

        let container = DocumentParser::parse_reader(cursor).unwrap();
        assert_eq!(container.len(), 1);

        let block = container.get_block(0).unwrap();
        assert_eq!(block.block_type(), "p");
        let mut block_content = Vec::new();
        for child in &block.children {
            if let Element::Text(text) = child {
                block_content.extend(text.lines.clone());
            }
        }
        assert_eq!(block_content.join("\n"), "Hello from reader");
    }

    #[test]
    fn test_parse_file_not_found() {
        let result = DocumentParser::parse_file("/non/existent/file.wasot");
        assert!(result.is_err());
        match result {
            Err(e) => assert_eq!(e.kind(), io::ErrorKind::NotFound),
            _ => panic!("Expected NotFound error"),
        }
    }

    #[test]
    fn test_parse_reader_error() {
        // Create a reader that always fails
        struct FailingReader;
        impl Read for FailingReader {
            fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
                Err(io::Error::other("Read failed"))
            }
        }

        let result = DocumentParser::parse_reader(FailingReader);
        assert!(result.is_err());
    }

    #[test]
    fn test_parse_string_invalid_meta_line() {
        // This should not cause an error - invalid meta lines are just treated as text
        let result = DocumentParser::parse_string("Valid line\n.invalid\x00meta\nMore text");
        assert!(result.is_ok());

        let container = result.unwrap();
        // Should have two blocks: first implicit text, then meta block
        assert_eq!(container.len(), 2);
    }

    #[test]
    fn test_multiple_parsing_calls() {
        // Test that static methods can be called multiple times
        let container1 = DocumentParser::parse_string(".p\nFirst document").unwrap();
        assert_eq!(container1.len(), 1);

        let container2 = DocumentParser::parse_string(".div\nSecond document").unwrap();
        assert_eq!(container2.len(), 1);

        let block = container2.get_block(0).unwrap();
        assert_eq!(block.block_type(), "div");
        let mut block_content = Vec::new();
        for child in &block.children {
            if let Element::Text(text) = child {
                block_content.extend(text.lines.clone());
            }
        }
        assert_eq!(block_content.join("\n"), "Second document");
    }

    #[test]
    fn test_explicit_block_closing() {
        let content = r".div
Content for div
./
More implicit text";

        let container = DocumentParser::parse_string(content).unwrap();
        assert_eq!(container.len(), 2);

        // Check div block was closed
        let div_block = container.get_block(0).unwrap();
        assert_eq!(div_block.block_type(), "div");
        let mut div_content = Vec::new();
        for child in &div_block.children {
            if let Element::Text(text) = child {
                div_content.extend(text.lines.clone());
            }
        }
        assert_eq!(div_content.join("\n"), "Content for div");

        // Check implicit text after closing
        let text_block = container.get_block(1).unwrap();
        assert_eq!(text_block.block_type(), "text");
        let mut text_content = Vec::new();
        for child in &text_block.children {
            if let Element::Text(text) = child {
                text_content.extend(text.lines.clone());
            }
        }
        assert_eq!(text_content.join("\n"), "More implicit text");
    }

    #[test]
    fn test_convenience_functions() {
        let content = ".p\nTest content";

        // Test parse_string function
        let container = parse_string(content).unwrap();
        assert_eq!(container.len(), 1);

        // Test that we can create emitters from various sources
        let _file_emitter = DocumentParser::from_file("test.wasot"); // Won't run without file
        let _string_emitter = DocumentParser::from_string(content.to_string());
        let _stdin_emitter = DocumentParser::from_stdin();
    }

    #[test]
    fn test_new_creates_default_state() {
        let parser = DocumentParser::new();
        assert!(parser.file_path.is_none());
        assert!(parser.reader.is_none());
        assert!(parser.accumulated_text_lines.is_empty());
        assert!(parser.first_text_line_index.is_none());
        assert!(parser.auto_convert_links_to_footnotes);
    }

    #[test]
    fn test_from_file_sets_path() {
        let parser = DocumentParser::from_file("test.wasot");
        assert_eq!(parser.file_path.as_ref().unwrap(), "test.wasot");
        assert!(parser.reader.is_none());
        assert!(parser.auto_convert_links_to_footnotes);
    }

    #[test]
    fn test_from_reader_sets_reader() {
        let content = "test content";
        let cursor = Cursor::new(content.as_bytes());
        let parser = DocumentParser::from_reader(cursor);
        assert!(parser.file_path.is_none());
        assert!(parser.reader.is_some());
        assert!(parser.auto_convert_links_to_footnotes);
    }

    #[test]
    fn test_from_stdin_creates_reader() {
        // We can't easily test actual stdin, but we can test the constructor pattern
        let parser = DocumentParser::from_stdin();
        assert!(parser.file_path.is_none());
        assert!(parser.reader.is_some());
    }

    #[test]
    fn test_from_string_creates_cursor() {
        let content = "test content";
        let parser = DocumentParser::from_string(content.to_string());
        assert!(parser.file_path.is_none());
        assert!(parser.reader.is_some());
    }

    #[test]
    fn test_with_auto_convert_links_to_footnotes() {
        let parser = DocumentParser::new().with_auto_convert_links_to_footnotes(false);
        assert!(!parser.auto_convert_links_to_footnotes);

        let parser = DocumentParser::new().with_auto_convert_links_to_footnotes(true);
        assert!(parser.auto_convert_links_to_footnotes);
    }

    #[test]
    fn test_parse_file_io_operations() {
        // Test with a temporary file
        use std::fs::File;
        use std::io::Write;
        use tempfile::tempdir;

        let dir = tempdir().unwrap();
        let file_path = dir.path().join("test.wasot");
        let mut file = File::create(&file_path).unwrap();
        writeln!(file, ".p").unwrap();
        writeln!(file, "Test content").unwrap();

        let container = DocumentParser::parse_file(&file_path).unwrap();
        assert_eq!(container.len(), 1);

        let block = container.get_block(0).unwrap();
        assert_eq!(block.block_type(), "p");
    }

    #[test]
    fn test_parse_reader_with_multiple_lines() {
        let content = ".div\nFirst line\nSecond line\n..p\nNested content";
        let cursor = Cursor::new(content.as_bytes());

        let container = DocumentParser::parse_reader(cursor).unwrap();
        assert_eq!(container.len(), 2);

        let p_block = container.get_block(0).unwrap(); // First finished
        assert_eq!(p_block.block_type(), "p");

        let div_block = container.get_block(1).unwrap(); // Second finished
        assert_eq!(div_block.block_type(), "div");
    }

    #[test]
    fn test_parse_string_with_line_enumeration() {
        let content = "Line 1\nLine 2\n.p\nBlock content";
        let container = DocumentParser::parse_string(content).unwrap();
        assert_eq!(container.len(), 2);

        // Check that line indices are properly handled
        let text_block = container.get_block(0).unwrap();
        assert_eq!(text_block.block_type(), "text");
        assert!(text_block.is_implicit_text());
    }

    #[test]
    fn test_flush_accumulated_text_empty() {
        let _parser = DocumentParser::new();
        // flush_accumulated_text is private, but we can test indirectly through parsing
        let container = DocumentParser::parse_string("").unwrap();
        assert_eq!(container.len(), 0);
    }

    #[test]
    fn test_flush_accumulated_text_with_content() {
        // Test via parsing which calls flush internally
        let content = "Text line 1\nText line 2\n.p\nBlock content";
        let container = DocumentParser::parse_string(content).unwrap();

        // Should have implicit text block and explicit p block
        assert_eq!(container.len(), 2);

        let text_block = container.get_block(0).unwrap();
        assert_eq!(text_block.block_type(), "text");
        if let Some(Element::Text(text)) = text_block.children.first() {
            assert_eq!(text.lines.len(), 2);
            assert_eq!(text.lines[0], "Text line 1");
            assert_eq!(text.lines[1], "Text line 2");
        }
    }

    #[test]
    fn test_convert_links_to_footnotes_no_links() {
        let content = "Regular text\nMore regular text\n.p\nBlock text";
        let _parser = DocumentParser::new().with_auto_convert_links_to_footnotes(true);
        let container = DocumentParser::parse_string(content).unwrap();

        // Should work normally with no links
        assert_eq!(container.len(), 2);
    }

    #[test]
    fn test_convert_links_to_footnotes_with_links() {
        // This test checks the link conversion functionality indirectly
        let content = "Check out [example](https://example.com)\n.p\nMore content";
        let _parser = DocumentParser::new().with_auto_convert_links_to_footnotes(true);
        let container = DocumentParser::parse_string(content).unwrap();

        assert_eq!(container.len(), 2);
        let text_block = container.get_block(0).unwrap();
        assert_eq!(text_block.block_type(), "text");
    }

    #[test]
    fn test_convert_links_to_footnotes_disabled() {
        let content = "Check out [example](https://example.com)\n.p\nMore content";
        let _parser = DocumentParser::new().with_auto_convert_links_to_footnotes(false);
        let container = DocumentParser::parse_string(content).unwrap();

        assert_eq!(container.len(), 2);
        let text_block = container.get_block(0).unwrap();
        assert_eq!(text_block.block_type(), "text");
    }

    #[test]
    fn test_accumulate_text_line_tracks_first_line() {
        // Test indirectly through parsing
        let content = "First text\nSecond text\nThird text";
        let container = DocumentParser::parse_string(content).unwrap();

        assert_eq!(container.len(), 1);
        let text_block = container.get_block(0).unwrap();
        if let Some(Element::Text(text)) = text_block.children.first() {
            assert_eq!(text.lines.len(), 3);
        }
    }

    #[test]
    fn test_process_line_with_events_meta_line() {
        // Test via emitter which uses process_line_with_events
        let content = ".div\nContent\n";
        let emitter = DocumentParser::from_string(content.to_string());
        let receiver = emitter.subscribe();

        let handle = thread::spawn(move || {
            emitter.run();
        });

        let events: Vec<_> = receiver.take(3).collect();
        let _ = handle.join();

        // Should have BlockStarted, TextFinished, BlockFinished events
        assert!(!events.is_empty());
    }

    #[test]
    fn test_process_line_with_events_text_line() {
        let content = "Regular text line\n.p\nBlock content";
        let emitter = DocumentParser::from_string(content.to_string());
        let receiver = emitter.subscribe();

        let handle = thread::spawn(move || {
            emitter.run();
        });

        let events: Vec<_> = receiver.take(5).collect();
        let _ = handle.join();

        assert!(!events.is_empty());
    }

    #[test]
    fn test_process_line_with_events_heading() {
        let content = ".# Heading\nMore text";
        let emitter = DocumentParser::from_string(content.to_string());
        let receiver = emitter.subscribe();

        let handle = thread::spawn(move || {
            emitter.run();
        });

        let events: Vec<_> = receiver.take(4).collect();
        let _ = handle.join();

        // Should have BlockStarted and immediate BlockFinished for heading
        assert!(!events.is_empty());
    }

    #[test]
    fn test_default_implementation() {
        let parser: DocumentParser = Default::default();
        assert!(parser.file_path.is_none());
        assert!(parser.reader.is_none());
        assert!(parser.accumulated_text_lines.is_empty());
    }

    #[test]
    fn test_emitter_subscribe() {
        let emitter = DocumentParser::from_string("test".to_string());
        let _receiver = emitter.subscribe();
        // Should not panic and should return a valid receiver
    }

    #[test]
    fn test_emitter_run_with_file_path() {
        use std::fs::File;
        use std::io::Write;
        use tempfile::tempdir;

        let dir = tempdir().unwrap();
        let file_path = dir.path().join("test.wasot");
        let mut file = File::create(&file_path).unwrap();
        writeln!(file, ".p").unwrap();
        writeln!(file, "Test content").unwrap();

        let emitter = DocumentParser::from_file(&file_path);
        let receiver = emitter.subscribe();

        let handle = thread::spawn(move || {
            emitter.run();
        });

        let events: Vec<_> = receiver.take(3).collect();
        let _ = handle.join();

        assert!(!events.is_empty());
    }

    #[test]
    fn test_emitter_run_with_reader() {
        let content = ".div\nContent from reader";
        let cursor = Cursor::new(content.as_bytes());
        let emitter = DocumentParser::from_reader(cursor);
        let receiver = emitter.subscribe();

        let handle = thread::spawn(move || {
            emitter.run();
        });

        let events: Vec<_> = receiver.take(3).collect();
        let _ = handle.join();

        assert!(!events.is_empty());
    }

    #[test]
    fn test_emitter_run_no_source() {
        // Test the error case where neither file_path nor reader is set
        let mut emitter = DocumentParser::new();
        // Force both to be None (which they should be by default)
        emitter.file_path = None;
        emitter.reader = None;

        let receiver = emitter.subscribe();
        let handle = thread::spawn(move || {
            emitter.run(); // Should print error and return early
        });

        // Give it a moment to process
        thread::sleep(std::time::Duration::from_millis(10));
        let events: Vec<_> = receiver.take(1).collect();
        let _ = handle.join();

        // Should have no events due to error
        assert!(events.is_empty());
    }

    #[test]
    fn test_emitter_run_file_not_found() {
        let emitter = DocumentParser::from_file("/non/existent/file.wasot");
        let receiver = emitter.subscribe();

        let handle = thread::spawn(move || {
            emitter.run(); // Should print error and return early
        });

        thread::sleep(std::time::Duration::from_millis(10));
        let events: Vec<_> = receiver.take(1).collect();
        let _ = handle.join();

        // Should have no events due to file error
        assert!(events.is_empty());
    }

    #[test]
    fn test_emitter_run_reader_error() {
        struct FailingReader;
        impl Read for FailingReader {
            fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
                Err(io::Error::other("Read failed"))
            }
        }

        let emitter = DocumentParser::from_reader(FailingReader);
        let receiver = emitter.subscribe();

        let handle = thread::spawn(move || {
            emitter.run(); // Should handle read error gracefully
        });

        thread::sleep(std::time::Duration::from_millis(10));
        let events: Vec<_> = receiver.take(1).collect();
        let _ = handle.join();

        // Should have no events due to read error
        assert!(events.is_empty());
    }

    #[test]
    fn test_parse_file_with_processing_error() {
        use std::fs::File;
        use std::io::Write;
        use tempfile::tempdir;

        let dir = tempdir().unwrap();
        let file_path = dir.path().join("test.wasot");
        let mut file = File::create(&file_path).unwrap();
        // Write content that might cause processing issues
        writeln!(file, ".p").unwrap();
        writeln!(file, "Normal content").unwrap();

        let result = DocumentParser::parse_file(&file_path);
        assert!(result.is_ok()); // Should handle gracefully
    }

    #[test]
    fn test_parse_reader_with_processing_error() {
        let content = ".p\nContent that should parse fine";
        let cursor = Cursor::new(content.as_bytes());

        let result = DocumentParser::parse_reader(cursor);
        assert!(result.is_ok()); // Should handle gracefully
    }

    #[test]
    fn test_parse_string_finish_error() {
        // Test string parsing that might have finish errors
        let content = ".div\nUnclosed content";
        let result = DocumentParser::parse_string(content);
        assert!(result.is_ok()); // Parser should handle unclosed blocks gracefully
    }

    #[test]
    fn test_convenience_parse_file_function() {
        use std::fs::File;
        use std::io::Write;
        use tempfile::tempdir;

        let dir = tempdir().unwrap();
        let file_path = dir.path().join("test.wasot");
        let mut file = File::create(&file_path).unwrap();
        writeln!(file, ".p").unwrap();
        writeln!(file, "Test content").unwrap();

        let container = parse_file(&file_path).unwrap();
        assert_eq!(container.len(), 1);
    }

    #[test]
    fn test_convenience_parse_string_function() {
        let content = ".p\nTest content";
        let container = parse_string(content).unwrap();
        assert_eq!(container.len(), 1);
    }
}
