# retoor <retoor@molodetz.nl>

from devplacepy.services.jobs.seo.checks import registry
from devplacepy.services.jobs.seo.checks.base import (
    Check,
    PageContext,
    SiteContext,
    PASS,
    WARN,
    FAIL,
    INFO,
    SKIP,
    CRITICAL,
    HIGH,
    LOW,
)


def _check(status, severity, category="meta"):
    return Check(
        id=f"{category}.{status}",
        category=category,
        title="t",
        status=status,
        severity=severity,
    )


def test_all_pass_scores_100_grade_a():
    checks = [_check(PASS, HIGH), _check(PASS, CRITICAL)]
    result = registry.compute_score(checks)
    assert result["score"] == 100
    assert result["grade"] == "A"


def test_all_fail_scores_0_grade_f():
    checks = [_check(FAIL, HIGH), _check(FAIL, CRITICAL)]
    result = registry.compute_score(checks)
    assert result["score"] == 0
    assert result["grade"] == "F"


def test_warn_gives_half_credit():
    result = registry.compute_score([_check(WARN, HIGH)])
    assert result["score"] == 50


def test_info_and_skip_excluded_from_weight():
    checks = [_check(INFO, LOW), _check(SKIP, LOW), _check(PASS, HIGH)]
    result = registry.compute_score(checks)
    assert result["score"] == 100
    assert result["counts"]["info"] == 1
    assert result["counts"]["skip"] == 1
    assert result["counts"]["pass"] == 1


def test_informational_severity_zero_weight_ignored():
    checks = [_check(FAIL, "info"), _check(PASS, HIGH)]
    result = registry.compute_score(checks)
    assert result["score"] == 100


def test_severity_weighting_favours_critical():
    checks = [_check(FAIL, CRITICAL), _check(PASS, LOW)]
    result = registry.compute_score(checks)
    assert result["score"] < 50


def test_grade_boundaries():
    assert registry._grade(90) == "A"
    assert registry._grade(89) == "B"
    assert registry._grade(80) == "B"
    assert registry._grade(70) == "C"
    assert registry._grade(55) == "D"
    assert registry._grade(54) == "F"


def test_categories_reported_per_bucket():
    checks = [
        _check(PASS, HIGH, category="meta"),
        _check(FAIL, HIGH, category="links"),
    ]
    result = registry.compute_score(checks)
    assert result["categories"]["meta"]["score"] == 100
    assert result["categories"]["links"]["score"] == 0


def test_empty_checks_scores_zero():
    result = registry.compute_score([])
    assert result["score"] == 0
    assert result["grade"] == "F"


def test_run_page_checks_returns_checks():
    page = PageContext(
        requested_url="https://example.com",
        url="https://example.com",
        status=200,
        ok=True,
        rendered_html="<html><head><title>Hi</title></head><body></body></html>",
    )
    site = SiteContext(target_url="https://example.com", base_host="example.com")
    checks = registry.run_page_checks(page, site)
    assert isinstance(checks, list)
    assert all(isinstance(c, Check) for c in checks)


def test_run_site_checks_returns_checks():
    site = SiteContext(target_url="https://example.com", base_host="example.com")
    checks = registry.run_site_checks(site)
    assert isinstance(checks, list)
    assert all(isinstance(c, Check) for c in checks)


def test_bad_page_check_does_not_abort(monkeypatch):
    def explode(page, site):
        raise RuntimeError("boom")

    monkeypatch.setattr(registry, "PAGE_CHECKS", [explode])
    page = PageContext(url="https://example.com", ok=True)
    site = SiteContext(target_url="https://example.com")
    checks = registry.run_page_checks(page, site)
    assert len(checks) == 1
    assert checks[0].status == INFO
    assert "explode" in checks[0].id
