#!/usr/bin/env python3
from __future__ import annotations

import datetime as dt
import hashlib
import json
import os
from pathlib import Path
import subprocess
import sys

ROOT = Path("/data/video-pipeline/HaTramAudio/project/016-Nguoi-Giu-Am-Thanh-Cuoi-Cung")
PROJECT = ROOT.name
RUN = "run-20260720T233725Z-24504f17"
OWNER = "zoro"
CANON_SHA = "fae6fce617a14dc4f8b3bd52968cc688a456c45a60bc2ed7701ccd8164875e02"
PROMPTS = ROOT / "work/artwork/image-prompts.json"
GENERATOR = Path.home() / ".hermes/skills/content-creation/tao-anh/scripts/generate_image.py"
MAPPING = {
    "intro_poster_16x9": ROOT / "image/provider/intro-poster-provider.png",
    "left_panel_portrait": ROOT / "image/provider/left-panel-provider.png",
    "right_panel_portrait": ROOT / "image/provider/right-panel-provider.png",
}


def now() -> str:
    return dt.datetime.now(dt.timezone.utc).isoformat().replace("+00:00", "Z")


def digest(path: Path) -> str:
    h = hashlib.sha256()
    with path.open("rb") as f:
        while block := f.read(8 * 1024 * 1024):
            h.update(block)
    return h.hexdigest()


def atomic(path: Path, obj: dict) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    tmp = path.with_suffix(path.suffix + ".tmp")
    tmp.write_text(json.dumps(obj, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
    os.replace(tmp, path)


def guard() -> None:
    lock = json.loads((ROOT / ".ownership-lock.json").read_text(encoding="utf-8"))
    if (lock.get("project_id"), lock.get("run_id"), lock.get("owner"), lock.get("status")) != (PROJECT, RUN, OWNER, "main_session_pipeline"):
        raise RuntimeError("ownership mismatch")
    if digest(ROOT / "story/story-canon.txt") != CANON_SHA:
        raise RuntimeError("canon drift")
    tts = json.loads((ROOT / "script/tts-manifest.json").read_text(encoding="utf-8"))
    if tts.get("status") != "completed" or not tts.get("verified") or tts.get("source_canon_sha256") != CANON_SHA:
        raise RuntimeError("TTS Gate is not terminal verified")


def main() -> None:
    guard()
    bundle = json.loads(PROMPTS.read_text(encoding="utf-8"))
    if bundle.get("source_canon_sha256") != CANON_SHA:
        raise RuntimeError("prompt bundle canon mismatch")
    for rel, expected in bundle.get("authority_sha256", {}).items():
        if digest(ROOT / rel) != expected:
            raise RuntimeError(f"authority drift: {rel}")
    receipts = []
    for key, output in MAPPING.items():
        guard()
        prompt = bundle["prompts"][key]
        prompt_sha = hashlib.sha256(prompt.encode("utf-8")).hexdigest()
        receipt_path = ROOT / f"log/artwork-{key}.json"
        if receipt_path.exists() and output.exists():
            old = json.loads(receipt_path.read_text(encoding="utf-8"))
            if old.get("status") == "generated" and old.get("prompt_sha256") == prompt_sha and old.get("artifact_sha256") == digest(output):
                receipts.append(old)
                continue
        if output.exists():
            raise RuntimeError(f"unreceipted artwork exists: {output}")
        attempt = {
            "schema_version": 1,
            "project_id": PROJECT,
            "run_id": RUN,
            "status": "requesting",
            "verified": False,
            "prompt_key": key,
            "prompt_sha256": prompt_sha,
            "source_canon_sha256": CANON_SHA,
            "output": str(output),
            "created_at": now(),
        }
        atomic(receipt_path, attempt)
        output.parent.mkdir(parents=True, exist_ok=True)
        result = subprocess.run(
            [sys.executable, str(GENERATOR), "--prompt", prompt, "--output", str(output), "--n", "1", "--size", "auto", "--quality", "auto", "--background", "auto", "--detail", "high", "--format", "png", "--timeout", "600"],
            text=True,
            capture_output=True,
            timeout=720,
        )
        if result.returncode != 0:
            attempt.update(status="failed", error=(result.stderr or result.stdout)[-1500:], updated_at=now())
            atomic(receipt_path, attempt)
            raise RuntimeError(f"provider failed for {key}")
        if not output.exists() or output.stat().st_size < 1024 or output.read_bytes()[:8] != b"\x89PNG\r\n\x1a\n":
            raise RuntimeError(f"invalid PNG output for {key}")
        attempt.update(status="generated", technical_verified=True, verified=False, artifact_sha256=digest(output), bytes=output.stat().st_size, provider_requests=1, updated_at=now())
        atomic(receipt_path, attempt)
        receipts.append(attempt)
    print(json.dumps({"status": "generated_awaiting_visual_qa", "artifacts": [{"key": x["prompt_key"], "sha256": x["artifact_sha256"]} for x in receipts]}))


if __name__ == "__main__":
    main()
