use super::*;

#[test]
fn test_factory_creation() {
    let factory = MarkdownSyntaxFactory::new();
    assert!(factory.supports("markdown"));
    assert!(!factory.supports("rust"));
    assert_eq!(factory.supported_languages(), vec!["markdown"]);
}

#[test]
fn test_factory_default() {
    let factory = MarkdownSyntaxFactory::default();
    assert!(factory.supports("markdown"));
    assert!(!factory.supports("rust"));
}

#[test]
fn test_factory_supports_negative_cases() {
    let factory = MarkdownSyntaxFactory::new();
    assert!(!factory.supports(""));
    assert!(!factory.supports("Markdown"));
    assert!(!factory.supports("MARKDOWN"));
    assert!(!factory.supports("md"));
    assert!(!factory.supports("html"));
}

#[test]
fn test_create_driver() {
    let factory = MarkdownSyntaxFactory::new();

    let driver = factory.create("markdown");
    assert!(driver.is_some());

    let driver = factory.create("rust");
    assert!(driver.is_none());
}

#[test]
fn test_create_driver_unsupported_languages() {
    let factory = MarkdownSyntaxFactory::new();
    assert!(factory.create("").is_none());
    assert!(factory.create("Markdown").is_none());
    assert!(factory.create("md").is_none());
    assert!(factory.create("rust").is_none());
    assert!(factory.create("html").is_none());
}

#[test]
fn test_driver_not_parsed_before_parse() {
    let factory = MarkdownSyntaxFactory::new();
    let driver = factory.create("markdown").unwrap();
    assert!(!driver.is_parsed());
}

#[test]
fn test_driver_parse_and_highlights() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    // Parse simple Markdown
    driver.parse("# Hello World\n\nSome text.");
    assert!(driver.is_parsed());

    // Get highlights
    let highlights = driver.highlights(0..100);

    // Should have highlights for heading
    assert!(!highlights.is_empty(), "Expected highlights for Markdown");
}

#[test]
fn test_driver_language_id() {
    let factory = MarkdownSyntaxFactory::new();
    let driver = factory.create("markdown").unwrap();
    assert_eq!(driver.language(), "markdown");
}

#[test]
fn test_highlights_contain_heading() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("# Hello World");
    let highlights = driver.highlights(0..100);

    // Find heading highlight
    let heading_highlight = highlights
        .iter()
        .find(|h| h.category.as_str().starts_with("markup.heading"));

    assert!(heading_highlight.is_some(), "Expected heading highlight");
}

#[test]
fn test_highlights_h2_heading() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("## Sub Heading");
    let highlights = driver.highlights(0..100);

    let heading_highlight = highlights
        .iter()
        .find(|h| h.category.as_str().starts_with("markup.heading"));

    assert!(heading_highlight.is_some(), "Expected heading highlight for h2");
}

#[test]
fn test_highlights_contain_list_marker() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("- item 1\n- item 2");
    let highlights = driver.highlights(0..100);

    // Find list marker highlight
    let list_highlight = highlights
        .iter()
        .find(|h| h.category.as_str().starts_with("markup.list"));

    assert!(list_highlight.is_some(), "Expected list marker highlight");
}

#[test]
fn test_highlights_contain_code_block() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("```\ncode\n```");
    let highlights = driver.highlights(0..100);

    // Find code block highlight (markup.raw)
    let code_highlight = highlights
        .iter()
        .find(|h| h.category.as_str().starts_with("markup.raw"));

    assert!(code_highlight.is_some(), "Expected code block highlight");
}

#[test]
fn test_highlights_empty_range() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("# Hello");
    let highlights = driver.highlights(0..0);
    assert!(highlights.is_empty());
}

#[test]
fn test_highlights_partial_range() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    let code = "# Heading 1\n\n## Heading 2";
    driver.parse(code);

    // Only query first line
    let highlights = driver.highlights(0..11);
    for h in &highlights {
        assert!(
            h.start_byte < 11,
            "Highlight starts at {} which is outside requested range",
            h.start_byte
        );
    }
}

