# retoor <retoor@molodetz.nl>

import requests
from tests.conftest import BASE_URL
from devplacepy.database import get_table, refresh_snapshot
from devplacepy.services.jobs import queue


def _json_headers():
    return {"Accept": "application/json"}


def _clear_seo_jobs():
    refresh_snapshot()
    jobs = get_table("jobs")
    for row in list(jobs.find(kind="seo")):
        jobs.delete(uid=row["uid"])


def test_seo_page_renders(app_server):
    r = requests.get(f"{BASE_URL}/tools/seo")
    assert r.status_code == 200
    assert "SEO Diagnostics" in r.text
    assert "data-seo-form" in r.text


def test_run_enqueues_and_returns_uid(app_server):
    try:
        r = requests.post(
            f"{BASE_URL}/tools/seo/run",
            headers=_json_headers(),
            data={"url": "https://example.com", "mode": "url", "max_pages": "5"},
        )
        assert r.status_code == 200, r.text
        body = r.json()
        uid = body["uid"]
        assert uid
        assert body["status_url"] == f"/tools/seo/{uid}"
        assert body["ws_url"] == f"/tools/seo/{uid}/ws"

        refresh_snapshot()
        job = queue.get_job(uid)
        assert job is not None
        assert job["kind"] == "seo"
        assert job["status"] == queue.PENDING
        assert job["payload"]["url"] == "https://example.com"
        assert job["payload"]["max_pages"] == 5
        assert job["payload"]["allow_private"] is False
    finally:
        _clear_seo_jobs()


def test_run_rejects_blank_url(app_server):
    try:
        r = requests.post(
            f"{BASE_URL}/tools/seo/run",
            headers=_json_headers(),
            data={"url": "  ", "mode": "url"},
            allow_redirects=False,
        )
        assert r.status_code in (400, 422), r.text
    finally:
        _clear_seo_jobs()


def test_run_rejects_invalid_mode(app_server):
    try:
        r = requests.post(
            f"{BASE_URL}/tools/seo/run",
            headers=_json_headers(),
            data={"url": "https://example.com", "mode": "bogus"},
            allow_redirects=False,
        )
        assert r.status_code in (400, 422), r.text
    finally:
        _clear_seo_jobs()


def test_run_clamps_max_pages_above_cap(app_server):
    try:
        r = requests.post(
            f"{BASE_URL}/tools/seo/run",
            headers=_json_headers(),
            data={"url": "https://example.com", "mode": "url", "max_pages": "9999"},
            allow_redirects=False,
        )
        assert r.status_code in (400, 422), r.text
    finally:
        _clear_seo_jobs()


def test_run_rejects_malformed_scheme(app_server):
    r = requests.post(
        f"{BASE_URL}/tools/seo/run",
        headers=_json_headers(),
        data={"url": "ahttps://devplace.net/sitem", "mode": "url"},
        allow_redirects=False,
    )
    assert r.status_code in (400, 422), r.text


def test_run_rejects_relative_path(app_server):
    r = requests.post(
        f"{BASE_URL}/tools/seo/run",
        headers=_json_headers(),
        data={"url": "/feed", "mode": "url"},
        allow_redirects=False,
    )
    assert r.status_code in (400, 422), r.text


def test_run_normalizes_missing_scheme(app_server):
    try:
        r = requests.post(
            f"{BASE_URL}/tools/seo/run",
            headers=_json_headers(),
            data={"url": "example.com", "mode": "url", "max_pages": "5"},
        )
        assert r.status_code == 200, r.text
        uid = r.json()["uid"]
        refresh_snapshot()
        job = queue.get_job(uid)
        assert job is not None
        assert job["payload"]["url"] == "https://example.com"
    finally:
        _clear_seo_jobs()


def test_run_rejects_non_http_scheme(app_server):
    r = requests.post(
        f"{BASE_URL}/tools/seo/run",
        headers=_json_headers(),
        data={"url": "ftp://example.com", "mode": "url"},
        allow_redirects=False,
    )
    assert r.status_code in (400, 422), r.text


