#!/usr/bin/env python3
"""Запускает все обязательные проверки одним вызовом и не скрывает ни одного отказа.

Каждая проверка пишет свой JSON-отчёт и свой лог. Сводка перечисляет провалившиеся
шаги с их собственным объяснением, а не просто «failed» — иначе приходится читать
четыре лога, чтобы понять, что именно не так.
"""
from __future__ import annotations

import argparse
import json
import subprocess
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent))

from skill_config import FONT_PACK, LOUDNESS, emit, utf8_stdout  # noqa: E402

HERE = Path(__file__).resolve().parent


def run(command: list[str], log: Path) -> dict:
    completed = subprocess.run(command, capture_output=True, text=True, errors="replace")
    log.parent.mkdir(parents=True, exist_ok=True)
    log.write_text((completed.stdout or "") + "\n" + (completed.stderr or ""),
                   encoding="utf-8")
    summary = None
    text = completed.stdout or ""
    if "{" in text:
        try:
            summary = json.loads(text[text.index("{"):])
        except json.JSONDecodeError:
            summary = None
    return {
        "step": Path(command[1]).stem if len(command) > 1 else command[0],
        "returncode": completed.returncode,
        "log": str(log),
        "errors": (summary or {}).get("errors") or [],
        "warnings": (summary or {}).get("warnings") or [],
        "status": (summary or {}).get("status"),
    }


def main() -> None:
    utf8_stdout()
    parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
    parser.add_argument("video")
    parser.add_argument("timeline")
    parser.add_argument("caption_map")
    parser.add_argument("--canvas", default="reels")
    parser.add_argument("--loudness", default="reels", choices=list(LOUDNESS))
    parser.add_argument("--fonts-dir", default=str(FONT_PACK))
    parser.add_argument("--report-dir", default="quality")
    parser.add_argument("--skip-fonts", action="store_true",
                        help="Пропустить аудит шрифтового пака (он не зависит от рендера)")
    parser.add_argument("--skip-checkpoints", action="store_true")
    args = parser.parse_args()

    out = Path(args.report_dir)
    out.mkdir(parents=True, exist_ok=True)
    python = sys.executable

    jobs: list[tuple[list[str], Path]] = [
        ([python, str(HERE / "validate_sync.py"), args.timeline, args.caption_map,
          "--report", str(out / "sync.json")], out / "sync.log"),
        ([python, str(HERE / "validate_full_end.py"), args.video, args.timeline,
          "--report", str(out / "full_end.json")], out / "full_end.log"),
        ([python, str(HERE / "validate_render.py"), args.video,
          "--timeline", args.timeline,
          "--report", str(out / "render.json")], out / "render.log"),
        ([python, str(HERE / "validate_delivery.py"), args.video,
          "--canvas", args.canvas, "--loudness", args.loudness,
          "--timeline", args.timeline, "--caption-map", args.caption_map,
          "--report", str(out / "delivery.json")], out / "delivery.log"),
    ]
    if not args.skip_fonts:
        jobs.append((
            [python, str(HERE / "font_audit.py"), args.fonts_dir, "--quiet",
             "--report", str(out / "fonts.json")],
            out / "fonts.log",
        ))
    if not args.skip_checkpoints:
        jobs.append((
            [python, str(HERE / "render_word_checkpoints.py"), args.video, args.timeline,
             "--out-dir", str(out / "checkpoints")],
            out / "checkpoints.log",
        ))

    results = [run(command, log) for command, log in jobs]
    failed = [item for item in results if item["returncode"]]

    summary = {
        "status": "failed" if failed else "ok",
        "video": args.video,
        "canvas": args.canvas,
        "loudness_target": args.loudness,
        "checks": [
            {"step": item["step"], "ok": item["returncode"] == 0,
             "status": item["status"], "log": item["log"],
             "errors": item["errors"][:6], "warnings": item["warnings"][:4]}
            for item in results
        ],
        "failed_steps": [item["step"] for item in failed],
        "all_errors": [error for item in failed for error in item["errors"]][:20],
        "report_dir": str(out.resolve()),
        "what_to_do": (
            "Каждый шаг оставил свой JSON рядом с логом. Исправляй причину, а не "
            "порог: ослабленный порог не делает монтаж лучше."
            if failed else
            "Все ворота пройдены. Переименуй .partial.mp4 в финальное имя с версией."
        ),
    }
    (out / "summary.json").write_text(
        json.dumps(summary, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
    emit(summary)
    if failed:
        raise SystemExit(2)


if __name__ == "__main__":
    main()