#[test]
fn test_reparse_updates_highlights() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    // First parse: heading (with trailing newline for proper parsing)
    driver.parse("# Hello\n\nSome text.");
    let h1 = driver.highlights(0..100);
    assert!(
        h1.iter()
            .any(|h| h.category.as_str().starts_with("markup.heading")),
        "Should have heading highlight"
    );

    // Re-parse: list
    driver.parse("- item 1\n- item 2");
    let h2 = driver.highlights(0..100);
    assert!(
        h2.iter()
            .any(|h| h.category.as_str().starts_with("markup.list")),
        "Should have list highlight after re-parse"
    );
}

#[test]
fn test_incremental_update() {
    use reovim_driver_syntax::SyntaxEdit;

    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    // Initial parse
    driver.parse("# Hello");
    assert!(driver.is_parsed());

    // Insert " World" at the end
    let updated = "# Hello World";
    let edit = SyntaxEdit::insert(7, 0, 7, 13, 0, 13);
    driver.update(updated, &edit);
    assert!(driver.is_parsed());

    let highlights = driver.highlights(0..updated.len());
    assert!(!highlights.is_empty(), "Should have highlights after incremental update");
}

#[test]
fn test_injections_detects_language() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("```rust\nfn main() {}\n```");
    let injections = driver.injections();

    // Should detect one injection for the Rust code block
    assert_eq!(injections.len(), 1, "Expected one injection for Rust code block");
    assert_eq!(injections[0].language_id, "rust", "Expected Rust language ID");
}

#[test]
fn test_injections_multiple_languages() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("```rust\nfn main() {}\n```\n\n```python\nprint('hello')\n```");
    let injections = driver.injections();

    // Should detect two injections
    assert_eq!(injections.len(), 2, "Expected two injections");

    let languages: Vec<&str> = injections.iter().map(|i| i.language_id.as_str()).collect();
    assert!(languages.contains(&"rust"), "Expected Rust injection");
    assert!(languages.contains(&"python"), "Expected Python injection");
}

#[test]
fn test_injections_no_language_tag() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    // Code block without language tag should have no injections
    driver.parse("```\nsome code\n```");
    let injections = driver.injections();
    assert!(
        injections.is_empty(),
        "Code block without language tag should have no injections"
    );
}

#[test]
fn test_injections_empty_for_plain_text() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("Just some plain text.\n\nAnother paragraph.");
    let injections = driver.injections();
    assert!(injections.is_empty(), "Plain text should have no injections");
}

#[test]
fn test_folds_returns_empty_for_markdown() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    // Markdown factory does not configure folds query
    driver.parse("# Heading\n\nParagraph.\n\n## Sub heading");
    let folds = driver.folds();
    assert!(folds.is_empty(), "Markdown should not have folds (no folds query configured)");
}

#[test]
fn test_indent_returns_none_for_markdown() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("# Heading\n\nParagraph.");
    let indent = driver.indent_for(0);
    assert!(indent.is_none(), "Markdown should not have indent hints (no indents query)");
}

#[test]
fn test_empty_file() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("");
    assert!(driver.is_parsed());

    let highlights = driver.highlights(0..0);
    assert!(highlights.is_empty());
}

#[test]
fn test_utf8_safety() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    // Parse Markdown with Unicode
    let code = "# \u{65e5}\u{672c}\u{8a9e}\u{898b}\u{51fa}\u{3057}\n\n- \u{00e9}moji \u{1f389}";
    driver.parse(code);
    let highlights = driver.highlights(0..code.len());

    // All byte ranges should be valid UTF-8 boundaries
    for span in &highlights {
        assert!(
            code.is_char_boundary(span.start_byte),
            "start_byte {} is not a char boundary in '{code}'",
            span.start_byte,
        );
        assert!(
            code.is_char_boundary(span.end_byte),
            "end_byte {} is not a char boundary in '{code}'",
            span.end_byte,
        );
    }
}

// ========================================================================
// Factory creates drivers for injection use
// ========================================================================

