# retoor <retoor@molodetz.nl>

from __future__ import annotations

import asyncio
import json
import sys
from datetime import datetime, timezone
from pathlib import Path

from .checks.base import SiteContext
from .checks.registry import compute_score, run_page_checks, run_site_checks
from .crawler import crawl_target


def _emit(frame: dict) -> None:
    sys.stdout.write(json.dumps(frame, ensure_ascii=False) + "\n")
    sys.stdout.flush()


def _trim_site(site: SiteContext) -> dict:
    robots = site.robots or {}
    sitemap = site.sitemap or {}
    return {
        "robots": {
            "status": robots.get("status"),
            "disallows": robots.get("disallows", [])[:50],
            "sitemap_urls": robots.get("sitemap_urls", [])[:10],
            "blocks_target": robots.get("blocks_target", False),
        },
        "sitemap": {
            "status": sitemap.get("status"),
            "valid_xml": sitemap.get("valid_xml", False),
            "url_count": sitemap.get("url_count", 0),
            "lastmod_count": sitemap.get("lastmod_count", 0),
        },
        "llms_txt": site.llms_txt or {},
    }


async def _run(payload: dict, output_dir: Path) -> dict:
    site = await crawl_target(payload, _emit, output_dir)

    all_checks: list = []
    pages_summary: list[dict] = []
    _emit({"type": "stage", "stage": "checks", "message": "Running SEO checks"})
    for page in site.pages:
        page_checks = run_page_checks(page, site)
        all_checks.extend(page_checks)
        page_score = compute_score(page_checks)
        page_dicts = [c.to_dict() for c in page_checks]
        pages_summary.append(
            {
                "url": page.url,
                "requested_url": page.requested_url,
                "status": page.status,
                "ok": page.ok,
                "error": page.error,
                "screenshot": page.screenshot,
                "score": page_score["score"],
                "grade": page_score["grade"],
                "counts": page_score["counts"],
            }
        )
        _emit(
            {
                "type": "page",
                "url": page.url,
                "status": page.status,
                "score": page_score["score"],
                "grade": page_score["grade"],
                "counts": page_score["counts"],
                "checks": page_dicts,
            }
        )

    site_checks = run_site_checks(site)
    all_checks.extend(site_checks)
    _emit(
        {
            "type": "site_checks",
            "checks": [c.to_dict() for c in site_checks],
        }
    )

    overall = compute_score(all_checks)
    report = {
        "target": site.target_url,
        "mode": site.mode,
        "generated_at": datetime.now(timezone.utc).isoformat(),
        "page_count": len(site.pages),
        "score": overall["score"],
        "grade": overall["grade"],
        "counts": overall["counts"],
        "categories": overall["categories"],
        "pages": pages_summary,
        "checks": [c.to_dict() for c in all_checks],
        "site": _trim_site(site),
    }
    if output_dir is not None:
        (output_dir / "report.json").write_text(
            json.dumps(report, ensure_ascii=False), encoding="utf-8"
        )
    _emit(
        {
            "type": "report_ready",
            "score": report["score"],
            "grade": report["grade"],
            "counts": report["counts"],
            "categories": report["categories"],
            "page_count": report["page_count"],
        }
    )
    return report


def main(argv: list) -> int:
    if len(argv) != 3:
        sys.stderr.write("usage: seo.worker <payload_json> <output_dir>\n")
        return 2
    payload = json.loads(Path(argv[1]).read_text(encoding="utf-8"))
    output_dir = Path(argv[2])
    output_dir.mkdir(parents=True, exist_ok=True)
    try:
        asyncio.run(_run(payload, output_dir))
    except Exception as exc:  # noqa: BLE001 - surface as a worker error line
        _emit({"type": "error", "message": str(exc)[:500]})
        return 1
    return 0


if __name__ == "__main__":
    raise SystemExit(main(sys.argv))
