import os
import pytest

try:
    from bs4 import BeautifulSoup
except Exception:  # pragma: no cover - optional in local env
    BeautifulSoup = None

from addon.plugins import serienstream_plugin as sp


pytestmark = pytest.mark.skipif(BeautifulSoup is None, reason="bs4 not available")


def _soup(html: str):
    return BeautifulSoup(html, "html.parser")


def test_search_series_api_first(monkeypatch):
    """search_series() kombiniert API-Treffer mit Katalog-Cache (ohne Duplikate)."""
    monkeypatch.setattr(sp, "_get_base_url", lambda: "https://s.to")
    monkeypatch.setattr(sp, "_search_series_api", lambda q: [
        sp.SeriesResult(title="Star Trek", description="", url="https://s.to/serie/star-trek"),
    ])
    # Katalog-Cache: eine bekannte + eine neue URL
    cache_items = [
        sp.SeriesResult(title="Star Trek", description="", url="https://s.to/serie/star-trek"),  # Duplikat
        sp.SeriesResult(title="Star Trek: Academy", description="", url="https://s.to/serie/star-trek-academy"),
    ]
    monkeypatch.setattr(sp, "_load_catalog_index_from_cache", lambda: cache_items)
    results = sp.search_series("trek")
    titles = [r.title for r in results]
    # API-Treffer zuerst, Duplikate (gleiche URL) werden entfernt
    assert titles[0] == "Star Trek"
    assert "Star Trek: Academy" in titles
    assert titles.count("Star Trek") == 1


def test_search_series_falls_back_to_catalog_cache(monkeypatch):
    """Wenn API und Server-Suche leer sind, wird der Katalog-Cache als Fallback genutzt."""
    monkeypatch.setattr(sp, "_get_base_url", lambda: "https://s.to")
    # API und Server-Suche liefern nichts
    monkeypatch.setattr(sp, "_search_series_api", lambda q: [])
    monkeypatch.setattr(sp, "_search_series_server", lambda q: [])
    # Katalog-Cache mit Testdaten fuellen
    cache_items = [
        sp.SeriesResult(title="Der Hund", description="", url="https://s.to/serie/der-hund"),
        sp.SeriesResult(title="Hundeleben", description="", url="https://s.to/serie/hundeleben"),
    ]
    monkeypatch.setattr(sp, "_load_catalog_index_from_cache", lambda: cache_items)
    results = sp.search_series("hund")
    titles = [r.title for r in results]
    # Nur Ganzwort-Treffer (nicht Hundeleben)
    assert titles == ["Der Hund"]


def test_extract_season_links():
    html = """
    <ul class='nav list-items-nav'>
      <a data-season-pill='1' href='/serie/x/staffel-1'>1</a>
      <a data-season-pill='2' href='/serie/x/staffel-2'>2</a>
      <a data-season-pill='1' href='/serie/x/staffel-1/episode-1'>skip</a>
    </ul>
    """
    seasons = sp._extract_season_links(_soup(html))
    assert seasons == [(1, "https://s.to/serie/x/staffel-1"), (2, "https://s.to/serie/x/staffel-2")]


def test_extract_episodes_skips_upcoming_and_tba():
    html = """
    <table class='episode-table'>
      <tbody>
        <tr class='episode-row' onclick="window.location='https://s.to/serie/x/staffel-1/episode-1'">
          <th class='episode-number-cell'>1</th>
          <td><strong class='episode-title-ger'>Ep1</strong></td>
          <td class='episode-watch-cell'><img alt='VOE'></td>
        </tr>
        <tr class='episode-row upcoming' onclick="window.location='https://s.to/serie/x/staffel-1/episode-2'">
          <th class='episode-number-cell'>2</th>
          <td>
            <strong class='episode-title-ger'></strong>
            <span class='badge badge-upcoming'>DEMNÄCHST</span>
          </td>
          <td class='episode-watch-cell'>— TBA —</td>
        </tr>
      </tbody>
    </table>
    """
    episodes = sp._extract_episodes(_soup(html))
    assert [e.number for e in episodes] == [1]


def test_fetch_episode_hoster_names(monkeypatch):
    html = """
    <button class='link-box' data-provider-name='VOE' data-play-url='/redirect/voe'></button>
    <button class='link-box' data-provider-name='Vidoza' data-play-url='/redirect/vidoza'></button>
    """

    def fake_get_soup(url, session=None):
        return _soup(html)

    monkeypatch.setattr(sp, "_get_soup", fake_get_soup)
    monkeypatch.setattr(sp, "_get_base_url", lambda: "https://s.to")
    names = sp.fetch_episode_hoster_names("/serie/x/staffel-1/episode-1")
    assert names == ["VOE", "Vidoza"]