#[test]
fn test_factory_creates_drivers_for_injection() {
    let factory = MarkdownSyntaxFactory::new();

    // Factory should create drivers usable as injection children
    let driver1 = factory.create("markdown");
    let driver2 = factory.create("markdown");
    assert!(driver1.is_some(), "Should create Markdown driver for injection");
    assert!(driver2.is_some(), "Should create independent Markdown drivers");
}

// ========================================================================
// Module Trait Tests
// ========================================================================

#[test]
fn test_module_new() {
    let module = TreesitterMarkdownModule::new();
    let _id = module.id();
}

#[test]
fn test_module_default() {
    fn takes_default<T: Default>(val: T) -> T {
        drop(val);
        T::default()
    }
    let module = takes_default(TreesitterMarkdownModule::new());
    assert_eq!(module.name(), "Treesitter Markdown");
}

#[test]
fn test_module_id() {
    let module = TreesitterMarkdownModule::new();
    assert_eq!(module.id(), ModuleId::new("treesitter-markdown"));
}

#[test]
fn test_module_name() {
    let module = TreesitterMarkdownModule::new();
    assert_eq!(module.name(), "Treesitter Markdown");
}

#[test]
fn test_module_version() {
    let module = TreesitterMarkdownModule::new();
    let version = module.version();
    assert_eq!(version, Version::new(0, 9, 0));
}

#[test]
fn test_module_init() {
    use reovim_kernel::api::v1::ServiceRegistry;

    let mut module = TreesitterMarkdownModule::new();
    let kernel = reovim_kernel::api::v1::KernelContext::default();
    let services = Arc::new(ServiceRegistry::new());
    let ctx = ModuleContext::new(
        kernel,
        services.clone(),
        std::path::PathBuf::from("/tmp/test-data"),
        std::path::PathBuf::from("/tmp/test-cache"),
    );
    let result = module.init(&ctx);
    assert_eq!(result, ProbeResult::Success);

    // Verify that the factory was registered
    let syntax_store = services.get_or_create::<SyntaxFactoryStore>();
    let factory = syntax_store.find("markdown");
    assert!(factory.is_some(), "Markdown factory should be available after module init");
}

#[test]
fn test_module_exit() {
    let mut module = TreesitterMarkdownModule::new();
    let result = module.exit();
    assert!(result.is_ok());
}

// ========================================================================
// Send + Sync Tests
// ========================================================================

#[test]
fn test_factory_send_sync() {
    fn assert_send_sync<T: Send + Sync>() {}
    assert_send_sync::<MarkdownSyntaxFactory>();
}

#[test]
fn test_driver_send_sync() {
    fn assert_send_sync<T: Send + Sync + ?Sized>(_: &T) {}
    let factory = MarkdownSyntaxFactory::new();
    let driver = factory.create("markdown").unwrap();
    assert_send_sync(&*driver);
}

// ========================================================================
// Multiple Factory Instances
// ========================================================================

#[test]
fn test_multiple_factory_instances() {
    let factory1 = MarkdownSyntaxFactory::new();
    let factory2 = MarkdownSyntaxFactory::new();

    let mut driver1 = factory1.create("markdown").unwrap();
    let mut driver2 = factory2.create("markdown").unwrap();

    driver1.parse("# Heading 1");
    driver2.parse("- list item");

    assert!(driver1.is_parsed());
    assert!(driver2.is_parsed());

    let h1 = driver1.highlights(0..100);
    let h2 = driver2.highlights(0..100);

    assert!(!h1.is_empty());
    assert!(!h2.is_empty());
}

// ========================================================================
// Realistic Markdown Tests
// ========================================================================

#[test]
fn test_realistic_markdown_document() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    let code = r#"# Project Title

A short description.

## Features

- Feature one
- Feature two
- Feature three

## Code Example

```rust
fn main() {
println!("Hello!");
}
```

## License

