from __future__ import annotations

from types import SimpleNamespace

import requests

from worai.seocheck.checks.canonical import CanonicalCheck
from worai.seocheck.checks.llms_txt import check_llms_txt
from worai.seocheck.checks.page_meta import PageMetaCheck
from worai.seocheck.checks.resource_404 import Resource404Check
from worai.seocheck.checks.response_time import ResponseTimeCheck
from worai.seocheck.checks.robots_txt import _disallow_all, _extract_groups, check_robots_txt
from worai.seocheck.checks.status import StatusCheck
from worai.seocheck.checks.ttfb import TtfbCheck
from worai.seocheck.checks.wordlift_bootstrap import WordLiftBootstrapCheck


class _Page:
    def __init__(self, *, title: str = "", values: dict[str, object] | None = None, raises: bool = False) -> None:
        self._title = title
        self._values = values or {}
        self._raises = raises

    def title(self) -> str:
        return self._title

    def evaluate(self, script: str, *_args):
        if self._raises:
            raise RuntimeError("eval failed")
        for key, value in self._values.items():
            if key in script:
                return value
        return self._values.get("default", "")


class _Session:
    def __init__(self, responses):
        self._responses = list(responses)

    def get(self, _url: str, timeout: float):
        assert timeout == 1.0
        if not self._responses:
            raise AssertionError("no response")
        response = self._responses.pop(0)
        if isinstance(response, Exception):
            raise response
        return response


def test_canonical_status_response_time_and_resource_checks() -> None:
    canonical_ok = CanonicalCheck().run(
        page=_Page(values={"canonical": "https://example.com/"}),
        response=None,
        elapsed_ms=0,
        resources=[],
    )
    assert canonical_ok.status == "ok"

    canonical_warn = CanonicalCheck().run(page=_Page(), response=None, elapsed_ms=0, resources=[])
    assert canonical_warn.status == "warn"

    assert ResponseTimeCheck().run(page=None, response=None, elapsed_ms=100, resources=[]).status == "ok"
    assert ResponseTimeCheck().run(page=None, response=None, elapsed_ms=2500, resources=[]).status == "warn"
    assert ResponseTimeCheck().run(page=None, response=None, elapsed_ms=7000, resources=[]).status == "fail"

    resources = [
        {"status": 200, "resource_type": "image"},
        {"status": 404, "resource_type": "image", "url": "x"},
        {"status": 500, "resource_type": "script", "url": "y"},
        {"status": 403, "resource_type": "xhr", "url": "z"},
    ]
    result = Resource404Check(max_samples=1).run(page=None, response=None, elapsed_ms=0, resources=resources)
    assert result.status == "warn"
    assert result.data["count"] == 2
    assert len(result.data["samples"]) == 1


def test_page_meta_status_ttfb_and_wordlift_checks() -> None:
    page = _Page(
        title="Title",
        values={
            "meta[name=\"description\"]": "Desc",
            "meta[name=\"robots\"]": "index,follow",
            "meta[property=\"og:title\"]": "OGT",
            "meta[property=\"og:description\"]": "OGD",
        },
    )
    meta_ok = PageMetaCheck().run(page=page, response=None, elapsed_ms=0, resources=[])
    assert meta_ok.status == "ok"

    meta_warn = PageMetaCheck().run(page=_Page(), response=None, elapsed_ms=0, resources=[])
    assert meta_warn.status == "warn"
    assert "missing title" in meta_warn.details

    assert StatusCheck().run(page=None, response=None, elapsed_ms=0, resources=[]).status == "fail"
    assert StatusCheck().run(page=None, response=SimpleNamespace(status=200), elapsed_ms=0, resources=[]).status == "ok"
    assert StatusCheck().run(page=None, response=SimpleNamespace(status=500), elapsed_ms=0, resources=[]).status == "warn"

    ttfb = TtfbCheck(ok_ms=100, warn_ms=200)
    assert ttfb.run(page=_Page(), response=None, elapsed_ms=0, resources=[]).status == "fail"
    assert ttfb.run(page=_Page(raises=True), response=SimpleNamespace(status=200), elapsed_ms=0, resources=[]).status == "fail"
    assert ttfb.run(page=_Page(values={"default": None}), response=SimpleNamespace(status=200), elapsed_ms=0, resources=[]).status == "fail"
    assert (
        ttfb.run(
            page=_Page(values={"default": {"requestStart": 1, "responseStart": 50}}),
            response=SimpleNamespace(status=200),
            elapsed_ms=0,
            resources=[],
        ).status
        == "ok"
    )
    assert (
        ttfb.run(
            page=_Page(values={"default": {"requestStart": 1, "responseStart": 250}}),
            response=SimpleNamespace(status=200),
            elapsed_ms=0,
            resources=[],
        ).status
        == "fail"
    )

    assert WordLiftBootstrapCheck().run(
        page=_Page(values={"default": True}),
        response=None,
        elapsed_ms=0,
        resources=[],
    ).status == "ok"
    assert WordLiftBootstrapCheck().run(
        page=_Page(values={"default": False}),
        response=None,
        elapsed_ms=0,
        resources=[],
    ).status == "fail"


def test_llms_and_robots_checks_and_parsers() -> None:
    assert _disallow_all("User-agent: *\nDisallow: /\n") is True
    assert _disallow_all("User-agent: *\nDisallow:\n") is False

    groups = _extract_groups(["User-agent: *", "Disallow: /", "User-agent: test", "Disallow: /no"]) 
    assert len(groups) == 2

    fail = check_llms_txt("https://example.com", session=_Session([requests.RequestException("x")]), timeout=1.0)
    assert fail.status == "fail"

    ok = check_llms_txt(
        "https://example.com",
        session=_Session([SimpleNamespace(status_code=200, text="abc")]),
        timeout=1.0,
    )
    assert ok.status == "ok"

    warn = check_llms_txt(
        "https://example.com",
        session=_Session([SimpleNamespace(status_code=404, text=""), SimpleNamespace(status_code=404, text="")]),
        timeout=1.0,
    )
    assert warn.status == "warn"

    robots_fail = check_robots_txt(
        "https://example.com",
        session=_Session([requests.RequestException("x")]),
        timeout=1.0,
    )
    assert robots_fail.status == "fail"

    robots_warn = check_robots_txt(
        "https://example.com",
        session=_Session([SimpleNamespace(status_code=500, text="")]),
        timeout=1.0,
    )
    assert robots_warn.status == "warn"

    robots_ok = check_robots_txt(
        "https://example.com",
        session=_Session([SimpleNamespace(status_code=200, text="User-agent: *\nDisallow:" )]),
        timeout=1.0,
    )
    assert robots_ok.status == "ok"

    robots_blocked = check_robots_txt(
        "https://example.com",
        session=_Session([SimpleNamespace(status_code=200, text="User-agent: *\nDisallow: /")]),
        timeout=1.0,
    )
    assert robots_blocked.status == "warn"
