#!/usr/bin/env python
"""Test runner for crawler.py — times steps and kills on inactivity."""
from __future__ import annotations

import subprocess
import sys
import time
from datetime import datetime, timezone
from pathlib import Path

HERE = Path(__file__).resolve().parent
CRAWLER = HERE / "crawler.py"
OUT_DIR = HERE.parent / "sites_crawled" / "www.prolicht.at"
LOG_PATH = HERE / "crawler.log"


def run_crawl(args: list[str], step_timeout: float = 15.0) -> subprocess.CompletedProcess:
    """Run crawler.py as subprocess, print output with timestamps, kill if step takes too long."""
    cmd = [sys.executable, str(CRAWLER)] + [a for a in args if a]
    print(f"[{datetime.now(timezone.utc).strftime('%H:%M:%S')}] Running: {' '.join(cmd)}")
    print("=" * 80)

    proc = subprocess.Popen(
        cmd,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        text=True,
        encoding="utf-8",
        errors="replace",
        cwd=str(HERE),
    )

    last_line_time = time.time()
    all_lines: list[str] = []
    start_time = time.time()
    killed = False

    while True:
        line = proc.stdout.readline() if proc.stdout else ""
        if not line:
            if proc.poll() is not None:
                break
            elapsed_since_line = time.time() - last_line_time
            if elapsed_since_line >= step_timeout:
                print(f"\n[TIMEOUT] No output for {elapsed_since_line:.0f}s (limit={step_timeout}s) — killing crawler")
                proc.kill()
                killed = True
                break
            time.sleep(0.5)
            continue

        line = line.rstrip("\n")
        elapsed = time.time() - start_time
        print(f"  [{elapsed:7.1f}s] {line}")
        all_lines.append(line)
        last_line_time = time.time()

    proc.wait(timeout=10)
    total_time = time.time() - start_time
    print(f"\n[killed={killed}] Crawler exited with code {proc.returncode} after {total_time:.1f}s")

    return subprocess.CompletedProcess(
        args=cmd,
        returncode=proc.returncode,
        stdout="\n".join(all_lines),
        stderr="",
    )


def verify_output(host_dir: Path) -> dict[str, bool]:
    """Check that required output files exist and are non-empty."""
    checks: dict[str, bool] = {}

    checks["domain_dir"] = host_dir.exists()

    for subdir in ["images", "screenshots"]:
        p = host_dir / subdir
        checks[f"{subdir}_dir"] = p.exists()

    for name in [
        "prolicht__at.html",
        "prolicht__at.txt",
        "prolicht__at.md",
        "prolicht__at.images.json",
        "prolicht__at.crawl.json",
        "_crawl_run.json",
        "_consent_snapshots.json",
        "_discovered_urls.json",
        "_failed_urls.json",
    ]:
        p = host_dir / name
        checks[name] = p.exists() and p.stat().st_size > 0

    return checks


def normalize_url(url: str) -> str:
    clean = url.rstrip("/")
    if "?" in clean:
        clean = clean.split("?")[0]
    return clean


def print_results(checks: dict[str, bool]) -> int:
    failures = 0
    for name, ok in sorted(checks.items()):
        status = "PASS" if ok else "FAIL"
        print(f"  {status} {name}")
        if not ok:
            failures += 1

    print(f"\n{len(checks)} checks: {len(checks) - failures} pass, {failures} fail")
    return 1 if failures else 0


def main() -> int:
    import argparse
    p = argparse.ArgumentParser()
    p.add_argument("--step-timeout", type=float, default=15.0, help="Seconds without output before killing")
    p.add_argument("--limit", type=int, default=6)
    p.add_argument("--headless", action="store_true", default=True)
    p.add_argument("--view-w", type=int, default=1920)
    p.add_argument("--view-h", type=int, default=1080)
    p.add_argument("--markdown", type=str, default="true")
    p.add_argument("--verbose", action="store_true")
    p.add_argument("--vision", type=str, default="false")
    args = p.parse_args()

    cmd_args = [
        "--fetch-sitemap", "https://www.prolicht.at",
        "--limit", str(args.limit),
        "--viewport-width", str(args.view_w),
        "--viewport-height", str(args.view_h),
        "--markdown", args.markdown,
        "--vision", args.vision,
    ]
    if args.headless:
        cmd_args.append("--headless")
    if args.verbose:
        cmd_args.append("--verbose")

    result = run_crawl(cmd_args, step_timeout=args.step_timeout)
    print("\n" + "=" * 80)
    print("OUTPUT VERIFICATION")
    print("=" * 80)

    checks = verify_output(OUT_DIR)
    exit_code = print_results(checks)

    if result.returncode != 0 and not checks.get("prolicht__at.html"):
        print(f"\n[WARN] Crawler exited with code {result.returncode} and no root page output")

    return exit_code


if __name__ == "__main__":
    raise SystemExit(main())
