#!/usr/bin/env python3
"""Summarize competing tileset candidates for field maps."""
from __future__ import annotations

import argparse
import json
import re
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]


def load_wrapped_json(path: Path, name: str) -> dict:
    text = path.read_text(encoding="utf-8")
    match = re.fullmatch(rf"window\.{re.escape(name)} = (.*);\n?", text, re.S)
    if not match:
        raise ValueError(f"{path} does not contain window.{name}")
    data = json.loads(match.group(1))
    if not isinstance(data, dict):
        raise ValueError(f"{path} must contain an object")
    return data


def suffix_tilesets(map_name: str) -> list[str]:
    suffix = map_name[-1] if map_name[-1:].isalpha() else ""
    if not suffix:
        return []
    return [f"map_{suffix}1", f"map_{suffix}2"]


def unique_variants(variants: list[list[str]]) -> list[list[str]]:
    seen = set()
    result = []
    for variant in variants:
        key = tuple(variant)
        if not key or key in seen:
            continue
        seen.add(key)
        result.append(variant)
    return result


def summarize(maps: dict, scene_links: dict) -> str:
    lines = [
        "# Map Tileset Candidate Summary",
        "",
        "Generated from `out/maps.js` and `out/scene_links.json`.",
        "",
        "`selected` is the tileset pair currently used by the web renderer. "
        "`suffix` comes from the final map filename letter, `observed` comes from EXE scene records, "
        "and `condition` comes from event dispatch condition payload strings.",
        "",
        "| map | selected | suffix | observed scene variants | condition tilesets | note |",
        "| --- | --- | --- | --- | --- | --- |",
    ]
    for name, info in sorted(maps.items()):
        selected = info.get("layerTilesets") or []
        suffix = suffix_tilesets(name)
        observed = unique_variants(
            [
                info.get("observedSceneTilesets") or [],
                *(info.get("sceneTilesetVariants") or []),
            ]
        )
        condition = scene_links.get(name, {}).get("tilesets", [])
        notes = []
        if suffix and selected[: len(suffix)] != suffix:
            notes.append("selected differs from suffix")
        if observed and selected not in observed:
            notes.append("selected differs from observed scene")
        if condition and not any(item in condition for item in selected):
            notes.append("selected absent from condition")
        if observed and any(variant != selected for variant in observed):
            notes.append("has competing scene variant")
        if condition and any(item not in selected for item in condition):
            notes.append("condition has extra tilesets")

        observed_text = "<br>".join(",".join(variant) for variant in observed) or "-"
        lines.append(
            "| {name} | {selected} | {suffix} | {observed} | {condition} | {note} |".format(
                name=name,
                selected=",".join(selected) or "-",
                suffix=",".join(suffix) or "-",
                observed=observed_text,
                condition=",".join(condition) or "-",
                note=", ".join(notes) or "-",
            )
        )
    lines.append("")
    return "\n".join(lines)


def main() -> None:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--maps", type=Path, default=ROOT / "out" / "maps.js")
    parser.add_argument("--scene-links", type=Path, default=ROOT / "out" / "scene_links.json")
    parser.add_argument("--out", type=Path, default=ROOT / "out" / "map_tileset_candidates.md")
    args = parser.parse_args()

    maps = load_wrapped_json(args.maps, "HWANSE_MAPS")
    scene_links = json.loads(args.scene_links.read_text(encoding="utf-8"))
    args.out.parent.mkdir(parents=True, exist_ok=True)
    args.out.write_text(summarize(maps, scene_links), encoding="utf-8")
    print(f"wrote {len(maps)} map tileset candidate summaries -> {args.out}")


if __name__ == "__main__":
    main()