MIT
"#;
    driver.parse(code);
    let highlights = driver.highlights(0..code.len());

    // Should have heading highlights
    assert!(
        highlights
            .iter()
            .any(|h| h.category.as_str().starts_with("markup.heading")),
        "Expected heading highlights in realistic document"
    );

    // Should have list highlights
    assert!(
        highlights
            .iter()
            .any(|h| h.category.as_str().starts_with("markup.list")),
        "Expected list highlights in realistic document"
    );

    // Should have code block highlights
    assert!(
        highlights
            .iter()
            .any(|h| h.category.as_str().starts_with("markup.raw")),
        "Expected code block highlights in realistic document"
    );

    // Injection detection
    let injections = driver.injections();
    assert_eq!(injections.len(), 1, "Expected one injection for rust code block");
    assert_eq!(injections[0].language_id, "rust");
}

// ========================================================================
// Decoration Tests
// ========================================================================

#[test]
fn test_decorations_heading_markers() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("# H1\n\n## H2\n\n### H3\n");
    let decos = driver.decorations(0..200);

    // Should have heading category annotations
    let headings: Vec<_> = decos
        .iter()
        .filter(|a| a.category.as_str().starts_with("markup.heading."))
        .collect();

    assert!(
        headings.len() >= 3,
        "Expected at least 3 heading marker annotations, got {}: {headings:?}",
        headings.len()
    );

    // Verify the h1 marker has correct category
    let h1 = decos
        .iter()
        .find(|a| a.category.as_str() == "markup.heading.1");
    assert!(h1.is_some(), "Expected markup.heading.1 decoration");
}

#[test]
fn test_decorations_all_heading_levels() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("# H1\n\n## H2\n\n### H3\n\n#### H4\n\n##### H5\n\n###### H6\n");
    let decos = driver.decorations(0..200);

    for level in 1..=6 {
        let category = format!("markup.heading.{level}");
        let found = decos.iter().any(|a| a.category.as_str() == category);
        assert!(found, "Expected decoration for {category}");
    }
}

#[test]
fn test_decorations_list_bullets() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("- item one\n- item two\n");
    let decos = driver.decorations(0..100);

    let bullets: Vec<_> = decos
        .iter()
        .filter(|a| a.category.as_str().starts_with("markup.list.bullet."))
        .collect();

    assert_eq!(bullets.len(), 2, "Expected 2 bullet decorations, got: {bullets:?}");
    // Top-level bullets should be depth 0
    for b in &bullets {
        assert_eq!(b.category.as_str(), "markup.list.bullet.0");
    }
}

#[test]
fn test_decorations_list_bullets_mixed_markers() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("- minus\n+ plus\n* star\n");
    let decos = driver.decorations(0..100);

    let bullet_count = decos
        .iter()
        .filter(|a| a.category.as_str().starts_with("markup.list.bullet."))
        .count();

    assert_eq!(bullet_count, 3, "Expected 3 bullet decorations for -, +, *");
}

#[test]
fn test_decorations_checkboxes() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("- [ ] unchecked\n- [x] checked\n");
    let decos = driver.decorations(0..100);

    let unchecked = decos
        .iter()
        .find(|a| a.category.as_str() == "markup.list.checkbox");
    assert!(unchecked.is_some(), "Expected unchecked checkbox decoration");

    let checked = decos
        .iter()
        .find(|a| a.category.as_str() == "markup.list.checkbox.checked");
    assert!(checked.is_some(), "Expected checked checkbox decoration");
}

#[test]
fn test_decorations_code_block() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("```\nsome code\n```\n");
    let decos = driver.decorations(0..100);

    let code_bg = decos
        .iter()
        .find(|a| a.category.as_str() == "markup.raw.block");
    assert!(
        code_bg.is_some(),
        "Expected code block decoration with markup.raw.block category"
    );
}

#[test]
fn test_decorations_blockquote_marker() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("> quoted text\n");
    let decos = driver.decorations(0..100);

    let bq = decos
        .iter()
        .find(|a| a.category.as_str() == "markup.quote.marker");
    assert!(bq.is_some(), "Expected blockquote marker decoration");
}

#[test]
fn test_decorations_horizontal_rule() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("---\n");
    let decos = driver.decorations(0..100);

    let hr = decos
        .iter()
        .find(|a| a.category.as_str() == "markup.horizontal_rule");
    assert!(hr.is_some(), "Expected horizontal rule decoration");
}

