#[cfg(test)]
mod tests {

    use crate::emitters::wasot_file_emitter::WasotFileEmitter;
    use crate::events::{Consumer, Emitter, Event};
    use std::io::Cursor;
    use std::sync::{Arc, Mutex};

    /// A test consumer that collects events for testing
    struct AutoConvertTestConsumer {
        events: Arc<Mutex<Vec<Event>>>,
    }

    impl AutoConvertTestConsumer {
        fn new() -> Self {
            Self {
                events: Arc::new(Mutex::new(Vec::new())),
            }
        }
    }

    impl Consumer for AutoConvertTestConsumer {
        fn handle(&mut self, event: Event) {
            self.events.lock().unwrap().push(event);
        }
    }

    #[test]
    fn test_auto_convert_links_to_footnotes_enabled() {
        let wasot_content = r#"
Check out this ((great website :https://example.com)) for more info.
Also see ((another site :https://test.org)) and ((third link :https://demo.net)).
"#;

        let cursor = Cursor::new(wasot_content.as_bytes());
        let emitter = WasotFileEmitter::from_reader(Box::new(cursor))
            .with_auto_convert_links_to_footnotes(true);
        let consumer = AutoConvertTestConsumer::new();
        let consumer_events = consumer.events.clone();

        // Create a reader from the emitter
        let reader = emitter.subscribe();

        // Run the emitter in the background
        std::thread::spawn(move || {
            emitter.run();
        });

        // Consume events
        let mut consumer_instance = consumer;
        consumer_instance.run(reader);

        // Check the collected events
        let events = consumer_events.lock().unwrap().clone();

        // Should have at least one TextFinished event
        let text_events: Vec<_> = events
            .iter()
            .filter_map(|e| match e {
                Event::TextFinished {
                    lines,
                    links: _,
                    footnotes,
                } => Some((lines, footnotes)),
                _ => None,
            })
            .collect();

        assert!(
            !text_events.is_empty(),
            "Should have at least one TextFinished event"
        );

        let (lines, footnotes) = &text_events[0];

        // Check that links were converted to footnote markers
        let text_content = lines.join(" ");
        assert!(
            text_content.contains("*1"),
            "Should contain footnote marker *1"
        );
        assert!(
            text_content.contains("*2"),
            "Should contain footnote marker *2"
        );
        assert!(
            text_content.contains("*3"),
            "Should contain footnote marker *3"
        );

        // Should not contain the original link syntax
        assert!(
            !text_content.contains(":https://example.com"),
            "Should not contain original link target"
        );
        assert!(
            !text_content.contains(":https://test.org"),
            "Should not contain original link target"
        );
        assert!(
            !text_content.contains(":https://demo.net"),
            "Should not contain original link target"
        );

        // Check that footnotes were generated
        assert_eq!(footnotes.len(), 3, "Should have 3 generated footnotes");

        assert_eq!(footnotes[0].marker, 1);
        assert_eq!(footnotes[0].link, "https://example.com");

        assert_eq!(footnotes[1].marker, 2);
        assert_eq!(footnotes[1].link, "https://test.org");

        assert_eq!(footnotes[2].marker, 3);
        assert_eq!(footnotes[2].link, "https://demo.net");
    }

    #[test]
    fn test_auto_convert_links_to_footnotes_disabled() {
        let wasot_content = r#"
Check out this ((great website :https://example.com)) for more info.
Also see ((another site :https://test.org)) and ((third link :https://demo.net)).
"#;

        let cursor = Cursor::new(wasot_content.as_bytes());
        let emitter = WasotFileEmitter::from_reader(Box::new(cursor))
            .with_auto_convert_links_to_footnotes(false);
        let consumer = AutoConvertTestConsumer::new();
        let consumer_events = consumer.events.clone();

        // Create a reader from the emitter
        let reader = emitter.subscribe();

        // Run the emitter in the background
        std::thread::spawn(move || {
            emitter.run();
        });

        // Consume events
        let mut consumer_instance = consumer;
        consumer_instance.run(reader);

        // Check the collected events
        let events = consumer_events.lock().unwrap().clone();

        // Should have at least one TextFinished event
        let text_events: Vec<_> = events
            .iter()
            .filter_map(|e| match e {
                Event::TextFinished {
                    lines,
                    links,
                    footnotes,
                } => Some((lines, links, footnotes)),
                _ => None,
            })
            .collect();

        assert!(
            !text_events.is_empty(),
            "Should have at least one TextFinished event"
        );

        let (lines, links, footnotes) = &text_events[0];

        // Links should NOT be converted - original link syntax should remain
        let text_content = lines.join(" ");
        assert!(
            text_content.contains(":https://example.com"),
            "Should contain original link target"
        );
        assert!(
            text_content.contains(":https://test.org"),
            "Should contain original link target"
        );
        assert!(
            text_content.contains(":https://demo.net"),
            "Should contain original link target"
        );

        // Should not contain footnote markers
        assert!(
            !text_content.contains("*1"),
            "Should not contain footnote marker *1"
        );
        assert!(
            !text_content.contains("*2"),
            "Should not contain footnote marker *2"
        );
        assert!(
            !text_content.contains("*3"),
            "Should not contain footnote marker *3"
        );

        // Should have links parsed normally
        let total_links: usize = links.iter().map(|line_links| line_links.len()).sum();
        assert!(total_links > 0, "Should have parsed links");

        // Should have no generated footnotes
        assert_eq!(
            footnotes.len(),
            0,
            "Should have no generated footnotes when disabled"
        );
    }

    #[test]
    fn test_auto_convert_with_existing_footnotes() {
        let wasot_content = r#"
Some text with ((link :https://example.com)).
*1 Existing footnote
More text with ((another link :https://test.org)).
*5 Another existing footnote
"#;

        let cursor = Cursor::new(wasot_content.as_bytes());
        let emitter = WasotFileEmitter::from_reader(Box::new(cursor))
            .with_auto_convert_links_to_footnotes(true);
        let consumer = AutoConvertTestConsumer::new();
        let consumer_events = consumer.events.clone();

        // Create a reader from the emitter
        let reader = emitter.subscribe();

        // Run the emitter in the background
        std::thread::spawn(move || {
            emitter.run();
        });

        // Consume events
        let mut consumer_instance = consumer;
        consumer_instance.run(reader);

        // Check the collected events
        let events = consumer_events.lock().unwrap().clone();

        let text_events: Vec<_> = events
            .iter()
            .filter_map(|e| match e {
                Event::TextFinished {
                    lines,
                    links: _,
                    footnotes,
                } => Some((lines, footnotes)),
                _ => None,
            })
            .collect();

        assert!(
            !text_events.is_empty(),
            "Should have at least one TextFinished event"
        );

        let (lines, footnotes) = &text_events[0];

        // Should have both existing and generated footnotes
        assert!(
            footnotes.len() >= 4,
            "Should have at least 4 footnotes (2 existing + 2 generated)"
        );

        // Check that existing footnotes are preserved
        assert!(footnotes
            .iter()
            .any(|f| f.marker == 1 && f.link == "Existing footnote"));
        assert!(footnotes
            .iter()
            .any(|f| f.marker == 5 && f.link == "Another existing footnote"));

        // Check that generated footnotes start after highest existing marker (5)
        let generated_footnotes: Vec<_> = footnotes
            .iter()
            .filter(|f| f.link.starts_with("https://"))
            .collect();
        assert_eq!(
            generated_footnotes.len(),
            2,
            "Should have 2 generated footnotes"
        );

        // Generated footnotes should start from marker 6
        assert!(generated_footnotes
            .iter()
            .any(|f| f.marker == 6 && f.link == "https://example.com"));
        assert!(generated_footnotes
            .iter()
            .any(|f| f.marker == 7 && f.link == "https://test.org"));

        // Text should contain the new markers
        let text_content = lines.join(" ");
        assert!(
            text_content.contains("*6"),
            "Should contain footnote marker *6"
        );
        assert!(
            text_content.contains("*7"),
            "Should contain footnote marker *7"
        );
    }

    #[test]
    fn test_auto_convert_links_without_targets() {
        let wasot_content = r#"
Some text with ((link without target)) and ((another link :https://example.com)).
"#;

        let cursor = Cursor::new(wasot_content.as_bytes());
        let emitter = WasotFileEmitter::from_reader(Box::new(cursor))
            .with_auto_convert_links_to_footnotes(true);
        let consumer = AutoConvertTestConsumer::new();
        let consumer_events = consumer.events.clone();

        let reader = emitter.subscribe();
        std::thread::spawn(move || {
            emitter.run();
        });

        let mut consumer_instance = consumer;
        consumer_instance.run(reader);

        let events = consumer_events.lock().unwrap().clone();
        let text_events: Vec<_> = events
            .iter()
            .filter_map(|e| match e {
                Event::TextFinished {
                    lines,
                    links: _,
                    footnotes,
                } => Some((lines, footnotes)),
                _ => None,
            })
            .collect();

        assert!(
            !text_events.is_empty(),
            "Should have at least one TextFinished event"
        );

        let (lines, footnotes) = &text_events[0];

        // Only the link with a target should be converted
        assert_eq!(footnotes.len(), 1, "Should have 1 generated footnote");
        assert_eq!(footnotes[0].marker, 1);
        assert_eq!(footnotes[0].link, "https://example.com");

        let text_content = lines.join(" ");
        // Link without target should remain unchanged
        assert!(
            text_content.contains("((link without target))"),
            "Link without target should remain"
        );
        // Link with target should be converted
        assert!(
            text_content.contains("*1"),
            "Should contain footnote marker *1"
        );
        assert!(
            !text_content.contains(":https://example.com"),
            "Should not contain original target"
        );
    }

    #[test]
    fn test_auto_convert_default_enabled() {
        // Test that auto-conversion is enabled by default
        let wasot_content = r#"
Text with ((link :https://example.com)).
"#;

        let cursor = Cursor::new(wasot_content.as_bytes());
        // Don't call with_auto_convert_links_to_footnotes - should default to true
        let emitter = WasotFileEmitter::from_reader(Box::new(cursor));
        let consumer = AutoConvertTestConsumer::new();
        let consumer_events = consumer.events.clone();

        let reader = emitter.subscribe();
        std::thread::spawn(move || {
            emitter.run();
        });

        let mut consumer_instance = consumer;
        consumer_instance.run(reader);

        let events = consumer_events.lock().unwrap().clone();
        let text_events: Vec<_> = events
            .iter()
            .filter_map(|e| match e {
                Event::TextFinished {
                    lines,
                    links: _,
                    footnotes,
                } => Some((lines, footnotes)),
                _ => None,
            })
            .collect();

        assert!(
            !text_events.is_empty(),
            "Should have at least one TextFinished event"
        );

        let (lines, footnotes) = &text_events[0];

        // Should be converted by default
        assert_eq!(
            footnotes.len(),
            1,
            "Should have 1 generated footnote by default"
        );
        assert_eq!(footnotes[0].link, "https://example.com");

        let text_content = lines.join(" ");
        assert!(
            text_content.contains("*1"),
            "Should contain footnote marker *1 by default"
        );
    }

    #[test]
    fn test_auto_convert_complex_links() {
        let wasot_content = r#"
See ((Example Site .. arg1 key=value :https://example.com)) and ((Named Link .. name="test" :https://test.org)).
"#;

        let cursor = Cursor::new(wasot_content.as_bytes());
        let emitter = WasotFileEmitter::from_reader(Box::new(cursor))
            .with_auto_convert_links_to_footnotes(true);
        let consumer = AutoConvertTestConsumer::new();
        let consumer_events = consumer.events.clone();

        let reader = emitter.subscribe();
        std::thread::spawn(move || {
            emitter.run();
        });

        let mut consumer_instance = consumer;
        consumer_instance.run(reader);

        let events = consumer_events.lock().unwrap().clone();
        let text_events: Vec<_> = events
            .iter()
            .filter_map(|e| match e {
                Event::TextFinished {
                    lines,
                    links: _,
                    footnotes,
                } => Some((lines, footnotes)),
                _ => None,
            })
            .collect();

        assert!(
            !text_events.is_empty(),
            "Should have at least one TextFinished event"
        );

        let (lines, footnotes) = &text_events[0];

        // Both complex links should be converted
        assert_eq!(footnotes.len(), 2, "Should have 2 generated footnotes");

        assert_eq!(footnotes[0].marker, 1);
        assert_eq!(footnotes[0].link, "https://example.com");

        assert_eq!(footnotes[1].marker, 2);
        assert_eq!(footnotes[1].link, "https://test.org");

        let text_content = lines.join(" ");
        assert!(
            text_content.contains("*1"),
            "Should contain footnote marker *1"
        );
        assert!(
            text_content.contains("*2"),
            "Should contain footnote marker *2"
        );

        // Original complex link syntax should be replaced
        assert!(
            !text_content.contains("arg1 key=value :https://example.com"),
            "Should not contain original complex link"
        );
        assert!(
            !text_content.contains("name=\"test\" :https://test.org"),
            "Should not contain original complex link"
        );
    }

    #[test]
    fn test_auto_convert_multiple_links_same_line() {
        let wasot_content = r#"
Visit ((Site A :https://a.com)) and ((Site B :https://b.com)) then ((Site C :https://c.com)).
"#;

        let cursor = Cursor::new(wasot_content.as_bytes());
        let emitter = WasotFileEmitter::from_reader(Box::new(cursor))
            .with_auto_convert_links_to_footnotes(true);
        let consumer = AutoConvertTestConsumer::new();
        let consumer_events = consumer.events.clone();

        let reader = emitter.subscribe();
        std::thread::spawn(move || {
            emitter.run();
        });

        let mut consumer_instance = consumer;
        consumer_instance.run(reader);

        let events = consumer_events.lock().unwrap().clone();
        let text_events: Vec<_> = events
            .iter()
            .filter_map(|e| match e {
                Event::TextFinished {
                    lines,
                    links: _,
                    footnotes,
                } => Some((lines, footnotes)),
                _ => None,
            })
            .collect();

        assert!(
            !text_events.is_empty(),
            "Should have at least one TextFinished event"
        );

        let (lines, footnotes) = &text_events[0];

        // All three links should be converted
        assert_eq!(footnotes.len(), 3, "Should have 3 generated footnotes");

        let text_content = lines.join(" ");
        assert!(
            text_content.contains("*1"),
            "Should contain footnote marker *1"
        );
        assert!(
            text_content.contains("*2"),
            "Should contain footnote marker *2"
        );
        assert!(
            text_content.contains("*3"),
            "Should contain footnote marker *3"
        );

        // Check footnote content
        assert_eq!(footnotes[0].link, "https://a.com");
        assert_eq!(footnotes[1].link, "https://b.com");
        assert_eq!(footnotes[2].link, "https://c.com");
    }

    #[test]
    fn test_auto_convert_nested_quotes_in_links() {
        let wasot_content = r#"
Check ((this "quoted" link :https://example.com)) out.
"#;

        let cursor = Cursor::new(wasot_content.as_bytes());
        let emitter = WasotFileEmitter::from_reader(Box::new(cursor))
            .with_auto_convert_links_to_footnotes(true);
        let consumer = AutoConvertTestConsumer::new();
        let consumer_events = consumer.events.clone();

        let reader = emitter.subscribe();
        std::thread::spawn(move || {
            emitter.run();
        });

        let mut consumer_instance = consumer;
        consumer_instance.run(reader);

        let events = consumer_events.lock().unwrap().clone();
        let text_events: Vec<_> = events
            .iter()
            .filter_map(|e| match e {
                Event::TextFinished {
                    lines,
                    links: _,
                    footnotes,
                } => Some((lines, footnotes)),
                _ => None,
            })
            .collect();

        assert!(
            !text_events.is_empty(),
            "Should have at least one TextFinished event"
        );

        let (lines, footnotes) = &text_events[0];

        assert_eq!(footnotes.len(), 1, "Should have 1 generated footnote");
        assert_eq!(footnotes[0].link, "https://example.com");

        let text_content = lines.join(" ");
        assert!(
            text_content.contains("*1"),
            "Should contain footnote marker *1"
        );
    }

    #[test]
    fn test_auto_convert_unicode_links() {
        let wasot_content = r#"
Visit ((测试网站 :https://例子.com)) and ((Café Website :https://café.org)).
"#;

        let cursor = Cursor::new(wasot_content.as_bytes());
        let emitter = WasotFileEmitter::from_reader(Box::new(cursor))
            .with_auto_convert_links_to_footnotes(true);
        let consumer = AutoConvertTestConsumer::new();
        let consumer_events = consumer.events.clone();

        let reader = emitter.subscribe();
        std::thread::spawn(move || {
            emitter.run();
        });

        let mut consumer_instance = consumer;
        consumer_instance.run(reader);

        let events = consumer_events.lock().unwrap().clone();
        let text_events: Vec<_> = events
            .iter()
            .filter_map(|e| match e {
                Event::TextFinished {
                    lines,
                    links: _,
                    footnotes,
                } => Some((lines, footnotes)),
                _ => None,
            })
            .collect();

        assert!(
            !text_events.is_empty(),
            "Should have at least one TextFinished event"
        );

        let (lines, footnotes) = &text_events[0];

        assert_eq!(footnotes.len(), 2, "Should have 2 generated footnotes");
        assert_eq!(footnotes[0].link, "https://例子.com");
        assert_eq!(footnotes[1].link, "https://café.org");

        let text_content = lines.join(" ");
        assert!(
            text_content.contains("*1"),
            "Should contain footnote marker *1"
        );
        assert!(
            text_content.contains("*2"),
            "Should contain footnote marker *2"
        );
    }

    #[test]
    fn test_auto_convert_empty_links() {
        let wasot_content = r#"
Text with (()) empty link and ((valid :https://example.com)) link.
"#;

        let cursor = Cursor::new(wasot_content.as_bytes());
        let emitter = WasotFileEmitter::from_reader(Box::new(cursor))
            .with_auto_convert_links_to_footnotes(true);
        let consumer = AutoConvertTestConsumer::new();
        let consumer_events = consumer.events.clone();

        let reader = emitter.subscribe();
        std::thread::spawn(move || {
            emitter.run();
        });

        let mut consumer_instance = consumer;
        consumer_instance.run(reader);

        let events = consumer_events.lock().unwrap().clone();
        let text_events: Vec<_> = events
            .iter()
            .filter_map(|e| match e {
                Event::TextFinished {
                    lines,
                    links: _,
                    footnotes,
                } => Some((lines, footnotes)),
                _ => None,
            })
            .collect();

        assert!(
            !text_events.is_empty(),
            "Should have at least one TextFinished event"
        );

        let (lines, footnotes) = &text_events[0];

        // Only the valid link should be converted
        assert_eq!(footnotes.len(), 1, "Should have 1 generated footnote");
        assert_eq!(footnotes[0].link, "https://example.com");

        let text_content = lines.join(" ");
        assert!(
            text_content.contains("(())"),
            "Empty link should remain unchanged"
        );
        assert!(
            text_content.contains("*1"),
            "Should contain footnote marker *1"
        );
    }

    #[test]
    fn test_auto_convert_footnote_type_targets() {
        let wasot_content = r#"
See ((reference :*42)) and ((website :https://example.com)).
"#;

        let cursor = Cursor::new(wasot_content.as_bytes());
        let emitter = WasotFileEmitter::from_reader(Box::new(cursor))
            .with_auto_convert_links_to_footnotes(true);
        let consumer = AutoConvertTestConsumer::new();
        let consumer_events = consumer.events.clone();

        let reader = emitter.subscribe();
        std::thread::spawn(move || {
            emitter.run();
        });

        let mut consumer_instance = consumer;
        consumer_instance.run(reader);

        let events = consumer_events.lock().unwrap().clone();
        let text_events: Vec<_> = events
            .iter()
            .filter_map(|e| match e {
                Event::TextFinished {
                    lines,
                    links: _,
                    footnotes,
                } => Some((lines, footnotes)),
                _ => None,
            })
            .collect();

        assert!(
            !text_events.is_empty(),
            "Should have at least one TextFinished event"
        );

        let (_lines, footnotes) = &text_events[0];

        // Only URI links should be converted, not footnote references
        assert_eq!(footnotes.len(), 1, "Should have 1 generated footnote");

        let footnote_links: Vec<_> = footnotes.iter().map(|f| &f.link).collect();
        assert!(
            footnote_links.contains(&&"https://example.com".to_string()),
            "Should have URI"
        );
    }

    #[test]
    fn test_auto_convert_id_type_targets() {
        let wasot_content = r#"
Link to ((section :intro)) and ((website :https://example.com)).
"#;

        let cursor = Cursor::new(wasot_content.as_bytes());
        let emitter = WasotFileEmitter::from_reader(Box::new(cursor))
            .with_auto_convert_links_to_footnotes(true);
        let consumer = AutoConvertTestConsumer::new();
        let consumer_events = consumer.events.clone();

        let reader = emitter.subscribe();
        std::thread::spawn(move || {
            emitter.run();
        });

        let mut consumer_instance = consumer;
        consumer_instance.run(reader);

        let events = consumer_events.lock().unwrap().clone();
        let text_events: Vec<_> = events
            .iter()
            .filter_map(|e| match e {
                Event::TextFinished {
                    lines,
                    links: _,
                    footnotes,
                } => Some((lines, footnotes)),
                _ => None,
            })
            .collect();

        assert!(
            !text_events.is_empty(),
            "Should have at least one TextFinished event"
        );

        let (_lines, footnotes) = &text_events[0];

        // Only URI links should be converted, not ID references
        assert_eq!(footnotes.len(), 1, "Should have 1 generated footnote");

        let footnote_links: Vec<_> = footnotes.iter().map(|f| &f.link).collect();
        assert!(
            footnote_links.contains(&&"https://example.com".to_string()),
            "Should have URI"
        );
    }

    #[test]
    fn test_auto_convert_very_long_urls() {
        let long_url = format!("https://example.com/{}", "a".repeat(500));
        let wasot_content = format!("See ((long link :{long_url})).");

        let cursor = Cursor::new(wasot_content.clone().into_bytes());
        let emitter = WasotFileEmitter::from_reader(Box::new(cursor))
            .with_auto_convert_links_to_footnotes(true);
        let consumer = AutoConvertTestConsumer::new();
        let consumer_events = consumer.events.clone();

        let reader = emitter.subscribe();
        std::thread::spawn(move || {
            emitter.run();
        });

        let mut consumer_instance = consumer;
        consumer_instance.run(reader);

        let events = consumer_events.lock().unwrap().clone();
        let text_events: Vec<_> = events
            .iter()
            .filter_map(|e| match e {
                Event::TextFinished {
                    lines,
                    links: _,
                    footnotes,
                } => Some((lines, footnotes)),
                _ => None,
            })
            .collect();

        assert!(
            !text_events.is_empty(),
            "Should have at least one TextFinished event"
        );

        let (lines, footnotes) = &text_events[0];

        assert_eq!(footnotes.len(), 1, "Should have 1 generated footnote");
        assert_eq!(footnotes[0].link, long_url);

        let text_content = lines.join(" ");
        assert!(
            text_content.contains("*1"),
            "Should contain footnote marker *1"
        );
        assert!(
            !text_content.contains(&long_url),
            "Should not contain the long URL inline"
        );
    }

    #[test]
    fn test_auto_convert_mixed_content_blocks() {
        let wasot_content = r#"
.paragraph
First paragraph with ((link :https://a.com)).

.quote  
Quote with ((another link :https://b.com)).
"#;

        let cursor = Cursor::new(wasot_content.as_bytes());
        let emitter = WasotFileEmitter::from_reader(Box::new(cursor))
            .with_auto_convert_links_to_footnotes(true);
        let consumer = AutoConvertTestConsumer::new();
        let consumer_events = consumer.events.clone();

        let reader = emitter.subscribe();
        std::thread::spawn(move || {
            emitter.run();
        });

        let mut consumer_instance = consumer;
        consumer_instance.run(reader);

        let events = consumer_events.lock().unwrap().clone();

        // Should have multiple TextFinished events for different blocks
        let text_events: Vec<_> = events
            .iter()
            .filter_map(|e| match e {
                Event::TextFinished {
                    lines,
                    links: _,
                    footnotes,
                } => Some((lines, footnotes)),
                _ => None,
            })
            .collect();

        assert!(
            text_events.len() >= 2,
            "Should have multiple TextFinished events"
        );

        // Count total footnotes across all text blocks
        let total_footnotes: usize = text_events
            .iter()
            .map(|(_, footnotes)| footnotes.len())
            .sum();
        assert_eq!(
            total_footnotes, 2,
            "Should have 2 total generated footnotes"
        );

        // Check that markers were generated for each block
        let all_text: String = text_events
            .iter()
            .flat_map(|(lines, _)| lines.iter())
            .cloned()
            .collect::<Vec<_>>()
            .join(" ");

        assert!(
            all_text.contains("*1") || all_text.contains("*2"),
            "Should contain footnote markers"
        );
    }

    #[test]
    fn test_auto_convert_special_characters_in_urls() {
        let wasot_content = r#"
Link to ((API :https://api.example.com/users?id=123&format=json&callback=test)) endpoint.
"#;

        let cursor = Cursor::new(wasot_content.as_bytes());
        let emitter = WasotFileEmitter::from_reader(Box::new(cursor))
            .with_auto_convert_links_to_footnotes(true);
        let consumer = AutoConvertTestConsumer::new();
        let consumer_events = consumer.events.clone();

        let reader = emitter.subscribe();
        std::thread::spawn(move || {
            emitter.run();
        });

        let mut consumer_instance = consumer;
        consumer_instance.run(reader);

        let events = consumer_events.lock().unwrap().clone();
        let text_events: Vec<_> = events
            .iter()
            .filter_map(|e| match e {
                Event::TextFinished {
                    lines,
                    links: _,
                    footnotes,
                } => Some((lines, footnotes)),
                _ => None,
            })
            .collect();

        assert!(
            !text_events.is_empty(),
            "Should have at least one TextFinished event"
        );

        let (lines, footnotes) = &text_events[0];

        assert_eq!(footnotes.len(), 1, "Should have 1 generated footnote");
        assert_eq!(
            footnotes[0].link,
            "https://api.example.com/users?id=123&format=json&callback=test"
        );

        let text_content = lines.join(" ");
        assert!(
            text_content.contains("*1"),
            "Should contain footnote marker *1"
        );
    }
}
