"""Media discovery from standard HTML, Open Graph, JSON-LD and microdata."""

from __future__ import annotations

from bs4 import BeautifulSoup

from app.adapters.generic_html import GenericHTMLAdapter
from app.adapters.media_adapter import MediaAdapter, parse_duration
from app.services.caption_parser import CaptionResult


def _caption(title: str = "Page title", caption: str = "Page caption") -> CaptionResult:
    return CaptionResult(title=title, caption=caption, source="test")


def test_parse_duration_variants() -> None:
    assert parse_duration(12) == 12.0
    assert parse_duration(12.5) == 12.5
    assert parse_duration("42") == 42.0
    assert parse_duration("PT1H2M3.5S") == 3723.5
    assert parse_duration("P1DT2H") == 93600.0
    assert parse_duration(None) is None
    assert parse_duration(0) is None
    assert parse_duration("00:10") is None
    assert parse_duration("P0D") is None


def test_video_and_source_tags_are_extracted() -> None:
    html = """
    <html><head><title>Gallery</title></head><body>
      <div>
        <h2>First clip</h2>
        <video src="/media/first.mp4" poster="/thumb.jpg" duration="PT1M2S">
          <source src="/media/first.webm" type="video/webm">
        </video>
      </div>
    </body></html>
    """
    parsed = GenericHTMLAdapter().parse(html, "https://example.com/gallery")
    assert len(parsed.videos) == 2
    by_url = {video.media_url: video for video in parsed.videos}
    mp4 = by_url["https://example.com/media/first.mp4"]
    webm = by_url["https://example.com/media/first.webm"]
    assert mp4.media_type == "video/mp4"
    assert mp4.thumbnail_url == "https://example.com/thumb.jpg"
    assert mp4.duration_seconds == 62.0
    assert mp4.title == "First clip"
    assert webm.media_type == "video/webm"
    assert mp4.source_url == mp4.media_url
    assert webm.source_url == webm.media_url


def test_open_graph_video_without_extension_uses_page_identity() -> None:
    html = """
    <html><head>
      <title>An OG page</title>
      <meta property="og:description" content="OG caption">
      <meta property="og:video:secure_url" content="/player/stream">
      <meta property="og:video:type" content="video/mp4">
      <meta property="og:image" content="/poster.jpg">
    </head></html>
    """
    parsed = GenericHTMLAdapter().parse(html, "https://example.com/watch/1")
    assert len(parsed.videos) == 1
    video = parsed.videos[0]
    assert video.media_url == "https://example.com/player/stream"
    assert video.source_url == "https://example.com/watch/1"
    assert video.media_type == "video/mp4"
    assert video.thumbnail_url == "https://example.com/poster.jpg"


def test_jsonld_videoobject_is_extracted() -> None:
    html = """
    <html><body>
      <script type="application/ld+json">
      {"@context":"https://schema.org","@type":"VideoObject",
       "name":"JSON clip","description":"JSON caption",
       "contentUrl":"https://cdn.example.com/v/1.mp4",
       "thumbnailUrl":"https://cdn.example.com/t/1.jpg",
       "duration":"PT2M5S","contentSize":"12345",
       "url":"https://example.com/videos/1"}
      </script>
    </body></html>
    """
    parsed = GenericHTMLAdapter().parse(html, "https://example.com/videos/1")
    assert len(parsed.videos) == 1
    video = parsed.videos[0]
    assert video.title == "JSON clip"
    assert video.caption == "JSON caption"
    assert video.media_url == "https://cdn.example.com/v/1.mp4"
    assert video.source_url == "https://example.com/videos/1"
    assert video.thumbnail_url == "https://cdn.example.com/t/1.jpg"
    assert video.duration_seconds == 125.0
    assert video.file_size == 12345


