//! Adapter coverage fixture tests for Milestones 15 and 54-59.

use index_core::IndexNode;
use index_extract::{ExtractFormat, extract_document};
use index_transformer::{Transformer, state::Empty};

fn transform(html: &str) -> index_core::IndexDocument {
    Transformer::<Empty>::new()
        .fetched(html)
        .parse()
        .extract()
        .transform()
        .into_document()
}

fn has_code_block(nodes: &[IndexNode]) -> bool {
    nodes.iter().any(|node| match node {
        IndexNode::CodeBlock { code, .. } => !code.trim().is_empty(),
        IndexNode::Section { nodes, .. } => has_code_block(nodes),
        _ => false,
    })
}

#[test]
fn accepted_adapter_fixtures_emit_task_views() {
    for (fixture, expected_adapter, expected_title, expected_task) in [
        (
            include_str!("fixtures/adapters/gitlab-project.html"),
            "gitlab",
            "GitLab:",
            "Open issues and merge requests",
        ),
        (
            include_str!("fixtures/adapters/gitlab-issue.html"),
            "gitlab",
            "GitLab:",
            "Open issues and merge requests",
        ),
        (
            include_str!("fixtures/adapters/sourcehut-project.html"),
            "sourcehut",
            "SourceHut:",
            "Read mailing-list context",
        ),
        (
            include_str!("fixtures/adapters/forgejo-project.html"),
            "forge",
            "Forge:",
            "Open issues and pull requests",
        ),
        (
            include_str!("fixtures/adapters/gitea-issue.html"),
            "forge",
            "Forge:",
            "Open issues and pull requests",
        ),
        (
            include_str!("fixtures/adapters/read-the-docs.html"),
            "read-the-docs",
            "Read the Docs:",
            "Open table of contents",
        ),
        (
            include_str!("fixtures/adapters/mdn-reference.html"),
            "mdn",
            "MDN:",
            "Open browser compatibility notes",
        ),
        (
            include_str!("fixtures/adapters/hacker-news-front.html"),
            "hacker-news",
            "Hacker News:",
            "Open discussion threads",
        ),
        (
            include_str!("fixtures/adapters/hacker-news-item.html"),
            "hacker-news",
            "Hacker News:",
            "Read comment threads",
        ),
        (
            include_str!("fixtures/adapters/discourse-thread.html"),
            "discourse",
            "Discourse thread:",
            "Inspect replies",
        ),
        (
            include_str!("fixtures/adapters/stackexchange-question.html"),
            "stackoverflow",
            "StackExchange:",
            "Review accepted answer",
        ),
        (
            include_str!("fixtures/adapters/reddit-thread.html"),
            "reddit",
            "Reddit thread:",
            "Inspect nested comments",
        ),
        (
            include_str!("fixtures/adapters/slashdot-thread.html"),
            "slashdot",
            "Slashdot:",
            "Inspect comment thread",
        ),
        (
            include_str!("fixtures/adapters/xenforo-thread.html"),
            "forum-xenforo",
            "Forum thread:",
            "Inspect quote/reply chain",
        ),
        (
            include_str!("fixtures/adapters/legacy-forum-thread.html"),
            "forum-legacy",
            "Legacy forum thread:",
            "Inspect quotes/code blocks",
        ),
        (
            include_str!("fixtures/adapters/arxiv-abstract.html"),
            "arxiv",
            "arXiv abstract:",
            "Open PDF or source",
        ),
        (
            include_str!("fixtures/adapters/internet-archive-item.html"),
            "internet-archive",
            "Internet Archive item:",
            "Open available files",
        ),
    ] {
        let document = transform(fixture);

        assert_eq!(
            document.metadata.adapter_id.as_ref().map(|id| id.as_str()),
            Some(expected_adapter)
        );
        assert!(document.title.starts_with(expected_title));
        assert!(document.nodes.iter().any(
            |node| matches!(node, IndexNode::List { items, .. } if items.iter().any(|item| item == expected_task))
        ));
    }
}

