"""Require exact OMRChecker output for all six TDC layout fixtures."""

from __future__ import annotations

import argparse
import csv
import json
import os
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path


SCRIPT_DIR = Path(__file__).resolve().parent
if (SCRIPT_DIR / "manifest.json").is_file():
    BUNDLE = SCRIPT_DIR
else:
    BUNDLE = SCRIPT_DIR / "output/omr/TDC_Form_Family_v01_RC2_OMR"


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "--omrchecker",
        type=Path,
        required=True,
        help="Path to the pinned OMRChecker source directory containing main.py",
    )
    return parser.parse_args()


def decode_id(raw_rows: str, mapping: list[str | None]) -> str:
    if len(raw_rows) != 3 or not raw_rows.isdigit():
        raise ValueError(f"Invalid raw ID rows: {raw_rows!r}")
    value = mapping[int(raw_rows[0])]
    if value is None:
        raise ValueError(f"Unused prefix row selected: {raw_rows[0]}")
    return value + raw_rows[1:]


def verify_id_mappings() -> None:
    mappings = json.loads((BUNDLE / "shared/id_mappings.json").read_text())
    assert decode_id("159", mappings["numeric3"]["positions"][0]) == "159"
    assert decode_id("127", mappings["ohio_prefix2"]["positions"][0]) == "F27"
    assert decode_id("627", mappings["missouri_prefix2"]["positions"][0]) == "F27"


def run_layout(omrchecker: Path, layout: str) -> None:
    layout_dir = BUNDLE / "layouts" / layout
    test_dir = BUNDLE / "tests" / layout
    expected = json.loads((test_dir / "expected_output.json").read_text())

    with tempfile.TemporaryDirectory(prefix=f"tdc-omr-{layout}-") as temporary:
        temp = Path(temporary)
        inputs = temp / "inputs"
        outputs = temp / "outputs"
        inputs.mkdir()
        for source in (
            layout_dir / "template.json",
            layout_dir / "omr_marker.jpg",
            test_dir / "marked_test.pdf",
        ):
            shutil.copy2(source, inputs / source.name)

        environment = os.environ.copy()
        environment["MPLCONFIGDIR"] = str(temp / "matplotlib")
        completed = subprocess.run(
            [sys.executable, str(omrchecker / "main.py"), "-i", str(inputs), "-o", str(outputs)],
            cwd=omrchecker,
            env=environment,
            text=True,
            capture_output=True,
        )
        if completed.returncode:
            print(completed.stdout)
            print(completed.stderr, file=sys.stderr)
            raise RuntimeError(f"OMRChecker failed for {layout}: {completed.returncode}")

        csv_files = list((outputs / "Results").glob("Results_*.csv"))
        if len(csv_files) != 1:
            raise RuntimeError(f"{layout}: expected one results CSV, found {len(csv_files)}")
        with csv_files[0].open(newline="", encoding="utf-8-sig") as stream:
            rows = list(csv.DictReader(stream))
        if len(rows) != 1:
            raise RuntimeError(f"{layout}: expected one result row, found {len(rows)}")
        row = rows[0]
        mismatches = {
            field: (wanted, row.get(field))
            for field, wanted in expected.items()
            if row.get(field) != wanted
        }
        if mismatches:
            details = ", ".join(f"{field}: {got!r} != {wanted!r}" for field, (wanted, got) in mismatches.items())
            raise RuntimeError(f"{layout}: {details}")
        print(f"PASS: {layout} exact ID and {len(expected) - 1} responses")


def main() -> int:
    args = parse_args()
    if not (args.omrchecker / "main.py").is_file():
        raise FileNotFoundError(args.omrchecker / "main.py")
    verify_id_mappings()
    print("PASS: numeric, Ohio, and Missouri ID mappings")
    for layout in sorted(path.name for path in (BUNDLE / "layouts").iterdir() if path.is_dir()):
        run_layout(args.omrchecker.resolve(), layout)
    print("PASS: all six TDC layout golden tests")
    return 0


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