#!/usr/bin/env python3
"""Pass/fail verification for the Written 50ABCDE v03 server bundle."""

from __future__ import annotations

import json
import os
import re
import subprocess
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
SAMPLE_DIR = ROOT / "samples" / "sample7"
EXPECTED_PATH = ROOT / "deploy" / "expected_output.json"
VERIFIED_SCANS = [
    "2026-08-03-0002.jpg",
    "PXL_20260803_185005794.jpg",
]


def load_expected() -> dict[str, str]:
    payload = json.loads(EXPECTED_PATH.read_text(encoding="utf-8"))
    return payload["responses"]


def find_scan_files() -> list[Path]:
    found = [SAMPLE_DIR / name for name in VERIFIED_SCANS if (SAMPLE_DIR / name).exists()]
    return found


def run_omr() -> tuple[int, str]:
    env = os.environ.copy()
    env["OMR_HEADLESS"] = "1"
    completed = subprocess.run(
        [sys.executable, "main.py", "-i", str(SAMPLE_DIR)],
        cwd=ROOT,
        capture_output=True,
        text=True,
        env=env,
        check=False,
    )
    return completed.returncode, completed.stdout + completed.stderr


def parse_response_for_scan(output: str, scan_name: str) -> dict[str, str] | None:
    pattern = (
        rf"Opening image:.*?'{re.escape(scan_name)}'.*?Read Response:.*?\n\s*(\{{.*?\}})"
    )
    match = re.search(pattern, output, re.DOTALL)
    if not match:
        return None
    return eval(match.group(1))


def parse_global_thr_for_scan(output: str, scan_name: str) -> float | None:
    pattern = (
        rf"Opening image:.*?'{re.escape(scan_name)}'.*?global_thr:\s*([0-9.]+)"
    )
    match = re.search(pattern, output, re.DOTALL)
    return float(match.group(1)) if match else None


def compare(expected: dict[str, str], actual: dict[str, str]) -> list[str]:
    errors: list[str] = []
    keys = sorted(set(expected) | set(actual))
    for key in keys:
        exp = expected.get(key, "")
        got = actual.get(key, "")
        if exp != got:
            errors.append(f"{key}: expected '{exp}', got '{got}'")
    return errors


def main() -> int:
    print("OMRChecker v03 verification")
    print(f"Repo: {ROOT}")
    print(f"Commit pin: {(ROOT / 'deploy' / 'COMMIT.txt').read_text(encoding='utf-8').splitlines()[0]}")

    required = [
        SAMPLE_DIR / "template.json",
        SAMPLE_DIR / "omr_marker.jpg",
        EXPECTED_PATH,
        ROOT / "src" / "utils" / "interaction.py",
    ]
    missing = [str(path) for path in required if not path.exists()]
    if missing:
        print("FAIL: missing required files:")
        for path in missing:
            print(f"  - {path}")
        return 1

    scans = find_scan_files()
    if not scans:
        print("FAIL: no verified scan files found in samples/sample7/")
        print("Place these files in samples/sample7/ before running verify:")
        for name in VERIFIED_SCANS:
            print(f"  - {name}")
        return 1

    expected = load_expected()
    failures = 0
    code, output = run_omr()
    if code != 0:
        print(f"FAIL: main.py exited with code {code}")
        print(output[-2000:])
        return 1

    for scan in scans:
        print(f"\n--- {scan.name} ---")
        actual = parse_response_for_scan(output, scan.name)
        if actual is None:
            print("FAIL: could not parse Read Response from OMR output")
            failures += 1
            continue

        thr = parse_global_thr_for_scan(output, scan.name)
        if thr is not None:
            print(f"global_thr: {thr}")
            if thr > 150:
                print("FAIL: global_thr too high — likely marker misalignment")

        errors = compare(expected, actual)
        if errors:
            print("FAIL: response mismatch")
            for err in errors[:15]:
                print(f"  {err}")
            if len(errors) > 15:
                print(f"  ... and {len(errors) - 15} more")
            failures += 1
        else:
            print("PASS: response matches expected_output.json")

    if failures:
        print(f"\nRESULT: FAIL ({failures} scan(s) failed)")
        return 1

    print(f"\nRESULT: PASS ({len(scans)} scan(s) verified)")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