def test_run_enforces_one_active_job_per_owner(app_server):
    try:
        first = requests.post(
            f"{BASE_URL}/tools/seo/run",
            headers=_json_headers(),
            data={"url": "https://example.com", "mode": "url"},
        )
        assert first.status_code == 200, first.text
        first_uid = first.json()["uid"]

        second = requests.post(
            f"{BASE_URL}/tools/seo/run",
            headers=_json_headers(),
            data={"url": "https://other.example", "mode": "url"},
        )
        assert second.status_code == 429, second.text
        error = second.json()["error"]
        assert error["status"] == 429
        assert error["uid"] == first_uid
    finally:
        _clear_seo_jobs()


def test_status_shape_for_pending_job(app_server):
    try:
        uid = queue.enqueue(
            "seo",
            {"url": "https://example.com", "mode": "url", "max_pages": 10},
            "user",
            "seo-status-owner",
            "SEO: https://example.com",
        )
        refresh_snapshot()
        r = requests.get(f"{BASE_URL}/tools/seo/{uid}", headers=_json_headers())
        assert r.status_code == 200, r.text
        body = r.json()
        assert body["uid"] == uid
        assert body["kind"] == "seo"
        assert body["status"] == "pending"
        assert body["target"] == "https://example.com"
        assert body["mode"] == "url"
        assert body["ws_url"] == f"/tools/seo/{uid}/ws"
        assert body["report_url"] is None
        assert body["score"] is None
        assert body["grade"] is None
        assert body["page_count"] == 0
    finally:
        _clear_seo_jobs()


def test_status_unknown_uid_404(app_server):
    r = requests.get(
        f"{BASE_URL}/tools/seo/nope-not-a-job", headers=_json_headers()
    )
    assert r.status_code == 404


def test_status_rejects_non_seo_kind(app_server):
    try:
        uid = queue.enqueue("other", {}, "user", "seo-kind-owner", "x")
        refresh_snapshot()
        r = requests.get(f"{BASE_URL}/tools/seo/{uid}", headers=_json_headers())
        assert r.status_code == 404
    finally:
        get_table("jobs").delete(kind="other")


def test_report_unknown_uid_404(app_server):
    r = requests.get(
        f"{BASE_URL}/tools/seo/nope-not-a-job/report", headers=_json_headers()
    )
    assert r.status_code == 404


def test_report_pending_job_renders_empty(app_server):
    try:
        uid = queue.enqueue(
            "seo",
            {"url": "https://example.com", "mode": "url", "max_pages": 10},
            "user",
            "seo-report-owner",
            "SEO: https://example.com",
        )
        refresh_snapshot()
        r = requests.get(
            f"{BASE_URL}/tools/seo/{uid}/report", headers=_json_headers()
        )
        assert r.status_code == 200, r.text
        body = r.json()
        assert body["uid"] == uid
        assert body["status"] == "pending"
        assert body["score"] is None
        assert body["page_count"] == 0
        assert body["pages"] == []
        assert body["checks"] == []
    finally:
        _clear_seo_jobs()


def test_screenshot_unknown_uid_404(app_server):
    r = requests.get(f"{BASE_URL}/tools/seo/nope-not-a-job/screenshot/0")
    assert r.status_code == 404


def test_screenshot_missing_file_404(app_server):
    try:
        uid = queue.enqueue(
            "seo",
            {"url": "https://example.com", "mode": "url", "max_pages": 10},
            "user",
            "seo-shot-owner",
            "SEO: https://example.com",
        )
        refresh_snapshot()
        r = requests.get(f"{BASE_URL}/tools/seo/{uid}/screenshot/0")
        assert r.status_code == 404
    finally:
        _clear_seo_jobs()


def test_screenshot_rejects_path_traversal(app_server):
    try:
        uid = queue.enqueue(
            "seo",
            {"url": "https://example.com", "mode": "url", "max_pages": 10},
            "user",
            "seo-traversal-owner",
            "SEO: https://example.com",
        )
        refresh_snapshot()
        r = requests.get(f"{BASE_URL}/tools/seo/{uid}/screenshot/-1")
        assert r.status_code == 404
    finally:
        _clear_seo_jobs()