#[test]
fn compatibility_pack_fixtures_cover_major_families() {
    for (fixture, expected_adapter, expected_task) in [
        (
            include_str!("fixtures/adapters/family-forum.html"),
            "family-pack.forums",
            "Inspect pagination and replies",
        ),
        (
            include_str!("fixtures/adapters/family-qa.html"),
            "family-pack.qa",
            "Inspect answer ranking",
        ),
        (
            include_str!("fixtures/adapters/family-docs.html"),
            "family-pack.docs",
            "Inspect code examples",
        ),
        (
            include_str!("fixtures/adapters/family-news.html"),
            "family-pack.news-media",
            "Open citations and sources",
        ),
        (
            include_str!("fixtures/adapters/family-portal.html"),
            "family-pack.portal",
            "Open primary categories",
        ),
        (
            include_str!("fixtures/adapters/family-app-shell.html"),
            "family-pack.app-shell",
            "Open primary actions and settings",
        ),
        (
            include_str!("fixtures/adapters/family-commerce-cards.html"),
            "family-pack.commerce-cards",
            "Open product detail links",
        ),
        (
            include_str!("fixtures/adapters/family-mixed-media.html"),
            "family-pack.mixed-media",
            "Open video/audio/gallery entries",
        ),
    ] {
        let document = transform(fixture);
        assert_eq!(
            document.metadata.adapter_id.as_ref().map(|id| id.as_str()),
            Some(expected_adapter)
        );
        assert!(document.nodes.iter().any(
            |node| matches!(node, IndexNode::List { items, .. } if items.iter().any(|item| item == expected_task))
        ));
    }
}

#[test]
fn adapter_views_have_stable_extraction_snapshots() {
    let document = transform(include_str!(
        "fixtures/adapters/stackexchange-question.html"
    ));
    let markdown = extract_document(&document, ExtractFormat::Markdown);
    let json = extract_document(&document, ExtractFormat::Json);

    assert!(markdown.contains("# StackExchange: How can I preserve terminal forms?"));
    assert!(markdown.contains("Family: StackExchange | Intent: thread-page"));
    assert!(json.contains("\"adapter_id\": \"stackoverflow\""));
    assert!(json.contains("\"title\": \"Thread\""));
    assert!(json.contains("\"type\": \"list\""));
}

#[test]
fn uncertain_adapter_detection_falls_back_to_generic_transformer() {
    let document = transform(
        r#"
        <html>
          <head><link rel="canonical" href="https://example.net/t/not-discourse"></head>
          <main><h1>Plain thread shape</h1><p>Readable fallback body.</p></main>
        </html>
        "#,
    );

    assert_eq!(document.metadata.adapter_id, None);
    assert!(document.nodes.iter().any(
        |node| matches!(node, IndexNode::Paragraph(text) if text == "Readable fallback body.")
    ));
}

#[test]
fn hacker_news_adapter_preserves_form_actions_and_drops_layout_table() {
    let document = transform(include_str!("fixtures/adapters/hacker-news-front.html"));

    assert_eq!(
        document.metadata.adapter_id.as_ref().map(|id| id.as_str()),
        Some("hacker-news")
    );
    assert!(
        !document
            .nodes
            .iter()
            .any(|node| matches!(node, IndexNode::Table { .. }))
    );
    assert!(
        document
            .nodes
            .iter()
            .any(|node| matches!(node, IndexNode::Form(form) if form.action.ends_with("search")))
    );
}

#[test]
fn reddit_script_gated_fixture_emits_actionable_diagnostic() {
    let document = transform(include_str!("fixtures/adapters/reddit-script-gated.html"));
    let markdown = extract_document(&document, ExtractFormat::Markdown);

    assert_eq!(
        document.metadata.adapter_id.as_ref().map(|id| id.as_str()),
        Some("reddit")
    );
    assert!(markdown.contains("Likely cause"));
    assert!(markdown.contains("forum-blocked.capture"));
}

#[test]
fn forum_family_fixtures_preserve_code_quote_and_pagination_nodes() {
    for fixture in [
        include_str!("fixtures/adapters/reddit-thread.html"),
        include_str!("fixtures/adapters/xenforo-thread.html"),
        include_str!("fixtures/adapters/legacy-forum-thread.html"),
    ] {
        let document = transform(fixture);
        assert!(has_code_block(&document.nodes));
        assert!(document.nodes.iter().any(
            |node| matches!(node, IndexNode::Section { title: Some(title), .. } if title == "Pagination")
        ));
    }
}

