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

import argparse
import hashlib
import json
from pathlib import Path

ROOT = Path("/data/video-pipeline/HaTramAudio/project/015-Buc-Tranh-Khong-Co-Chu-Ky")
PROJECT_ID = "015-Buc-Tranh-Khong-Co-Chu-Ky"
RUN_ID = "run-20260720T181013Z-3b1f33ef"
OWNER = "Levy"


def sha(path: Path) -> str:
    h = hashlib.sha256()
    with path.open("rb") as f:
        for block in iter(lambda: f.read(8 * 1024 * 1024), b""):
            h.update(block)
    return h.hexdigest()


def guard() -> None:
    lock = json.loads((ROOT / ".ownership-lock.json").read_text(encoding="utf-8"))
    for key, value in {"project_id": PROJECT_ID, "run_id": RUN_ID, "owner": OWNER}.items():
        if lock.get(key) != value:
            raise RuntimeError(f"ownership mismatch: {key}")


def read_verified(path: Path, allowed_statuses: tuple[str, ...] = ("completed",)) -> dict:
    data = json.loads(path.read_text(encoding="utf-8"))
    if data.get("project_id", PROJECT_ID) != PROJECT_ID or data.get("run_id") != RUN_ID:
        raise RuntimeError(f"receipt identity mismatch: {path}")
    if data.get("status") not in allowed_statuses or data.get("verified") is not True:
        raise RuntimeError(f"receipt not terminal/verified: {path}")
    return data


def ensure_hash(path: Path, expected: str, label: str) -> None:
    if not path.is_file() or sha(path) != expected:
        raise RuntimeError(f"{label} artifact hash mismatch")


def write_request(stage: str, payload: dict, bindings: dict) -> None:
    guard()
    work = ROOT / "work" / stage / RUN_ID
    work.mkdir(parents=True, exist_ok=True)
    request_path = work / "request.json"
    binding_path = work / "request-bindings.json"
    request_path.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
    bindings["request_sha256"] = sha(request_path)
    binding_path.write_text(json.dumps(bindings, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
    print(json.dumps({"stage": stage, "request": str(request_path), "request_sha256": bindings["request_sha256"]}, ensure_ascii=False))


def footage() -> None:
    tts = read_verified(ROOT / "script" / "tts-manifest.json")
    layout = read_verified(ROOT / "image" / "layout-manifest.json")
    promotion = read_verified(ROOT / "script" / "promotion-report.json", ("passed", "completed", "completed_content_only"))
    canon_hash = promotion.get("canon_sha256") or promotion.get("source_canon_sha256")
    if tts.get("source_canon_sha256") != canon_hash or layout.get("source_canon_sha256") != canon_hash:
        raise RuntimeError("footage upstream canon mismatch")
    audio = ROOT / "audio" / "story-full.wav"
    layout_path = ROOT / "image" / "normalized" / "layout-1920x1080.png"
    ensure_hash(audio, tts["output_sha256"], "TTS")
    ensure_hash(layout_path, layout["layout_sha256"], "layout")
    payload = {
        "layout": str(layout_path),
        "footage_dir": "/data/video-pipeline/GacMaiAudio/footage",
        "pattern": "*.mp4",
        "recursive": True,
        "audio": str(audio),
        "output": str(ROOT / "output" / "footage" / "footage.mp4"),
        "seed": 2026072015,
        "overwrite": False,
        "width": 1920,
        "height": 1080,
        "fps": 30,
        "center_x": 656,
        "center_y": 0,
        "center_width": 608,
        "center_height": 1080,
        "video_encoder": "h264_nvenc",
        "preset": "p4",
        "cq": 21,
    }
    write_request("footage", payload, {
        "project_id": PROJECT_ID,
        "run_id": RUN_ID,
        "source_canon_sha256": canon_hash,
        "source_audio_sha256": tts["output_sha256"],
        "source_layout_sha256": layout["layout_sha256"],
        "output": payload["output"],
    })


def final() -> None:
    intro = read_verified(ROOT / "log" / "intro-render.json")
    footage_receipt = read_verified(ROOT / "log" / "footage-render.json")
    intro_path = ROOT / "output" / "intro" / "intro.mp4"
    footage_path = ROOT / "output" / "footage" / "footage.mp4"
    ensure_hash(intro_path, intro["artifact_sha256"], "intro")
    ensure_hash(footage_path, footage_receipt["artifact_sha256"], "footage")
    if not footage_receipt.get("technical_qa", {}).get("verified") or footage_receipt.get("content_qa") != "not_run_by_policy":
        raise RuntimeError("footage technical/no-content-QA contract is not verified")
    if intro["source_canon_sha256"] != footage_receipt["source_canon_sha256"]:
        raise RuntimeError("final upstream canon mismatch")
    payload = {
        "intro_video_path": str(intro_path),
        "footage_video_path": str(footage_path),
        "output_video_path": str(ROOT / "output" / "final.mp4"),
        "overwrite": False,
        "fps": 30,
        "width": 1920,
        "height": 1080,
        "video_encoder": "h264_nvenc",
        "preset": "p4",
        "cq": 21,
    }
    write_request("final", payload, {
        "project_id": PROJECT_ID,
        "run_id": RUN_ID,
        "source_canon_sha256": intro["source_canon_sha256"],
        "source_intro_sha256": intro["artifact_sha256"],
        "source_footage_sha256": footage_receipt["artifact_sha256"],
        "output": payload["output_video_path"],
    })


def transcode() -> None:
    final_receipt = read_verified(ROOT / "log" / "final-render.json")
    final_path = ROOT / "output" / "final.mp4"
    ensure_hash(final_path, final_receipt["artifact_sha256"], "final")
    if not final_receipt.get("technical_qa", {}).get("verified") or final_receipt.get("content_qa") != "not_run_by_policy":
        raise RuntimeError("final technical/no-content-QA contract is not verified")
    payload = {
        "input_video_path": str(final_path),
        "output_video_path": str(ROOT / "output" / "final-upload.mp4"),
        "target_output_bytes": 800000000,
        "max_output_bytes": 1000000000,
        "width": 1920,
        "height": 1080,
        "fps": 30,
        "audio_bitrate_kbps": 96,
        "overwrite": False,
    }
    write_request("transcode", payload, {
        "project_id": PROJECT_ID,
        "run_id": RUN_ID,
        "source_canon_sha256": final_receipt["source_canon_sha256"],
        "source_final_sha256": final_receipt["artifact_sha256"],
        "output": payload["output_video_path"],
    })


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("stage", choices=["footage", "final", "transcode"])
    args = parser.parse_args()
    guard()
    {"footage": footage, "final": final, "transcode": transcode}[args.stage]()


if __name__ == "__main__":
    main()
