#!/usr/bin/env python3
"""
Convert an EncounterJournal JSON dump into a Lua file the
MoonWellClient EncounterJournal addon can `loadstring`/`include`.

Field order, key sort and structure mirror what the C++ exporter
in mod-encounter-journal writes via .ej export. Use this when the
JSON is produced outside the worldserver (e.g., from a CI job that
queries acore_world directly).
"""

from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path
from typing import Any, Iterable


def lua_str(value: Any) -> str:
    s = str(value)
    s = s.replace("\\", "\\\\")
    s = s.replace("'", "\\'")
    s = s.replace("\n", "\\n")
    s = s.replace("\r", "\\r")
    return f"'{s}'"


def lua_value(value: Any) -> str:
    if isinstance(value, bool):
        return "true" if value else "false"
    if isinstance(value, (int, float)):
        # Integers stay int; floats use repr for round-trip stability.
        if isinstance(value, float) and value.is_integer():
            return str(int(value))
        return repr(value) if isinstance(value, float) else str(value)
    if value is None:
        return "nil"
    return lua_str(value)


def lua_array(values: Iterable[Any]) -> str:
    return "{ " + ", ".join(lua_value(v) for v in values) + " }"


def emit_keyed_rows(out: list[str], name: str, mapping: dict, indent: str) -> None:
    out.append(f"{indent}{name} = {{\n")
    for key in sorted(mapping.keys(), key=lambda k: int(k)):
        rows = mapping[key]
        if rows and isinstance(rows[0], list):
            out.append(f"{indent}    [{int(key)}] = {{\n")
            for row in rows:
                out.append(f"{indent}        {lua_array(row)},\n")
            out.append(f"{indent}    }},\n")
        else:
            # Single row OR flat list of ids (tierInstances).
            out.append(f"{indent}    [{int(key)}] = {lua_array(rows)},\n")
    out.append(f"{indent}}},\n")


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--input", "-i", required=True,
                        help="Path to EncounterJournalData.json")
    parser.add_argument("--output", "-o", required=True,
                        help="Path to write EncounterJournalData.lua")
    parser.add_argument("--global", "-g", dest="global_name",
                        default="MoonWellEncounterJournalData",
                        help="Name of the Lua global to assign")
    args = parser.parse_args()

    src = Path(args.input)
    if not src.exists():
        print(f"input file not found: {src}", file=sys.stderr)
        return 1

    with src.open("r", encoding="utf-8") as f:
        data = json.load(f)

    out: list[str] = []
    out.append("-- Generated by mod-encounter-journal/tools/json_to_lua.py.\n")
    out.append("-- Source of truth: custom_ej_* tables in acore_world.\n\n")
    out.append(f"{args.global_name} = {{\n")

    # tiers (flat array)
    out.append("    tiers = {\n")
    for tier in data.get("tiers", []):
        out.append(f"        {lua_array(tier)},\n")
    out.append("    },\n")

    # instances : map id -> single row
    instances = data.get("instances", {})
    out.append("    instances = {\n")
    for key in sorted(instances.keys(), key=lambda k: int(k)):
        out.append(f"        [{int(key)}] = {lua_array(instances[key])},\n")
    out.append("    },\n")

    # tierInstances : map tier_id -> [instance_id, ...]
    emit_keyed_rows(out, "tierInstances", data.get("tierInstances", {}), "    ")

    # encounters : map instance_id -> [[row], ...]
    emit_keyed_rows(out, "encounters", data.get("encounters", {}), "    ")

    # creatures : map encounter_id -> [[row], ...]
    emit_keyed_rows(out, "creatures", data.get("creatures", {}), "    ")

    # sections : map section_id -> single row
    sections = data.get("sections", {})
    out.append("    sections = {\n")
    for key in sorted(sections.keys(), key=lambda k: int(k)):
        out.append(f"        [{int(key)}] = {lua_array(sections[key])},\n")
    out.append("    },\n")

    # items : map encounter_id -> [[row], ...]
    emit_keyed_rows(out, "items", data.get("items", {}), "    ")

    out.append("}\n")

    Path(args.output).write_text("".join(out), encoding="utf-8")
    return 0


if __name__ == "__main__":
    sys.exit(main())