#[test]
fn test_decorations_empty_when_no_content() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("");
    let decos = driver.decorations(0..0);
    assert!(decos.is_empty(), "Empty document should have no decorations");
}

#[test]
fn test_decorations_partial_range() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    // H1 at byte 0..4, H2 at byte 6..
    driver.parse("# H1\n\n## H2\n");
    let decos = driver.decorations(0..5);

    // Should only get h1 decoration, not h2
    assert!(
        decos
            .iter()
            .any(|a| a.category.as_str() == "markup.heading.1"),
        "Should include h1 in range 0..5"
    );
    assert!(
        !decos
            .iter()
            .any(|a| a.category.as_str() == "markup.heading.2"),
        "Should NOT include h2 in range 0..5"
    );
}

#[test]
fn test_decorations_coexist_with_highlights() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("# Hello\n\n- item\n");
    let highlights = driver.highlights(0..100);
    let decos = driver.decorations(0..100);

    // Both should return data
    assert!(!highlights.is_empty(), "Should have highlights");
    assert!(!decos.is_empty(), "Should have decorations");

    // Decorations should have semantic categories (markup.*)
    assert!(
        decos
            .iter()
            .any(|a| a.category.as_str().starts_with("markup.")),
        "Decorations should have markup.* categories"
    );
}

#[test]
fn test_decoration_rules_count() {
    let rules = markdown_decoration_rules();
    assert_eq!(
        rules.len(),
        11,
        "Expected 11 decoration rules (6 headings + 2 checkboxes + code_block + blockquote + hr)"
    );
}

// ========================================================================
// Inline Decoration Tests
// ========================================================================

#[test]
fn test_inline_decoration_query_compiles() {
    let inline_lang: Language = tree_sitter_md::INLINE_LANGUAGE.into();
    assert!(
        Query::new(&inline_lang, MARKDOWN_INLINE_DECORATIONS_QUERY).is_ok(),
        "Inline decorations query should compile against INLINE_LANGUAGE"
    );
}

#[test]
fn test_inline_decoration_rules_count() {
    let rules = markdown_inline_decoration_rules();
    assert_eq!(
        rules.len(),
        6,
        "Expected 6 inline decoration rules (code_span.delimiter + code_span + emphasis + strong + strikethrough + link.destination)"
    );
}

#[test]
fn test_inline_decorations_emphasis() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("Hello *italic* world\n");
    let decos = driver.decorations(0..200);

    let emphasis = decos
        .iter()
        .find(|a| a.category.as_str() == "markup.italic");
    assert!(emphasis.is_some(), "Expected emphasis decoration for *italic*");
}

#[test]
fn test_inline_decorations_strong() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("Hello **bold** world\n");
    let decos = driver.decorations(0..200);

    let strong = decos.iter().find(|a| a.category.as_str() == "markup.bold");
    assert!(strong.is_some(), "Expected strong emphasis decoration for **bold**");
}

#[test]
fn test_inline_decorations_code_span() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("Use `code` here\n");
    let decos = driver.decorations(0..200);

    // Should have code span content annotation
    let code_bg = decos
        .iter()
        .find(|a| a.category.as_str() == "markup.raw.inline");
    assert!(code_bg.is_some(), "Expected inline code decoration");

    // Should have delimiter annotation
    let code_delim = decos
        .iter()
        .find(|a| a.category.as_str() == "markup.raw.delimiter");
    assert!(code_delim.is_some(), "Expected code span delimiter decoration");
}

#[test]
fn test_inline_decorations_strikethrough() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("~~strikethrough~~\n");
    let decos = driver.decorations(0..200);

    let strike = decos
        .iter()
        .find(|a| a.category.as_str() == "markup.strikethrough");
    assert!(strike.is_some(), "Expected strikethrough decoration");
}

#[test]
fn test_inline_decorations_link() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("[click here](https://example.com)\n");
    let decos = driver.decorations(0..200);

    let link_url = decos
        .iter()
        .find(|a| a.category.as_str() == "markup.link.url");
    assert!(link_url.is_some(), "Expected link URL decoration");
}

