from __future__ import annotations

import json
from pathlib import Path

import pytest

from worai.seocheck import cli as seocheck_cli
from worai.seocheck.checks.types import CheckResult


class _Check:
    def __init__(self, name: str, status: str = "ok") -> None:
        self.name = name
        self._status = status

    def run(self, **_kwargs):
        return CheckResult(name=self.name, status=self._status, details="d")


def test_helpers_for_counts_and_files(tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
    site = [{"name": "robots.txt", "status": "ok", "details": "ok", "url": "u"}]
    pages = [{"url": "u", "status": "warn", "checks": [{"name": "ttfb", "status": "warn"}]}]
    agg = seocheck_cli._aggregate_counts(site, pages)
    assert agg["site"]["total"] == 1
    assert agg["pages"]["by_status"]["warn"] == 1
    assert seocheck_cli._derive_page_status([{"status": "ok"}, {"status": "fail"}]) == "fail"
    assert seocheck_cli._status_rank("warn") > seocheck_cli._status_rank("ok")
    assert len(seocheck_cli._hash_url("https://example.com")) == 40

    seocheck_cli._print_site_results(site, as_json=False)
    seocheck_cli._print_page_results("u", [CheckResult(name="n", status="ok")], as_json=False)
    out = capsys.readouterr().out
    assert "SITE robots.txt" in out
    assert "URL u" in out

    report = tmp_path / "report.json"
    summary = tmp_path / "summary.txt"
    seocheck_cli._write_json_report(report, {"a": 1})
    seocheck_cli._write_summary(summary, site, pages)
    assert json.loads(report.read_text())["a"] == 1
    assert "SEO Check Summary" in summary.read_text()


def test_load_failed_urls(tmp_path: Path) -> None:
    payload = {"pages": [{"url": "u1", "status": "warn", "checks": []}, {"url": "u2", "status": "ok", "checks": []}]}
    p = tmp_path / "report.json"
    p.write_text(json.dumps(payload), encoding="utf-8")
    assert seocheck_cli._load_failed_urls(str(p)) == {"u1"}

    with pytest.raises(RuntimeError, match="Recheck report not found"):
        seocheck_cli._load_failed_urls(str(tmp_path / "missing.json"))


def test_process_url_saves_html_and_handles_check_error(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    class _Page:
        @staticmethod
        def content() -> str:
            return "<html/>"

        def close(self) -> None:
            return None

    class _Response:
        status_code = 200

    class _Browser:
        def __init__(self, **_kwargs):
            pass

        def __enter__(self):
            return self

        def __exit__(self, *_args):
            return None

        def open(self, _url):
            return _Page(), _Response(), 1.0, []

    class _BoomCheck:
        name = "boom"

        @staticmethod
        def run(**_kwargs):
            raise RuntimeError("x")

    monkeypatch.setattr(seocheck_cli, "Browser", _Browser)
    payload, summary, had_error = seocheck_cli._process_url(
        "https://example.com",
        page_checks=[_BoomCheck()],
        output_dir=tmp_path,
        save_html=True,
        headless=True,
        page_timeout=10,
        wait_until="load",
    )
    assert payload["checks"][0]["status"] == "fail"
    assert summary["html"] is not None
    assert had_error is False


def test_run_error_paths(monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr(seocheck_cli, "parse_sitemap_urls", lambda *_a, **_k: (_ for _ in ()).throw(RuntimeError("nope")))
    assert seocheck_cli.run(["https://example.com/sitemap.xml", "--no-report-ui"]) == 1

    monkeypatch.setattr(seocheck_cli, "parse_sitemap_urls", lambda *_a, **_k: [])
    assert seocheck_cli.run(["https://example.com/sitemap.xml", "--no-report-ui"]) == 1


def test_run_success_and_unknown_check(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    monkeypatch.setattr(seocheck_cli, "parse_sitemap_urls", lambda *_a, **_k: ["https://example.com/a"])
    monkeypatch.setattr(seocheck_cli, "check_robots_txt", lambda *_a, **_k: type("R", (), {"url": "u", "status": "ok", "details": "ok", "status_code": 200, "disallow_all": False})())
    monkeypatch.setattr(seocheck_cli, "check_llms_txt", lambda *_a, **_k: type("L", (), {"url": "u", "status": "ok", "details": "ok", "status_code": 200})())
    monkeypatch.setattr(seocheck_cli, "get_page_checks", lambda **_k: [_Check("status", "ok")])

    class _Page:
        @staticmethod
        def content() -> str:
            return "<html/>"

        def close(self) -> None:
            return None

    class _Resp:
        status_code = 200

    class _Browser:
        def __init__(self, **_kwargs):
            pass

        def __enter__(self):
            return self

        def __exit__(self, *_args):
            return None

        def open(self, _url):
            return _Page(), _Resp(), 1.0, []

    monkeypatch.setattr(seocheck_cli, "Browser", _Browser)
    rc = seocheck_cli.run(
        [
            "https://example.com/sitemap.xml",
            "--output-dir",
            str(tmp_path),
            "--no-report-ui",
            "--concurrency",
            "1",
        ]
    )
    assert rc == 0
    assert (tmp_path / "report.json").exists()

    rc = seocheck_cli.run(
        [
            "https://example.com/sitemap.xml",
            "--no-report-ui",
            "--checks",
            "unknown",
        ]
    )
    assert rc == 1
