#!/usr/bin/env python3
"""Export battle-like event/dialogue resource candidates for the browser runtime."""
from __future__ import annotations

import argparse
import json
import re
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]
OUT = ROOT / "out"
BATTLE_RESOURCE_RE = re.compile(r"^btl_([a-z])([0-9]+)\.cns$")
MAP_TILESET_RE = re.compile(r"^map_([a-z])([0-9]+)\.cns$")


def js_json(data) -> str:
    return json.dumps(data, ensure_ascii=False, separators=(",", ":"))


def load_json(path: Path, fallback):
    if not path.exists():
        return fallback
    return json.loads(path.read_text(encoding="utf-8"))


def compact_text_lines(lines: list[dict], limit: int = 8) -> list[str]:
    result = []
    for row in lines:
        text = row.get("text") if isinstance(row, dict) else str(row)
        if text and text not in result:
            result.append(text)
        if len(result) >= limit:
            break
    return result


def sample_text(block: dict, text_lines: list[str]) -> str:
    sample = block.get("sampleText")
    if isinstance(sample, str):
        return sample
    if isinstance(sample, list):
        for row in sample:
            if isinstance(row, str) and row:
                return row
            if isinstance(row, dict) and row.get("text"):
                return str(row["text"])
    return text_lines[0] if text_lines else ""


def build_summary(event_dialogue_blocks: dict, battle_backgrounds: dict) -> dict:
    backgrounds = set(battle_backgrounds)
    candidates = []
    for block in event_dialogue_blocks.get("blocks") or []:
        resource_names = block.get("resourceNames") or []
        battle_resources = [
            name
            for name in resource_names
            if BATTLE_RESOURCE_RE.fullmatch(name) and Path(name).stem in backgrounds
        ]
        if not battle_resources:
            continue
        map_tilesets = [
            name
            for name in block.get("tilesets") or []
            if MAP_TILESET_RE.fullmatch(name)
        ]
        map_families = sorted({
            MAP_TILESET_RE.fullmatch(name).group(1)
            for name in map_tilesets
            if MAP_TILESET_RE.fullmatch(name)
        })
        text_lines = compact_text_lines(block.get("textLines") or [])
        sample = sample_text(block, text_lines)
        for battle_resource in battle_resources:
            match = BATTLE_RESOURCE_RE.fullmatch(battle_resource)
            if not match:
                continue
            family, variant = match.groups()
            background = Path(battle_resource).stem
            candidates.append(
                {
                    "id": f"{block.get('blockId')}:{background}",
                    "blockId": block.get("blockId"),
                    "classification": block.get("classification"),
                    "startVaHex": block.get("startVaHex"),
                    "endVaHex": block.get("endVaHex"),
                    "sourceCommandVas": block.get("sourceCommandVas") or [],
                    "renderCommandVas": block.get("renderCommandVas") or [],
                    "battleResource": battle_resource,
                    "battleBackground": background,
                    "battleFamily": family,
                    "battleVariant": int(variant),
                    "mapTilesets": map_tilesets,
                    "mapFamilies": map_families,
                    "resourceNames": resource_names,
                    "sampleText": sample,
                    "textLines": text_lines,
                    "textLineCount": block.get("textLineCount", len(text_lines)),
                    "source": "event_dialogue_blocks",
                    "status": "candidate",
                }
            )
    candidates.sort(key=lambda row: (row["battleFamily"], row["battleVariant"], row["blockId"], row["battleBackground"]))
    by_family: dict[str, list[str]] = {}
    for row in candidates:
        by_family.setdefault(row["battleFamily"], []).append(row["id"])
        for family in row["mapFamilies"]:
            by_family.setdefault(family, []).append(row["id"])
    by_family = {key: sorted(dict.fromkeys(value)) for key, value in sorted(by_family.items())}
    return {
        "scope": "Battle-like event dialogue blocks with btl_* resources.",
        "source": "out/event_dialogue_blocks.json",
        "candidateCount": len(candidates),
        "blockCount": len({row["blockId"] for row in candidates}),
        "backgroundCount": len({row["battleBackground"] for row in candidates}),
        "byFamily": by_family,
        "candidates": candidates,
        "notes": [
            "These are resource/dialogue adjacency candidates, not confirmed event-driven battle entry points.",
            "The browser runtime uses them to choose a more source-backed battle review background and log text.",
        ],
    }


def write_outputs(summary: dict, out_dir: Path = OUT) -> None:
    out_dir.mkdir(parents=True, exist_ok=True)
    (out_dir / "battle_event_candidates.json").write_text(
        json.dumps(summary, ensure_ascii=False, indent=2) + "\n",
        encoding="utf-8",
    )
    (out_dir / "battle_event_candidates.js").write_text(
        "window.HWANSE_BATTLE_EVENT_CANDIDATES = "
        + js_json(summary)
        + ";\n",
        encoding="utf-8",
    )


def export_battle_event_candidates(
    event_dialogue_blocks: dict | None = None,
    battle_backgrounds: dict | None = None,
    out_dir: Path = OUT,
) -> dict:
    event_dialogue_blocks = event_dialogue_blocks or load_json(out_dir / "event_dialogue_blocks.json", {})
    battle_backgrounds = battle_backgrounds or load_json(out_dir / "battle_backgrounds.json", {})
    summary = build_summary(event_dialogue_blocks, battle_backgrounds)
    write_outputs(summary, out_dir)
    print(f"wrote {summary['candidateCount']} battle event candidates -> {out_dir / 'battle_event_candidates.js'}")
    return summary


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("--out-dir", type=Path, default=OUT)
    args = parser.parse_args()
    export_battle_event_candidates(out_dir=args.out_dir)


if __name__ == "__main__":
    main()