def test_jsonld_videoobject_without_content_becomes_detail_page() -> None:
    html = """
    <html><body>
      <script type="application/ld+json">
      {"@type":"VideoObject","name":"Detail title","url":"/videos/detail-1",
       "description":"Detail description"}
      </script>
    </body></html>
    """
    parsed = GenericHTMLAdapter().parse(html, "https://example.com/list")
    assert parsed.videos == []
    assert len(parsed.video_pages) == 1
    assert parsed.video_pages[0].url == "https://example.com/videos/detail-1"
    assert parsed.video_pages[0].title == "Detail title"
    assert parsed.video_pages[0].source == "jsonld"


def test_direct_media_links_are_recognized() -> None:
    html = """
    <html><body>
      <div><a href="/files/movie.mp4">Movie file</a></div>
      <a href="/files/clip.m3u8">HLS</a>
      <a href="/files/notes.txt">Notes</a>
      <a href="javascript:alert(1)">Bad</a>
      <a href="data:video/mp4;base64,AAAA">Data</a>
    </body></html>
    """
    parsed = GenericHTMLAdapter().parse(html, "https://example.com/page")
    urls = {video.media_url for video in parsed.videos}
    assert "https://example.com/files/movie.mp4" in urls
    assert "https://example.com/files/clip.m3u8" in urls
    assert "https://example.com/files/notes.txt" not in urls
    movie = next(v for v in parsed.videos if v.media_url and v.media_url.endswith(".mp4"))
    assert movie.title == "Movie file"
    assert movie.source_url == movie.media_url
    hls = next(v for v in parsed.videos if v.media_url and v.media_url.endswith(".m3u8"))
    assert hls.media_type == "application/vnd.apple.mpegurl"


def test_adapter_video_page_selectors() -> None:
    class CardAdapter(GenericHTMLAdapter):
        name = "cards"
        video_page_selectors = (".card a",)

    html = """
    <html><body>
      <div class="card">
        <h3>Card heading</h3>
        <a href="/detail/one">Open</a>
        <p>This card description is long enough to be useful.</p>
      </div>
    </body></html>
    """
    parsed = CardAdapter().parse(html, "https://example.com/list")
    assert parsed.videos == []
    assert len(parsed.video_pages) == 1
    page = parsed.video_pages[0]
    assert page.url == "https://example.com/detail/one"
    assert page.title == "Card heading"
    assert "long enough" in page.caption


def test_microdata_videoobject() -> None:
    html = """
    <html><body>
      <div itemscope itemtype="https://schema.org/VideoObject">
        <meta itemprop="name" content="Microdata clip">
        <meta itemprop="description" content="Microdata caption">
        <meta itemprop="contentUrl" content="/m/1.mp4">
      </div>
    </body></html>
    """
    parsed = GenericHTMLAdapter().parse(html, "https://example.com/micro")
    assert len(parsed.videos) == 1
    video = parsed.videos[0]
    assert video.title == "Microdata clip"
    assert video.caption == "Microdata caption"
    assert video.media_url == "https://example.com/m/1.mp4"


def test_duplicate_media_urls_are_collapsed() -> None:
    html = """
    <html><body>
      <video src="/same.mp4"></video>
      <a href="/same.mp4">Download</a>
      <meta property="og:video" content="/same.mp4">
    </body></html>
    """
    parsed = GenericHTMLAdapter().parse(html, "https://example.com/page")
    assert len(parsed.videos) == 1
    assert parsed.videos[0].media_url == "https://example.com/same.mp4"


def test_media_adapter_rejects_empty_and_non_http_sources() -> None:
    soup = BeautifulSoup(
        '<video src="file:///etc/passwd"></video><video src="javascript:alert(1)"></video>',
        "html.parser",
    )
    candidates, pages = MediaAdapter().extract(
        soup, "https://example.com/page", _caption()
    )
    assert candidates == []
    assert pages == []


def test_thumbnail_prefers_open_graph_image() -> None:
    html = """
    <html><head>
      <meta name="twitter:image" content="/twitter.jpg">
      <meta property="og:image" content="/og.jpg">
    </head><body>
      <video src="/v.mp4"></video>
    </body></html>
    """
    parsed = GenericHTMLAdapter().parse(html, "https://example.com/watch")
    assert parsed.videos[0].thumbnail_url == "https://example.com/og.jpg"
