#!/usr/bin/env python3
"""Generate Assets/**/1920x360 from existing 3840/1920 masters (CLI / Pillow Lanczos).

Full-canvas art is stretched into 16:3 boxes (no letterbox). Digit cells are
uniformly resized. Run from anywhere:

  python DyzineFrame/tools/gen_1920x360_assets.py
"""
from __future__ import annotations

import json
import shutil
import sys
from pathlib import Path

from PIL import Image

ROOT = Path(__file__).resolve().parents[1]
ASSETS = ROOT / "Assets"
SRC_SHARED_3840 = ASSETS / "Shared" / "3840x1080"
SRC_SHARED_1920 = ASSETS / "Shared" / "1920x1080"
DST_SHARED = ASSETS / "Shared" / "1920x360"
RES = "1920x360"

# 3840 FR 2534x1080 → half width, full strip height
FR_W, FR_H = 1267, 360
BG_W, BG_H = 1920, 360
DIGIT_W, DIGIT_H = 120, 220
DOLLAR_W = 127
PUNCT_W = 45


def _resize(src: Path, dst: Path, size: tuple[int, int]) -> None:
    dst.parent.mkdir(parents=True, exist_ok=True)
    with Image.open(src) as im:
        out = im.convert("RGBA") if im.mode in ("P", "LA") else im
        if out.mode not in ("RGB", "RGBA"):
            out = out.convert("RGBA")
        scaled = out.resize(size, Image.Resampling.LANCZOS)
        if dst.suffix.lower() in (".jpg", ".jpeg") and scaled.mode == "RGBA":
            scaled = scaled.convert("RGB")
        scaled.save(dst)
    print(f"  {dst.relative_to(ASSETS)}  ({size[0]}x{size[1]})")


def _copy_odometer_block(src_layout: dict) -> dict:
    return json.loads(json.dumps(src_layout.get("odometer") or {}))


def write_layout() -> Path:
    src = json.loads((SRC_SHARED_3840 / "layout.json").read_text(encoding="utf-8"))
    # Scale strip cells from 3840 → strip height ratio 360/1080
    sy = 360 / 1080
    sx = 1920 / 3840
    cells = []
    for cell in (src.get("digit_strip") or {}).get("cells") or []:
        c = dict(cell)
        c["x"] = int(round(c["x"] * sx))
        c["y"] = int(round(c["y"] * sy))
        c["w"] = max(1, int(round(c["w"] * sx)))
        c["h"] = max(1, int(round(c["h"] * sy)))
        cells.append(c)

    doc = {
        "resolution": RES,
        "screen": [BG_W, BG_H],
        "frame_anchor": [648, 0],
        "display_scale": 1.0,
        "digit_cell": {"w": DIGIT_W, "h": DIGIT_H},
        "digit_strip": {
            "orientation": "vertical",
            "digit_order": "0_at_top",
            "cells": cells,
        },
        "digit_slots": [],
        "symbol_slots": [],
        "use_template_screen_coords": True,
        "aligned_cells": {
            "anchor_right": 1850,
            "anchor_bottom": 320,
        },
        "odometer": _copy_odometer_block(src),
    }
    DST_SHARED.mkdir(parents=True, exist_ok=True)
    path = DST_SHARED / "layout.json"
    path.write_text(json.dumps(doc, indent=2) + "\n", encoding="utf-8")
    print(f"  {path.relative_to(ASSETS)}")
    return path


def gen_shared() -> None:
    print("Shared/1920x360")
    DST_SHARED.mkdir(parents=True, exist_ok=True)
    fr = SRC_SHARED_3840 / "FR.png"
    if fr.is_file():
        _resize(fr, DST_SHARED / "FR.png", (FR_W, FR_H))
    splash = SRC_SHARED_3840 / "splash1.png"
    if splash.is_file():
        _resize(splash, DST_SHARED / "splash1.png", (BG_W, BG_H))
    wall = SRC_SHARED_3840 / "pot_dyzine_logo.png"
    if wall.is_file():
        _resize(wall, DST_SHARED / "pot_dyzine_logo.png", (BG_W, BG_H))
    # Also keep a POG-style name for pi_wallpaper fallbacks
    pog_src = SRC_SHARED_1920 / "POG_Render_02.png"
    if pog_src.is_file():
        _resize(pog_src, DST_SHARED / "POG_Render_02.png", (BG_W, BG_H))

    for d in range(10):
        src = SRC_SHARED_1920 / f"{d}_175x320.png"
        if src.is_file():
            _resize(src, DST_SHARED / f"{d}_{DIGIT_W}x{DIGIT_H}.png", (DIGIT_W, DIGIT_H))
    dollar = SRC_SHARED_1920 / "$_185x320.png"
    if dollar.is_file():
        _resize(dollar, DST_SHARED / f"$_{DOLLAR_W}x{DIGIT_H}.png", (DOLLAR_W, DIGIT_H))
    for name, sw in (("comma", 66), ("decimal", 66)):
        src = SRC_SHARED_1920 / f"{name}_{sw}x320.png"
        if src.is_file():
            _resize(src, DST_SHARED / f"{name}_{PUNCT_W}x{DIGIT_H}.png", (PUNCT_W, DIGIT_H))

    write_layout()

    fw = SRC_SHARED_3840 / "fireworks.mp4"
    if fw.is_file():
        dst = DST_SHARED / "fireworks.mp4"
        if shutil.which("ffmpeg"):
            import subprocess

            print(f"  encoding fireworks -> {dst.relative_to(ASSETS)}")
            subprocess.run(
                [
                    "ffmpeg",
                    "-y",
                    "-i",
                    str(fw),
                    "-vf",
                    f"scale={BG_W}:{BG_H}",
                    "-an",
                    "-c:v",
                    "libx264",
                    "-pix_fmt",
                    "yuv420p",
                    "-crf",
                    "23",
                    "-preset",
                    "fast",
                    str(dst),
                ],
                check=False,
            )
        else:
            print("  SKIP fireworks (ffmpeg not found)")


def gen_games() -> None:
    for game_dir in sorted(ASSETS.iterdir()):
        if not game_dir.is_dir() or game_dir.name == "Shared":
            continue
        if not game_dir.name.isdigit():
            continue
        src_dir = game_dir / "3840x1080"
        if not src_dir.is_dir():
            print(f"SKIP game {game_dir.name}: no 3840x1080")
            continue
        bgs = list(src_dir.glob(f"{game_dir.name}-BG*"))
        if not bgs:
            print(f"SKIP game {game_dir.name}: no BG")
            continue
        src_bg = bgs[0]
        dst_dir = game_dir / RES
        dst_bg = dst_dir / f"{game_dir.name}-BG.png"
        print(f"Game {game_dir.name}")
        _resize(src_bg, dst_bg, (BG_W, BG_H))


def main() -> int:
    if not SRC_SHARED_3840.is_dir():
        print(f"Missing {SRC_SHARED_3840}", file=sys.stderr)
        return 1
    gen_shared()
    gen_games()
    print("DONE")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
