#!/usr/bin/env python3
import hashlib
import json
import sys
from datetime import datetime, timezone
from pathlib import Path

from PIL import Image

PROJECT = Path(__file__).resolve().parents[1]
IMAGE_DIR = PROJECT / "image"
GENERATION = PROJECT / "log/image-generation.json"
BRIEF = IMAGE_DIR / "image-brief.json"
MANIFEST = IMAGE_DIR / "layout-manifest.json"


def sha(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 fit_pad(source, size, background=(16, 24, 32)):
    image = Image.open(source).convert("RGB")
    image.thumbnail(size, Image.Resampling.LANCZOS)
    canvas = Image.new("RGB", size, background)
    x = (size[0] - image.width) // 2
    y = (size[1] - image.height) // 2
    canvas.paste(image, (x, y))
    return canvas


def save_atomic(image, path):
    temp = path.with_suffix(".part.png")
    image.save(temp, format="PNG", optimize=True)
    temp.replace(path)


def main():
    if not GENERATION.is_file() or not BRIEF.is_file():
        raise RuntimeError("image generation receipt/brief missing")
    generation = json.loads(GENERATION.read_text(encoding="utf-8"))
    brief = json.loads(BRIEF.read_text(encoding="utf-8"))
    canon = brief.get("source_canon_sha256")
    if generation.get("verified") is not True or generation.get("source_canon_sha256") != canon or generation.get("provider_rendered_text_only") is not True:
        raise RuntimeError("image generation authority mismatch")
    masters = {
        "intro": IMAGE_DIR / "intro-poster-master.png",
        "left": IMAGE_DIR / "left-panel-master.png",
        "right": IMAGE_DIR / "right-panel-master.png",
    }
    expected = {row["asset"]: row for row in generation.get("assets", [])}
    aliases = {"intro": "intro_poster", "left": "left_panel", "right": "right_panel"}
    for name, path in masters.items():
        row = expected.get(aliases[name], {})
        if not path.is_file() or row.get("sha256") != sha(path) or row.get("text_rendered_by_provider") is not True or row.get("postprocessed_text") is not False:
            raise RuntimeError(f"master image mismatch: {path}")
    poster = IMAGE_DIR / "intro-poster-1920x1080.png"
    left = IMAGE_DIR / "left-panel-656x1080.png"
    right = IMAGE_DIR / "right-panel-656x1080.png"
    layout = IMAGE_DIR / "layout-1920x1080.png"
    save_atomic(fit_pad(masters["intro"], (1920, 1080)), poster)
    save_atomic(fit_pad(masters["left"], (656, 1080)), left)
    save_atomic(fit_pad(masters["right"], (656, 1080)), right)
    composite = Image.new("RGB", (1920, 1080), (16, 24, 32))
    with Image.open(left).convert("RGB") as left_image, Image.open(right).convert("RGB") as right_image:
        composite.paste(left_image, (0, 0))
        composite.paste(right_image, (1264, 0))
    save_atomic(composite, layout)
    dimensions = {}
    for path, expected_size in ((poster, (1920, 1080)), (left, (656, 1080)), (right, (656, 1080)), (layout, (1920, 1080))):
        with Image.open(path) as image:
            dimensions[str(path.relative_to(PROJECT))] = list(image.size)
            if image.size != expected_size:
                raise RuntimeError(f"dimension mismatch: {path}")
    assets = {}
    for path in (*masters.values(), poster, left, right, layout):
        assets[str(path.relative_to(PROJECT))] = {"bytes": path.stat().st_size, "sha256": sha(path)}
    receipt = {
        "version": 1, "verified": True, "source_canon_sha256": canon,
        "operation": "local static-image resize/pad/paste only",
        "local_static_image_composition_allowed": True,
        "text_rendered_by_provider": True, "text_overlay_applied": False,
        "video_created_or_modified": False,
        "canvas": {"width": 1920, "height": 1080},
        "regions": {"left": {"x": 0, "width": 656}, "center": {"x": 656, "width": 608, "clean": True}, "right": {"x": 1264, "width": 656}},
        "dimensions": dimensions, "assets": assets,
        "visual_qa": {"required": True, "status": "pending", "verified": False},
        "created_at": datetime.now(timezone.utc).isoformat(),
    }
    MANIFEST.write_text(json.dumps(receipt, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
    print(json.dumps({"verified": True, "layout": str(layout), "text_overlay_applied": False}, ensure_ascii=False))
    return 0


if __name__ == "__main__":
    try:
        sys.exit(main())
    except Exception as exc:
        print(f"Layout blocked: {exc}", file=sys.stderr)
        sys.exit(1)
