#!/usr/bin/env python3
"""从 Unity Level{N}.prefab 解析 Tilemap（Ground / Border）格子数据。

层级锁定：
  - Baseblock / JumpBlock → ground（地砖属性）
  - WallBlock / 墙饰 → border（墙砖属性）
不再用死板的 tileIndex==1 → JumpBlock。
"""
from __future__ import annotations

import re
from functools import lru_cache
from pathlib import Path

GROUND_TILES = frozenset({"Baseblock", "JumpBlock"})
BORDER_DECOR = frozenset(
    {
        "WallBlock",
        "kuai11",
        "Decor23",
        "素材切图-23",
        "素材切图2-23",
        "小游戏素材红色_03",
    }
)


def parse_tilemap_layer(text: str, layer_name: str) -> dict[str, int]:
    """返回格子 → 该 Tilemap 本地 m_TileIndex。"""
    parts = re.split(r"(?=--- !u!1 &)", text)
    for part in parts:
        if f"m_Name: {layer_name}" not in part or "Tilemap:" not in part:
            continue
        tiles: dict[str, int] = {}
        for m in re.finditer(
            r"first: \{x: (-?\d+), y: (-?\d+), z: 0\}[\s\S]*?m_TileIndex: (\d+)",
            part,
        ):
            x, y, ti = int(m.group(1)), int(m.group(2)), int(m.group(3))
            tiles[f"{x},{y}"] = ti
        return tiles
    return {}


def _tilemap_part(text: str, layer_name: str) -> str | None:
    parts = re.split(r"(?=--- !u!1 &)", text)
    for part in parts:
        if f"m_Name: {layer_name}" not in part or "Tilemap:" not in part:
            continue
        return part
    return None


def _tile_asset_guids(tilemap_part: str) -> list[str | None]:
    """按 m_TileAssetArray 顺序解析 guid（空槽为 None）。"""
    assets: list[str | None] = []
    in_arr = False
    for line in tilemap_part.splitlines():
        if "m_TileAssetArray:" in line:
            in_arr = True
            continue
        if in_arr and ("m_TileSpriteArray" in line or "m_AnimationFrameRate" in line):
            break
        if not in_arr:
            continue
        if "guid:" in line:
            m = re.search(r"guid: ([a-f0-9]+)", line)
            assets.append(m.group(1) if m else None)
        elif "m_Data: {fileID: 0}" in line:
            assets.append(None)
    return assets


@lru_cache(maxsize=1)
def _guid_to_tile_name(unity_texture_root: str) -> dict[str, str]:
    root = Path(unity_texture_root)
    out: dict[str, str] = {}
    if not root.is_dir():
        return out
    for meta in root.rglob("*.asset.meta"):
        try:
            text = meta.read_text(encoding="utf-8", errors="ignore")
        except OSError:
            continue
        m = re.search(r"^guid: ([a-f0-9]+)", text, re.M)
        if m:
            out[m.group(1)] = meta.name.replace(".asset.meta", "")
    return out


def tile_asset_names(text: str, layer_name: str, unity_texture_root: Path | None = None) -> list[str | None]:
    part = _tilemap_part(text, layer_name)
    if not part:
        return []
    guids = _tile_asset_guids(part)
    if unity_texture_root is None:
        # 默认：prefab 所在工程 Assets/Texture
        return [None] * len(guids)
    mapping = _guid_to_tile_name(str(unity_texture_root))
    return [mapping.get(g) if g else None for g in guids]


def normalize_ground_tile(name: str | None) -> str:
    return "JumpBlock" if name == "JumpBlock" else "Baseblock"


def normalize_border_tile(name: str | None) -> str:
    if not name or name in GROUND_TILES:
        return "WallBlock"
    if name in BORDER_DECOR:
        return name
    # 其它墙饰保留文件名，禁止地砖名漏到墙层
    return name


def _resolve_name(assets: list[str | None], tile_index: int) -> str | None:
    if 0 <= tile_index < len(assets):
        return assets[tile_index]
    return None


def parse_level_prefab(prefab_path: Path, unity_texture_root: Path | None = None) -> dict:
    if not prefab_path.is_file():
        return {}
    text = prefab_path.read_text(encoding="utf-8")
    g_raw = parse_tilemap_layer(text, "Ground")
    b_raw = parse_tilemap_layer(text, "Border")
    if not g_raw and not b_raw:
        return {}

    if unity_texture_root is None:
        # Level91601.prefab → …/Assets/Prefabs/Level → …/Assets/Texture
        unity_texture_root = prefab_path.resolve().parents[2] / "Texture"

    g_assets = tile_asset_names(text, "Ground", unity_texture_root)
    b_assets = tile_asset_names(text, "Border", unity_texture_root)

    ground: dict[str, str] = {}
    border: dict[str, str] = {}

    # 按瓦片类型归层（层级固定）：地砖→Ground，墙/饰→Border
    for key, ti in g_raw.items():
        name = _resolve_name(g_assets, ti)
        if name in GROUND_TILES:
            ground[key] = normalize_ground_tile(name)
        else:
            border[key] = normalize_border_tile(name)

    for key, ti in b_raw.items():
        name = _resolve_name(b_assets, ti)
        if name in GROUND_TILES:
            ground[key] = normalize_ground_tile(name)
        else:
            border[key] = normalize_border_tile(name)

    # 同格冲突：墙优先（不可走）
    for key in list(ground.keys()):
        if key in border:
            del ground[key]

    return {"ground": ground, "border": border}
