#!/usr/bin/env python3
"""从 Cocos 贴图 + Unity pivot 生成 tile-display-meta.json（裁剪后可见尺寸）。"""
from __future__ import annotations

import json
import re
import struct
from pathlib import Path

UNITY_THEMES = {
    "silu": "silu",
    "snow": "snow",
    "sanxing": "sanxing",
    "chinese": "Chinese",
    "numMan": "numMan",
    "redarmy": "redArmy",
    "default": "Level",
}

TILE_NAMES = [
    "Baseblock",
    "JumpBlock",
    "WallBlock",
    "kuai11",
    "Decor23",
    "素材切图-23",
    "素材切图2-23",
    "小游戏素材红色_03",
]


def png_size(path: Path) -> tuple[int, int]:
    with path.open("rb") as f:
        f.read(16)
        return struct.unpack(">II", f.read(8))


def alpha_bbox(png_path: Path) -> tuple[int, int, int, int] | None:
    try:
        from PIL import Image
    except ImportError:
        return None
    try:
        img = Image.open(png_path).convert("RGBA")
        return img.getbbox()
    except Exception:
        return None


def read_unity_sprite_meta(meta_path: Path) -> dict | None:
    if not meta_path.is_file():
        return None
    text = meta_path.read_text(encoding="utf-8")
    pivot = re.search(r"spritePivot:\s*\{x:\s*([^,]+),\s*y:\s*([^}]+)\}", text)
    ppu = re.search(r"spritePixelsToUnits:\s*(\d+(?:\.\d+)?)", text)
    if not pivot:
        return None
    return {
        "pivotX": float(pivot.group(1)),
        "pivotY": float(pivot.group(2)),
        "ppu": float(ppu.group(1)) if ppu else 100.0,
    }


def resolve_draw_rect(
    png_path: Path,
    full_w: int,
    full_h: int,
    pivot_x: float,
    pivot_y: float,
    tile_name: str,
) -> dict:
    bbox = alpha_bbox(png_path)
    if not bbox:
        return {
            "width": full_w,
            "height": full_h,
            "pivotX": pivot_x,
            "pivotY": pivot_y,
            "fitMul": 1.0,
        }
    left, top, right, bottom = bbox
    tw, th = right - left, bottom - top
    if tw <= 0 or th <= 0 or (tw >= full_w and th >= full_h):
        return {
            "width": full_w,
            "height": full_h,
            "pivotX": pivot_x,
            "pivotY": pivot_y,
            "fitMul": 1.0,
        }

    pivot_bottom = pivot_y * full_h
    trim_bottom = full_h - bottom
    pivot_bottom_trim = pivot_bottom - trim_bottom
    meta_pivot_y = max(0.0, min(1.0, pivot_bottom_trim / th))
    meta_pivot_x = max(0.0, min(1.0, (pivot_x * full_w - left) / tw))

    fit_mul = 1.0
    out_pivot_y = meta_pivot_y
    # kuai11 篝火：底座贴齐地面格，略放大消除缝隙
    if tile_name == "kuai11":
        fit_mul = 1.12
        # 底座在裁剪图底部，pivot 放低使底座对齐格子
        out_pivot_y = max(0.28, min(0.42, meta_pivot_y * 0.45))

    return {
        "width": tw,
        "height": th,
        "pivotX": round(meta_pivot_x, 4),
        "pivotY": round(out_pivot_y, 4),
        "fitMul": fit_mul,
    }


def build_theme(cocos_tex: Path, unity_tex: Path, unity_folder: str, cocos_key: str) -> dict:
    theme_dir = unity_tex if unity_folder == "Level" else unity_tex / unity_folder
    cocos_dir = cocos_tex if cocos_key == "default" else cocos_tex / cocos_key
    tiles: dict[str, dict] = {}
    for name in TILE_NAMES:
        png = cocos_dir / f"{name}.png"
        if not png.is_file():
            if name == "Decor23":
                png = cocos_dir / "素材切图-23.png"
            elif name == "素材切图-23":
                png = cocos_dir / "Decor23.png"
        if not png.is_file():
            continue
        unity_png = theme_dir / png.name
        meta = read_unity_sprite_meta(unity_png.with_suffix(".png.meta"))
        if not meta:
            continue
        w, h = png_size(png)
        draw = resolve_draw_rect(png, w, h, meta["pivotX"], meta["pivotY"], name)
        tiles[name] = {**draw, "ppu": meta["ppu"]}
    return tiles


def main():
    import argparse

    ap = argparse.ArgumentParser()
    ap.add_argument("--unity-root", required=True)
    ap.add_argument("--out", default="assets/resources/theme/tile-display-meta.json")
    args = ap.parse_args()

    project = Path(__file__).resolve().parent.parent
    unity_tex = Path(args.unity_root) / "Assets" / "Texture"
    cocos_tex = project / "assets/resources/textures"
    themes: dict[str, dict] = {}
    for cocos_key, unity_folder in UNITY_THEMES.items():
        tiles = build_theme(cocos_tex, unity_tex, unity_folder, cocos_key)
        if tiles:
            themes[cocos_key] = tiles
            print(f"  {cocos_key}: {len(tiles)} tiles")

    out = project / args.out
    out.parent.mkdir(parents=True, exist_ok=True)
    payload = {"version": 1, "themes": themes}
    out.write_text(json.dumps(payload, indent=2, ensure_ascii=False), encoding="utf-8")
    print(f"Wrote -> {out}")


if __name__ == "__main__":
    main()
