#!/usr/bin/env python3
"""Validate and normalize phone images, with orientation retries for MJ-RC5."""

from __future__ import annotations

import argparse
import csv
import json
import shutil
import subprocess
import sys
import time
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
PROFILE = ROOT / "profiles" / "mj-rc5"
sys.path.insert(0, str(ROOT))

from omr_service.input_validation import partition_images  # noqa: E402
from omr_service.omr_results import has_valid_controls, read_omr_results  # noqa: E402
from omr_service.page_normalization import normalize_phone_image  # noqa: E402


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("images", nargs="+", type=Path)
    parser.add_argument("--omrchecker", required=True, type=Path)
    parser.add_argument("--output", required=True, type=Path)
    args = parser.parse_args()
    output = args.output.resolve()
    omr_root = args.omrchecker.resolve()
    if output.exists():
        raise FileExistsError(f"Refusing to replace existing output: {output}")
    if not (omr_root / "main.py").is_file():
        raise FileNotFoundError(omr_root / "main.py")
    output.mkdir(parents=True)

    valid, issues = partition_images([path.resolve() for path in args.images])
    source_by_id = {f"image-{index:04d}.png": path for index, path in enumerate(valid, 1)}
    pending = list(source_by_id)
    chosen: dict[str, dict[str, str]] = {}
    normalize_seconds = 0.0
    omr_seconds = 0.0
    logs: list[str] = []

    for angle in (0, 90, 270, 180):
        if not pending:
            break
        stage = f"orientation-{angle:03d}"
        input_dir = output / "normalized" / stage
        omr_output = output / "omr-output" / stage
        input_dir.mkdir(parents=True)
        omr_output.mkdir(parents=True)
        for name in ("template.json", "config.json", "omr_marker.jpg"):
            shutil.copy2(PROFILE / name, input_dir / name)
        started = time.perf_counter()
        for file_id in pending:
            normalize_phone_image(source_by_id[file_id], input_dir / file_id, angle)
        normalize_seconds += time.perf_counter() - started
        started = time.perf_counter()
        completed = subprocess.run(
            [sys.executable, str(omr_root / "main.py"), "-i", str(input_dir), "-o", str(omr_output)],
            cwd=omr_root, text=True, capture_output=True,
        )
        omr_seconds += time.perf_counter() - started
        logs.append(f"===== {stage} stdout =====\n{completed.stdout}")
        logs.append(f"===== {stage} stderr =====\n{completed.stderr}")
        results = read_omr_results(omr_output)
        retry: list[str] = []
        for file_id in pending:
            row = results.get(file_id)
            if row is not None:
                row["orientation"] = str(angle)
                chosen[file_id] = row
            if not has_valid_controls(row):
                retry.append(file_id)
        pending = retry

    (output / "console.txt").write_text("\n".join(logs))
    fields = ["source_file", "file_id", "orientation", "route", "control_left", "control_right",
              "player_id_1", "player_id_2", "player_id_3", "round_tens", "round_ones",
              "game_1", "game_2", "game_3", "game_4"]
    with (output / "batch-results.csv").open("w", newline="") as handle:
        writer = csv.DictWriter(handle, fieldnames=fields, extrasaction="ignore")
        writer.writeheader()
        for file_id, source in source_by_id.items():
            row = chosen.get(file_id, {"file_id": file_id, "route": "error"}).copy()
            row["source_file"] = str(source)
            if file_id in pending:
                row["route"] = "error"
            writer.writerow(row)
    summary = {
        "images": len(source_by_id), "normalization_seconds": round(normalize_seconds, 3),
        "omr_seconds": round(omr_seconds, 3), "total_seconds": round(normalize_seconds + omr_seconds, 3),
        "orientation_retries": sum(row.get("orientation", "0") != "0" for row in chosen.values()),
        "unresolved_files": [str(source_by_id[file_id]) for file_id in pending],
        "validation_issues": [issue.as_dict() for issue in issues],
        "status": "partial" if issues or pending else "ok",
    }
    (output / "batch-summary.json").write_text(json.dumps(summary, indent=2) + "\n")
    print(json.dumps(summary, indent=2))
    return 2 if issues or pending else 0


if __name__ == "__main__":
    raise SystemExit(main())
