#!/usr/bin/env python3
"""Summarize map-resource links found in scene event condition payloads."""
from __future__ import annotations

import argparse
import json
import re
from pathlib import Path


FIELD_MAP_RE = re.compile(r"map\d+_\d+[a-z]\.cns$")
TILESET_RE = re.compile(r"map_[a-z][0-9]\.cns$")


def unique(values: list[str]) -> list[str]:
    seen = set()
    result = []
    for value in values:
        if value in seen:
            continue
        seen.add(value)
        result.append(value)
    return result


def condition_strings(event: dict) -> list[str]:
    return unique(
        [
            linked
            for ref in event.get("eventDispatchRefs", [])
            for linked in ref.get("conditionLinkedStrings", [])
        ]
    )


def link_record(event: dict) -> dict:
    strings = condition_strings(event)
    field_maps = [item[:-4] for item in strings if FIELD_MAP_RE.fullmatch(item)]
    tilesets = [item[:-4] for item in strings if TILESET_RE.fullmatch(item)]
    other = [
        item
        for item in strings
        if item.endswith(".cns")
        and not FIELD_MAP_RE.fullmatch(item)
        and not TILESET_RE.fullmatch(item)
    ]
    return {
        "source": event["map"],
        "sceneId": event["sceneId"],
        "sceneIdHex": event["sceneIdHex"],
        "eventKind": event["eventKind"],
        "recordVa": event["recordVa"],
        "fieldMaps": unique(field_maps),
        "tilesets": unique(tilesets),
        "other": unique(other),
        "dispatchRefCount": len(event.get("eventDispatchRefs", [])),
    }


def records(events: list[dict]) -> list[dict]:
    return [link_record(event) for event in events]


def aggregate(records_: list[dict]) -> dict[str, dict]:
    result: dict[str, dict] = {}
    for record in records_:
        source = record["source"]
        entry = result.setdefault(
            source,
            {
                "fieldMaps": [],
                "tilesets": [],
                "other": [],
                "records": [],
            },
        )
        entry["records"].append(record)
        for key in ["fieldMaps", "tilesets", "other"]:
            entry[key] = unique([*entry[key], *record[key]])
    for source, entry in result.items():
        entry["fieldMaps"] = [target for target in entry["fieldMaps"] if target != source]
    return dict(sorted(result.items()))


def structured_links(events: list[dict]) -> dict[str, dict]:
    return aggregate(records(events))


def summarize(events: list[dict]) -> str:
    lines = [
        "# Scene Resource Link Summary",
        "",
        "Generated from `eventDispatchRefs[].conditionLinkedStrings`.",
        "",
        "| source map | scene | kind | field map links | tilesets | sprites/other | dispatch refs | record |",
        "| --- | --- | ---: | --- | --- | --- | ---: | --- |",
    ]
    aggregate_links: dict[str, set[str]] = {}
    for event in events:
        record = link_record(event)
        field_maps = record["fieldMaps"]
        tilesets = record["tilesets"]
        other = record["other"]
        aggregate_links.setdefault(event["map"], set()).update(field_maps)
        lines.append(
            "| {source} | {scene} | {kind} | {field_maps} | {tilesets} | {other} | {refs} | `{record}` |".format(
                source=event["map"],
                scene=event["sceneIdHex"],
                kind=event["eventKind"],
                field_maps=", ".join(field_maps) or "-",
                tilesets=", ".join(tilesets[:12]) or "-",
                other=", ".join(other[:12]) or "-",
                refs=len(event.get("eventDispatchRefs", [])),
                record=f"0x{event['recordVa']:08x}",
            )
        )

    lines.extend(
        [
            "",
            "## Aggregated Field Map Links",
            "",
            "| source map | linked field maps |",
            "| --- | --- |",
        ]
    )
    for source, targets in sorted(aggregate_links.items()):
        filtered = sorted(target for target in targets if target != source)
        lines.append(f"| {source} | {', '.join(filtered) or '-'} |")
    lines.append("")
    return "\n".join(lines)


def main() -> None:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--events", type=Path, default=Path("out/scene_events.json"))
    parser.add_argument("--out", type=Path, default=Path("out/scene_links_summary.md"))
    args = parser.parse_args()

    events = json.loads(args.events.read_text(encoding="utf-8"))
    args.out.parent.mkdir(parents=True, exist_ok=True)
    args.out.write_text(summarize(events), encoding="utf-8")
    print(f"wrote {len(events)} scene link summaries -> {args.out}")


if __name__ == "__main__":
    main()
