"""Extractor sanitization tests: every discovered URL is revalidated."""

from __future__ import annotations

from app.adapters.base import MediaCandidate, ParsedPage, SiteAdapter, VideoPageLink
from app.services.extractor import Extractor
from app.services.url_validator import NetworkGuard


def _guard() -> NetworkGuard:
    return NetworkGuard(["example.com"])


class FixedAdapter(SiteAdapter):
    name = "fixed"

    def __init__(self, parsed: ParsedPage) -> None:
        self._parsed = parsed

    def supports(self, url: str) -> bool:
        return True

    def parse(self, html: str, url: str) -> ParsedPage:
        return self._parsed


def test_discovered_urls_outside_allow_list_are_removed() -> None:
    parsed = ParsedPage(
        url="https://example.com/list",
        title="Title",
        caption="Caption",
        videos=[
            MediaCandidate(
                page_url="https://evil.test/page",
                source_url="https://evil.test/video.mp4",
                title="Bad",
                caption="Bad",
                media_url="https://evil.test/video.mp4",
            ),
            MediaCandidate(
                page_url="https://example.com/detail",
                source_url="https://example.com/detail",
                title="Only source",
                caption="",
                media_url=None,
            ),
            MediaCandidate(
                page_url="https://example.com/detail",
                source_url="https://example.com/detail-2",
                title="Allowed",
                caption="",
                media_url="https://cdn.example.com/video.mp4",
            ),
        ],
        video_pages=[
            VideoPageLink(url="https://evil.test/detail", title="Bad page"),
            VideoPageLink(url="https://example.com/detail", title="Good page"),
        ],
        next_page_url="https://evil.test/page2",
    )
    result = Extractor(_guard()).extract(FixedAdapter(parsed), "<html></html>", parsed.url)
    assert [video.title for video in result.videos] == ["Only source", "Allowed"]
    assert result.videos[0].media_url is None
    assert result.videos[0].source_url == "https://example.com/detail"
    assert result.videos[1].media_url == "https://cdn.example.com/video.mp4"
    assert result.videos[1].thumbnail_url is None
    assert [page.url for page in result.video_pages] == ["https://example.com/detail"]
    assert result.next_page_url is None


def test_discovered_urls_are_normalized_and_deduplicated() -> None:
    parsed = ParsedPage(
        url="https://example.com/list",
        title="  Title  ",
        caption="  Caption  ",
        videos=[
            MediaCandidate(
                page_url="https://EXAMPLE.com.:443/detail#x",
                source_url="https://example.com/video.mp4?x=1#frag",
                title="",
                caption="",
                media_url="https://example.com/video.mp4?x=1#frag",
                thumbnail_url="https://example.com/thumb.jpg#frag",
            ),
            MediaCandidate(
                page_url="https://example.com/detail",
                source_url="https://example.com/video.mp4?x=1",
                title="Duplicate",
                caption="Duplicate caption",
                media_url="https://example.com/video.mp4?x=1",
            ),
            MediaCandidate(
                page_url="https://example.com/detail",
                source_url="https://example.com/duplicate-source",
                title="Duplicate source",
                caption="",
                media_url="https://example.com/other.mp4",
            ),
            MediaCandidate(
                page_url="https://example.com/detail",
                source_url="https://example.com/duplicate-source",
                title="Duplicate source 2",
                caption="",
                media_url="https://example.com/other2.mp4",
            ),
        ],
        video_pages=[
            VideoPageLink(url="https://example.com/list#self", title="Self"),
            VideoPageLink(url="https://example.com/detail#one", title=" One "),
            VideoPageLink(url="https://example.com/detail", title="Duplicate"),
        ],
        next_page_url="https://example.com/list#same",
    )
    result = Extractor(_guard()).extract(FixedAdapter(parsed), "<html></html>", parsed.url)
    assert result.title == "Title"
    assert result.caption == "Caption"
    assert len(result.videos) == 2
    first = result.videos[0]
    assert first.source_url == "https://example.com/video.mp4?x=1"
    assert first.media_url == "https://example.com/video.mp4?x=1"
    assert first.thumbnail_url == "https://example.com/thumb.jpg"
    assert first.title == "Title"
    assert first.caption == "Caption"
    assert [page.url for page in result.video_pages] == ["https://example.com/detail"]
    assert result.video_pages[0].title == "One"
    assert result.next_page_url is None


def test_next_page_to_other_allowed_page_is_kept() -> None:
    parsed = ParsedPage(
        url="https://example.com/list",
        title="T",
        caption="C",
        next_page_url="https://example.com/list?page=2#frag",
    )
    result = Extractor(_guard()).extract(FixedAdapter(parsed), "<html></html>", parsed.url)
    assert result.next_page_url == "https://example.com/list?page=2"


def test_extractor_overrides_adapter_url_and_name() -> None:
    parsed = ParsedPage(url="https://evil.test/lying", title="", caption="")
    result = Extractor(_guard()).extract(FixedAdapter(parsed), "<html></html>", "https://example.com/real")
    assert result.url == "https://example.com/real"
    assert result.adapter_name == "fixed"
    assert result.title == "ویدئو"
    assert result.caption == "ویدئو"


def test_generic_adapter_output_survives_extractor() -> None:
    from app.adapters.generic_html import GenericHTMLAdapter

    html = """
    <html><head><title>Real</title></head><body>
      <video src="/v.mp4"></video>
      <script type="application/ld+json">
      {"@type":"VideoObject","name":"Other","url":"/detail"}
      </script>
    </body></html>
    """
    parsed = GenericHTMLAdapter().parse(html, "https://example.com/list")
    result = Extractor(_guard()).extract(
        GenericHTMLAdapter(), html, "https://example.com/list"
    )
    assert result.videos[0].media_url == "https://example.com/v.mp4"
    assert any(page.url == "https://example.com/detail" for page in result.video_pages)
    assert result.title == parsed.title


def test_invalid_candidate_fields_do_not_raise() -> None:
    parsed = ParsedPage(
        url="https://example.com/list",
        title="T",
        caption="C",
        videos=[
            MediaCandidate(
                page_url="",
                source_url="not a url",
                title="Bad",
                caption="",
                media_url="ftp://example.com/a.mp4",
            )
        ],
        video_pages=[VideoPageLink(url="data:text/html,x")],
        next_page_url="javascript:alert(1)",
    )
    result = Extractor(_guard()).extract(FixedAdapter(parsed), "", "https://example.com/list")
    assert result.videos == []
    assert result.video_pages == []
    assert result.next_page_url is None