#[test]
fn unknown_forum_family_uses_generic_fallback() {
    let document = transform(
        r#"
        <html>
          <head><link rel="canonical" href="https://unknown-board.example/threads/42"></head>
          <main><h1>Unknown board thread</h1><p>Readable generic body.</p></main>
        </html>
        "#,
    );

    assert_eq!(document.metadata.adapter_id, None);
    assert!(document.nodes.iter().any(
        |node| matches!(node, IndexNode::Paragraph(text) if text == "Readable generic body.")
    ));
}

#[test]
fn malformed_legacy_forum_fixture_keeps_readable_output() {
    let document = transform(include_str!("fixtures/legacy-malformed-board.html"));
    let markdown = extract_document(&document, ExtractFormat::Markdown);

    assert_eq!(
        document.metadata.adapter_id.as_ref().map(|id| id.as_str()),
        Some("forum-legacy")
    );
    assert!(markdown.contains("Malformed sample"));
    assert!(markdown.contains("Recover parser output"));
    assert!(markdown.contains("Next"));
}

#[test]
fn top100_representative_families_have_deterministic_paths() {
    for (fixture, expected_adapter, expected_text, expected_section) in [
        (
            include_str!("fixtures/adapters/top100-google-search.html"),
            Some("top100.baseline"),
            "Family: Search Portal | Intent: search-results",
            "main: Results",
        ),
        (
            include_str!("fixtures/adapters/top100-search-portal.html"),
            Some("top100.baseline"),
            "Family: Search Portal | Intent: portal-landing",
            "Scan ranked results",
        ),
        (
            include_str!("fixtures/adapters/top100-news-yahoo-article.html"),
            Some("top100.baseline"),
            "Family: Search Portal | Intent: article-or-reference",
            "Scan ranked results",
        ),
        (
            include_str!("fixtures/adapters/top100-msn-portal.html"),
            Some("top100.baseline"),
            "Family: Search Portal | Intent: portal-landing",
            "Scan ranked results",
        ),
        (
            include_str!("fixtures/adapters/top100-baidu-search.html"),
            Some("top100.baseline"),
            "Family: Search Portal | Intent: search-results",
            "main: Results",
        ),
        (
            include_str!("fixtures/adapters/top100-naver-search.html"),
            Some("top100.baseline"),
            "Family: Search Portal | Intent: search-results",
            "main: Results",
        ),
        (
            include_str!("fixtures/adapters/top100-yaru-search.html"),
            Some("top100.baseline"),
            "Family: Search Portal | Intent: search-results",
            "main: Results",
        ),
        (
            include_str!("fixtures/adapters/top100-yahoo-search.html"),
            Some("top100.baseline"),
            "Family: Search Portal | Intent: search-results",
            "main: Results",
        ),
        (
            include_str!("fixtures/adapters/top100-yandex-search.html"),
            Some("top100.baseline"),
            "Family: Search Portal | Intent: search-results",
            "main: Results",
        ),
        (
            include_str!("fixtures/adapters/top100-indeed-search.html"),
            Some("top100.baseline"),
            "Family: Services and Utility | Intent: search-results",
            "main: Results",
        ),
        (
            include_str!("fixtures/adapters/top100-indiatimes-portal.html"),
            Some("top100.baseline"),
            "Family: Knowledge Reference | Intent: portal-landing",
            "Read primary article content",
        ),
        (
            include_str!("fixtures/adapters/top100-docomo-portal.html"),
            Some("top100.baseline"),
            "Family: Services and Utility | Intent: portal-landing",
            "Read public utility or help content",
        ),
        (
            include_str!("fixtures/adapters/top100-adobe-portal.html"),
            Some("top100.baseline"),
            "Family: Services and Utility | Intent: portal-landing",
            "Read public utility or help content",
        ),
        (
            include_str!("fixtures/adapters/top100-apple-portal.html"),
            Some("top100.baseline"),
            "Family: Services and Utility | Intent: portal-landing",
            "Read public utility or help content",
        ),
        (
            include_str!("fixtures/adapters/top100-microsoft-portal.html"),
            Some("top100.baseline"),
            "Family: Services and Utility | Intent: portal-landing",
            "Read public utility or help content",
        ),
        (
            include_str!("fixtures/adapters/top100-samsung-portal.html"),
            Some("top100.baseline"),
            "Family: Services and Utility | Intent: portal-landing",
            "Read public utility or help content",
        ),
        (
            include_str!("fixtures/adapters/top100-usps-portal.html"),
            Some("top100.baseline"),
            "Family: Services and Utility | Intent: portal-landing",
            "Read public utility or help content",
        ),
        (
            include_str!("fixtures/adapters/top100-canva-app-shell.html"),
            Some("top100.baseline"),
            "Family: Services and Utility | Intent: app-shell",
            "Read public utility or help content",
        ),
        (
            include_str!("fixtures/adapters/top100-zoom-app-shell.html"),
            Some("top100.baseline"),
            "Family: Services and Utility | Intent: app-shell",
            "Read public utility or help content",
        ),
        (
            include_str!("fixtures/adapters/top100-telegram-portal.html"),
            Some("top100.baseline"),
            "Family: Social Community | Intent: portal-landing",
            "Read post/thread context",
        ),
        (
            include_str!("fixtures/adapters/top100-dzen-portal.html"),
            Some("top100.baseline"),
            "Family: Knowledge Reference | Intent: portal-landing",
            "Read primary article content",
        ),
        (
            include_str!("fixtures/adapters/top100-espn-portal.html"),
            Some("top100.baseline"),
            "Family: Knowledge Reference | Intent: portal-landing",
            "Read primary article content",
        ),
        (
            include_str!("fixtures/adapters/top100-globo-portal.html"),
            Some("top100.baseline"),
            "Family: Knowledge Reference | Intent: portal-landing",
            "Read primary article content",
        ),
        (
            include_str!("fixtures/adapters/top100-bbc-article.html"),
            Some("top100.baseline"),
            "Family: Knowledge Reference | Intent: article-or-reference",
            "Read primary article content",
        ),
        (
            include_str!("fixtures/adapters/top100-bbc-uk-article.html"),
            Some("top100.baseline"),
            "Family: Knowledge Reference | Intent: article-or-reference",
            "Read primary article content",
        ),
        (
            include_str!("fixtures/adapters/top100-cnn-article.html"),
            Some("top100.baseline"),
            "Family: Knowledge Reference | Intent: article-or-reference",
            "Read primary article content",
        ),
        (
            include_str!("fixtures/adapters/top100-fandom-article.html"),
            Some("top100.baseline"),
            "Family: Knowledge Reference | Intent: article-or-reference",
            "Read primary article content",
        ),
        (
            include_str!("fixtures/adapters/top100-namu-article.html"),
            None,
            "Main summary paragraph for the article subject.",
            "# Sample",
        ),
        (
            include_str!("fixtures/adapters/top100-nytimes-article.html"),
            Some("top100.baseline"),
            "Family: Knowledge Reference | Intent: article-or-reference",
            "Read primary article content",
        ),
        (
            include_str!("fixtures/adapters/top100-theguardian-article.html"),
            Some("top100.baseline"),
            "Family: Knowledge Reference | Intent: article-or-reference",
            "Read primary article content",
        ),
        (
            include_str!("fixtures/adapters/top100-weather-article.html"),
            Some("top100.baseline"),
            "Family: Knowledge Reference | Intent: article-or-reference",
            "Read primary article content",
        ),
        (
            include_str!("fixtures/adapters/top100-youtube-watch.html"),
            Some("top100.baseline"),
            "Family: Media and Streaming | Intent: video-hub",
            "main: Media Metadata",
        ),
        (
            include_str!("fixtures/adapters/top100-bilibili-watch.html"),
            Some("top100.baseline"),
            "Family: Media and Streaming | Intent: video-hub",
            "main: Media Metadata",
        ),
        (
            include_str!("fixtures/adapters/top100-imdb-video.html"),
            Some("top100.baseline"),
            "Family: Media and Streaming | Intent: video-hub",
            "main: Media Metadata",
        ),
        (
            include_str!("fixtures/adapters/top100-music-youtube-watch.html"),
            Some("top100.baseline"),
            "Family: Media and Streaming | Intent: video-hub",
            "main: Media Metadata",
        ),
        (
            include_str!("fixtures/adapters/top100-rutube-video.html"),
            Some("top100.baseline"),
            "Family: Media and Streaming | Intent: video-hub",
            "main: Media Metadata",
        ),
        (
            include_str!("fixtures/adapters/top100-spotify-track.html"),
            Some("top100.baseline"),
            "Family: Media and Streaming | Intent: video-hub",
            "main: Media Metadata",
        ),
        (
            include_str!("fixtures/adapters/top100-twitch-video.html"),
            Some("top100.baseline"),
            "Family: Media and Streaming | Intent: video-hub",
            "main: Media Metadata",
        ),
        (
            include_str!("fixtures/adapters/top100-amazon-listing.html"),
            Some("top100.baseline"),
            "Family: Commerce and Marketplace | Intent: marketplace-listing",
            "main: Listings",
        ),
        (
            include_str!("fixtures/adapters/top100-amazon-jp-listing.html"),
            Some("top100.baseline"),
            "Family: Commerce and Marketplace | Intent: marketplace-listing",
            "main: Listings",
        ),
        (
            include_str!("fixtures/adapters/top100-amazon-uk-listing.html"),
            Some("top100.baseline"),
            "Family: Commerce and Marketplace | Intent: marketplace-listing",
            "main: Listings",
        ),
        (
            include_str!("fixtures/adapters/top100-amazon-de-listing.html"),
            Some("top100.baseline"),
            "Family: Commerce and Marketplace | Intent: marketplace-listing",
            "main: Listings",
        ),
        (
            include_str!("fixtures/adapters/top100-amazon-in-listing.html"),
            Some("top100.baseline"),
            "Family: Commerce and Marketplace | Intent: marketplace-listing",
            "main: Listings",
        ),
        (
            include_str!("fixtures/adapters/top100-booking-listing.html"),
            Some("top100.baseline"),
            "Family: Commerce and Marketplace | Intent: marketplace-listing",
            "main: Listings",
        ),
        (
            include_str!("fixtures/adapters/top100-aliexpress-listing.html"),
            Some("top100.baseline"),
            "Family: Commerce and Marketplace | Intent: marketplace-listing",
            "main: Listings",
        ),
        (
            include_str!("fixtures/adapters/top100-rakuten-listing.html"),
            Some("top100.baseline"),
            "Family: Commerce and Marketplace | Intent: marketplace-listing",
            "main: Listings",
        ),
        (
            include_str!("fixtures/adapters/top100-ebay-listing.html"),
            Some("top100.baseline"),
            "Family: Commerce and Marketplace | Intent: marketplace-listing",
            "main: Listings",
        ),
        (
            include_str!("fixtures/adapters/top100-etsy-listing.html"),
            Some("top100.baseline"),
            "Family: Commerce and Marketplace | Intent: marketplace-listing",
            "main: Listings",
        ),
        (
            include_str!("fixtures/adapters/top100-ozon-listing.html"),
            Some("top100.baseline"),
            "Family: Commerce and Marketplace | Intent: marketplace-listing",
            "main: Listings",
        ),
        (
            include_str!("fixtures/adapters/top100-shein-listing.html"),
            Some("top100.baseline"),
            "Family: Commerce and Marketplace | Intent: marketplace-listing",
            "main: Listings",
        ),
        (
            include_str!("fixtures/adapters/top100-temu-listing.html"),
            Some("top100.baseline"),
            "Family: Commerce and Marketplace | Intent: marketplace-listing",
            "main: Listings",
        ),
        (
            include_str!("fixtures/adapters/top100-walmart-listing.html"),
            Some("top100.baseline"),
            "Family: Commerce and Marketplace | Intent: marketplace-listing",
            "main: Listings",
        ),
        (
            include_str!("fixtures/adapters/top100-wildberries-listing.html"),
            Some("top100.baseline"),
            "Family: Commerce and Marketplace | Intent: marketplace-listing",
            "main: Listings",
        ),
        (
            include_str!("fixtures/adapters/top100-zillow-listing.html"),
            Some("top100.baseline"),
            "Family: Commerce and Marketplace | Intent: marketplace-listing",
            "main: Listings",
        ),
        (
            include_str!("fixtures/adapters/top100-office-auth.html"),
            Some("top100.baseline"),
            "auth-wall",
            "## Suggested commands",
        ),
        (
            include_str!("fixtures/adapters/top100-x-blocked.html"),
            Some("top100.baseline"),
            "script-gate",
            "## Suggested commands",
        ),
    ] {
        let document = transform(fixture);
        let markdown = extract_document(&document, ExtractFormat::Markdown);
        assert_eq!(
            document.metadata.adapter_id.as_ref().map(|id| id.as_str()),
            expected_adapter
        );
        assert!(markdown.contains(expected_text));
        assert!(
            markdown.contains(expected_section),
            "expected section `{expected_section}` in markdown:\n{markdown}"
        );
    }
}