def test_fetch_episode_stream_link_prefers_requested_hoster(monkeypatch):
    html = """
    <button class='link-box' data-provider-name='VOE' data-play-url='/redirect/voe'></button>
    <button class='link-box' data-provider-name='Vidoza' data-play-url='/redirect/vidoza'></button>
    """

    def fake_get_soup(url, session=None):
        return _soup(html)

    monkeypatch.setattr(sp, "_get_soup", fake_get_soup)
    monkeypatch.setattr(sp, "_get_base_url", lambda: "https://s.to")
    link = sp.fetch_episode_stream_link("/serie/x/staffel-1/episode-1", preferred_hosters=["vidoza"])
    assert link == "https://s.to/redirect/vidoza"


def test_extract_latest_episodes():
    html = """
    <a class='latest-episode-row' href='/serie/x/staffel-1/episode-2'>
      <span class='ep-title' title='Show X'>Show X</span>
      <span class='ep-season'>S 1</span>
      <span class='ep-episode'>E 2</span>
      <span class='ep-time'>Heute</span>
    </a>
    """
    episodes = sp._extract_latest_episodes(_soup(html))
    assert len(episodes) == 1
    assert episodes[0].series_title == "Show X"
    assert episodes[0].season == 1
    assert episodes[0].episode == 2


def test_episode_url_for_uses_episode_cache(monkeypatch):
    plugin = sp.SerienstreamPlugin()
    info = sp.EpisodeInfo(
        number=2,
        title="Folge 2",
        original_title="",
        url="https://s.to/serie/x/staffel-1/episode-2",
    )
    plugin._episode_label_cache[("Show X", "Staffel 1")] = {"Episode 2: Folge 2": info}

    called = {"lookup": False}

    def _fail_lookup(*_args, **_kwargs):
        called["lookup"] = True
        return None

    monkeypatch.setattr(plugin, "_lookup_episode", _fail_lookup)

    url = plugin.episode_url_for("Show X", "Staffel 1", "Episode 2: Folge 2")
    assert url == "https://s.to/serie/x/staffel-1/episode-2"
    assert called["lookup"] is False


def test_parse_series_catalog_groups_and_entries():
    html = """
    <div class='background-1'><h3>Genre A</h3></div>
    <ul class='series-list'>
      <li class='series-item' data-search='desc a'>
        <a href='/serie/a'>A</a>
      </li>
    </ul>
    <div class='background-1'><h3>Genre B</h3></div>
    <ul class='series-list'>
      <li class='series-item' data-search='desc b'>
        <a href='/serie/b'>B</a>
      </li>
    </ul>
    """
    catalog = sp.parse_series_catalog(_soup(html))
    assert list(catalog.keys()) == ["Genre A", "Genre B"]
    assert [e.title for e in catalog["Genre A"]] == ["A"]
    assert [e.title for e in catalog["Genre B"]] == ["B"]


def test_titles_for_genre_from_catalog(monkeypatch):
    html = """
    <div class='background-1'><h3>Drama</h3></div>
    <ul class='series-list'>
      <li class='series-item' data-search='desc'>
        <a href='/serie/drama-1'>Drama 1</a>
      </li>
    </ul>
    """
    monkeypatch.setattr(sp, "_get_soup_simple", lambda url: _soup(html))
    monkeypatch.setattr(sp, "_get_base_url", lambda: "https://s.to")
    plugin = sp.SerienstreamPlugin()
    titles = plugin.titles_for_genre("Drama")
    assert titles == ["Drama 1"]


def test_popular_series_parsing(monkeypatch):
    html = """
    <div class='mb-5'>
      <h2>Meistgesehen</h2>
      <a class='show-card' href='/serie/popular-1'>
        <img alt='Popular 1' src='x.jpg'>
      </a>
      <a class='show-card' href='/serie/popular-2'>
        <img alt='Popular 2' src='y.jpg'>
      </a>
    </div>
    """
    monkeypatch.setattr(sp, "_get_soup_simple", lambda url: _soup(html))
    monkeypatch.setattr(sp, "_get_base_url", lambda: "https://s.to")
    plugin = sp.SerienstreamPlugin()
    titles = plugin.popular_series()
    assert titles == ["Popular 1", "Popular 2"]


@pytest.mark.live
def test_live_staffel_page_skips_upcoming():
    if not os.getenv("LIVE_TESTS"):
        pytest.skip("LIVE_TESTS not set")
    url = "https://s.to/serie/star-trek-starfleet-academy/staffel-1"
    soup = sp._get_soup_simple(url)
    rows = soup.select("table.episode-table tbody tr.episode-row")
    upcoming_rows = [row for row in rows if "upcoming" in (row.get("class") or [])]
    episodes = sp._extract_episodes(soup)
    assert len(episodes) == len(rows) - len(upcoming_rows)


@pytest.mark.live
def test_live_genres_and_titles():
    if not os.getenv("LIVE_TESTS"):
        pytest.skip("LIVE_TESTS not set")
    plugin = sp.SerienstreamPlugin()
    genres = plugin.genres()
    assert isinstance(genres, list) and genres
    sample = genres[0]
    titles = plugin.titles_for_genre(sample)
    assert isinstance(titles, list)