#[test]
fn test_inline_and_block_decorations_coexist() {
    let factory = MarkdownSyntaxFactory::new();
    let mut driver = factory.create("markdown").unwrap();

    driver.parse("# Heading with *emphasis*\n\n- bullet\n");
    let decos = driver.decorations(0..200);

    // Block decoration: heading marker
    let heading = decos
        .iter()
        .any(|a| a.category.as_str() == "markup.heading.1");
    assert!(heading, "Should have block-level heading decoration");

    // Inline decoration: emphasis
    let emphasis = decos.iter().any(|a| a.category.as_str() == "markup.italic");
    assert!(emphasis, "Should have inline emphasis decoration");

    // Block decoration: bullet
    let bullet = decos
        .iter()
        .any(|a| a.category.as_str().starts_with("markup.list.bullet."));
    assert!(bullet, "Should have block-level bullet decoration");
}

// ========================================================================
// Injection Highlighting POC (Markdown + Rust)
// ========================================================================

#[test]
#[cfg_attr(coverage_nightly, coverage(off))]
fn test_markdown_with_rust_injection_highlighting() {
    use {
        reovim_driver_syntax::SyntaxDriverFactory, reovim_module_treesitter_rust::RustSyntaxFactory,
    };

    let md_lang: Language = tree_sitter_md::LANGUAGE.into();
    let highlight_query = Arc::new(Query::new(&md_lang, MARKDOWN_HIGHLIGHTS_QUERY).unwrap());
    let injections_query = Arc::new(Query::new(&md_lang, MARKDOWN_INJECTIONS_QUERY).unwrap());

    // Create concrete Markdown driver with injections support
    let mut driver = TreeSitterDriver::with_queries(
        "markdown",
        &md_lang,
        highlight_query,
        None,
        Some(injections_query),
        None,
    )
    .unwrap();

    // Set Rust factory for dynamic injection child creation
    let factory: Arc<dyn SyntaxDriverFactory> = Arc::new(RustSyntaxFactory::new());
    driver.set_injection_factory(factory);

    // Parse Markdown with embedded Rust code block
    driver.parse("# Title\n\n```rust\nfn main() {}\n```\n");
    let highlights = driver.highlights(0..200);

    // Verify Markdown heading highlight exists
    assert!(
        highlights
            .iter()
            .any(|h| h.category.as_str().starts_with("markup.heading")),
        "Expected Markdown heading highlight"
    );

    // Verify Rust keyword highlight exists (from dynamic injection)
    assert!(
        highlights.iter().any(|h| h.category.as_str() == "keyword"
            || h.category.as_str() == "keyword.function"
            || h.category.as_str().starts_with("keyword")),
        "Expected Rust keyword highlight from dynamic injection, got: {highlights:?}"
    );
}

#[test]
fn test_markdown_with_multiple_language_injections() {
    use {
        reovim_driver_syntax::SyntaxDriverFactory, reovim_module_treesitter_rust::RustSyntaxFactory,
    };

    let md_lang: Language = tree_sitter_md::LANGUAGE.into();
    let highlight_query = Arc::new(Query::new(&md_lang, MARKDOWN_HIGHLIGHTS_QUERY).unwrap());
    let injections_query = Arc::new(Query::new(&md_lang, MARKDOWN_INJECTIONS_QUERY).unwrap());

    let mut driver = TreeSitterDriver::with_queries(
        "markdown",
        &md_lang,
        highlight_query,
        None,
        Some(injections_query),
        None,
    )
    .unwrap();

    // Only Rust is available — Python injection should be silently skipped
    let factory: Arc<dyn SyntaxDriverFactory> = Arc::new(RustSyntaxFactory::new());
    driver.set_injection_factory(factory);

    driver.parse("```rust\nfn main() {}\n```\n\n```python\nprint('hello')\n```\n");

    let injections = driver.injections();
    assert_eq!(injections.len(), 2);

    let highlights = driver.highlights(0..200);

    // Rust highlights should be present
    assert!(
        highlights
            .iter()
            .any(|h| h.category.as_str().starts_with("keyword")),
        "Expected Rust highlights from injection"
    );
}
