#!/usr/bin/env python3
import hashlib
import json
import os
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
MANIFEST = ROOT / "script/project-manifest.json"
EXPECTED_CANDIDATE = "b4f8136eb6ac3ef29c2c6036ad0fc73726e8317ce0f8205a1c4bf1cb83da230d"
REQUIRED = {
    "image_prompts": "script/image-prompts.json",
    "intro_poster_master": "image/intro-poster-master.png",
    "intro_poster": "image/intro-poster-1920x1080.png",
    "layout_manifest": "script/layout-manifest.json",
    "tts_manifest": "script/tts-manifest.json",
    "tts_receipt": "log/tts.json",
    "intro_voice": "audio/intro-voice.wav",
    "intro_silence": "audio/intro-silence-2s.wav",
}


def sha256(path):
    digest = hashlib.sha256()
    with path.open("rb") as handle:
        for block in iter(lambda: handle.read(8 * 1024 * 1024), b""):
            digest.update(block)
    return digest.hexdigest()


def atomic_json(path, value):
    part = path.with_suffix(path.suffix + ".part")
    part.write_text(json.dumps(value, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
    os.replace(part, path)


def main():
    manifest = json.loads(MANIFEST.read_text(encoding="utf-8"))
    if manifest.get("active_run") != "run-002" or manifest.get("steps", {}).get("story") != "completed":
        raise RuntimeError("production routing blocked until active run-002 Story Promotion Gate PASS")
    if not isinstance(EXPECTED_CANDIDATE, str) or not EXPECTED_CANDIDATE:
        raise RuntimeError("run-002 production routing hash is not frozen")
    if manifest.get("candidate_sha256") != EXPECTED_CANDIDATE:
        raise RuntimeError("candidate hash drift")
    semantic_path = ROOT / manifest["active_paths"]["semantic_review"]
    semantic = json.loads(semantic_path.read_text(encoding="utf-8"))
    if semantic.get("verified") is not True or semantic.get("candidate_sha256") != EXPECTED_CANDIDATE:
        raise RuntimeError("semantic audit not terminal on exact candidate")
    if semantic.get("semantic_verdict") != "PASS" or semantic.get("provenance_verdict") != "PASS" or semantic.get("stale") is not False:
        raise RuntimeError("semantic/provenance gate not PASS")
    active = manifest["active_paths"]
    conflicts = {key: active[key] for key, value in REQUIRED.items() if key in active and active[key] != value}
    if conflicts:
        raise RuntimeError(f"active path alias conflicts: {conflicts}")
    active.update(REQUIRED)
    for key, rel in active.items():
        path = (ROOT / rel).resolve()
        path.relative_to(ROOT.resolve())
    manifest["production_routing"] = {
        "status": "completed", "verified": True, "aliases_added": REQUIRED,
        "semantic_review_path": str(semantic_path.relative_to(ROOT)),
        "semantic_review_sha256": sha256(semantic_path),
    }
    atomic_json(MANIFEST, manifest)
    print(json.dumps({"status": "completed", "verified": True, "aliases_added": sorted(REQUIRED)}, ensure_ascii=False))


if __name__ == "__main__":
    main()
