from __future__ import annotations

import gzip
from pathlib import Path

import pytest

from worai.core import sitemap


class _Resp:
    def __init__(self, content: bytes, headers: dict[str, str] | None = None) -> None:
        self.content = content
        self.headers = headers or {}


class _Session:
    def __init__(self, response: _Resp | Exception) -> None:
        self._response = response

    def get(self, _url: str, timeout: float):
        assert timeout == 1.0
        if isinstance(self._response, Exception):
            raise self._response
        return self._response


def _urlset(*urls: str) -> bytes:
    body = "".join(f"<url><loc>{u}</loc></url>" for u in urls)
    return f"<urlset>{body}</urlset>".encode("utf-8")


def _index(*sitemaps: str) -> bytes:
    body = "".join(f"<sitemap><loc>{u}</loc></sitemap>" for u in sitemaps)
    return f"<sitemapindex>{body}</sitemapindex>".encode("utf-8")


def test_helpers_strip_decode_and_parse() -> None:
    assert sitemap._strip_ns("{x}urlset") == "urlset"
    assert sitemap._strip_ns("urlset") == "urlset"

    gz = gzip.compress(_urlset("https://example.com/a"))
    assert sitemap._decode_content("https://e.com/sitemap.xml.gz", _Resp(gz))
    assert sitemap._decode_content("https://e.com/sitemap.xml", _Resp(gz, {"content-type": "application/gzip"}))

    root_tag, locs = sitemap._parse_sitemap_xml(_urlset("https://example.com/a"))
    assert root_tag == "urlset"
    assert locs == ["https://example.com/a"]


def test_parse_sitemap_urls_from_local_index_and_file_scheme(tmp_path: Path) -> None:
    nested = tmp_path / "nested.xml"
    nested.write_bytes(_urlset("https://example.com/one", "https://example.com/two"))

    root = tmp_path / "root.xml"
    root.write_bytes(_index(str(nested)))

    assert sitemap.parse_sitemap_urls(str(root), session=_Session(_Resp(b"")), timeout=1.0) == [
        "https://example.com/one",
        "https://example.com/two",
    ]

    gz_file = tmp_path / "g.xml.gz"
    gz_file.write_bytes(gzip.compress(_urlset("https://example.com/gz")))
    assert sitemap.parse_sitemap_urls(f"file://{gz_file}", session=_Session(_Resp(b"")), timeout=1.0) == [
        "https://example.com/gz"
    ]


def test_parse_sitemap_urls_requests_browser_and_auto(monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr(sitemap, "_fetch_sitemap_requests", lambda *_a, **_k: _urlset("https://example.com/r"))
    urls = sitemap.parse_sitemap_urls("https://example.com/sitemap.xml", session=_Session(_Resp(b"")), timeout=1.0)
    assert urls == ["https://example.com/r"]

    monkeypatch.setattr(sitemap, "_fetch_sitemap_browser", lambda *_a, **_k: _urlset("https://example.com/b"))
    urls = sitemap.parse_sitemap_urls(
        "https://example.com/sitemap.xml",
        session=_Session(_Resp(b"")),
        timeout=1.0,
        fetch_mode="browser",
    )
    assert urls == ["https://example.com/b"]

    def _raise(*_a, **_k):
        raise RuntimeError("requests failed")

    monkeypatch.setattr(sitemap, "_fetch_sitemap_requests", _raise)
    urls = sitemap.parse_sitemap_urls(
        "https://example.com/sitemap.xml",
        session=_Session(_Resp(b"")),
        timeout=1.0,
        fetch_mode="auto",
    )
    assert urls == ["https://example.com/b"]


def test_parse_sitemap_urls_errors_and_limits(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    with pytest.raises(ValueError, match="Local sitemap file not found"):
        sitemap.parse_sitemap_urls("missing.xml", session=_Session(_Resp(b"")), timeout=1.0)

    with pytest.raises(ValueError, match="Unsupported sitemap URL scheme"):
        sitemap.parse_sitemap_urls("ftp://example.com/x.xml", session=_Session(_Resp(b"")), timeout=1.0)

    monkeypatch.setattr(sitemap, "_fetch_sitemap_requests", lambda *_a, **_k: b"<feed></feed>")
    with pytest.raises(ValueError, match="Unsupported sitemap type"):
        sitemap.parse_sitemap_urls("https://example.com/sitemap.xml", session=_Session(_Resp(b"")), timeout=1.0)

    def _raise(*_a, **_k):
        raise RuntimeError("r")

    def _raise_browser(*_a, **_k):
        raise RuntimeError("b")

    monkeypatch.setattr(sitemap, "_fetch_sitemap_requests", _raise)
    monkeypatch.setattr(sitemap, "_fetch_sitemap_browser", _raise_browser)
    with pytest.raises(RuntimeError, match="Requests sitemap fetch failed"):
        sitemap.parse_sitemap_urls(
            "https://example.com/sitemap.xml",
            session=_Session(_Resp(b"")),
            timeout=1.0,
            fetch_mode="auto",
        )

    monkeypatch.setattr(
        sitemap,
        "_fetch_sitemap_requests",
        lambda *_a, **_k: _urlset("https://example.com/1", "https://example.com/2"),
    )
    urls = sitemap.parse_sitemap_urls(
        "https://example.com/sitemap.xml",
        session=_Session(_Resp(b"")),
        timeout=1.0,
        max_urls=1,
    )
    assert urls == ["https://example.com/1"]

    assert sitemap.get_base_url("https://example.com/path") == "https://example.com"
