#!/usr/bin/env python3
"""Build enum order -> presentation map from 1C XML routes."""

from __future__ import annotations

import argparse
import json
import xml.etree.ElementTree as ET
from pathlib import Path
from typing import Any


NS = {
    "md": "http://v8.3/MDClasses",
    "v8": "http://v8.1c.ru/8.1/data/core",
}


def load_json(path: Path) -> dict[str, Any]:
    return json.loads(path.read_text(encoding="utf-8-sig"))


def local_name(tag: str) -> str:
    return tag.rsplit("}", 1)[-1]


def child_text(parent: ET.Element, name: str) -> str | None:
    for child in list(parent):
        if local_name(child.tag) == name:
            return child.text or ""
    return None


def properties(element: ET.Element) -> ET.Element | None:
    for child in list(element):
        if local_name(child.tag) == "Properties":
            return child
    return None


def synonym(props: ET.Element | None) -> str | None:
    if props is None:
        return None
    for syn in list(props):
        if local_name(syn.tag) != "Synonym":
            continue
        for item in list(syn):
            lang = None
            content = None
            for child in list(item):
                if local_name(child.tag) == "lang":
                    lang = child.text
                elif local_name(child.tag) == "content":
                    content = child.text
            if lang == "ru" and content:
                return content
    return None


def enum_values(path: Path) -> list[dict[str, Any]]:
    root = ET.parse(path).getroot()
    enum = next((node for node in root.iter() if local_name(node.tag) == "Enum"), None)
    if enum is None:
        return []
    child_objects = next((node for node in list(enum) if local_name(node.tag) == "ChildObjects"), None)
    if child_objects is None:
        return []
    values = []
    order = 0
    for node in list(child_objects):
        if local_name(node.tag) != "EnumValue":
            continue
        props = properties(node)
        name = child_text(props, "Name") if props is not None else None
        values.append(
            {
                "order": order,
                "uuid": (node.attrib.get("uuid") or "").lower() or None,
                "name": name,
                "synonym": synonym(props),
            }
        )
        order += 1
    return values


def is_base_config(top: dict[str, Any]) -> bool:
    relative = str(top.get("relative_path") or "")
    return relative.startswith("Enums\\")


def route_score(row: dict[str, Any]) -> tuple[int, str]:
    return (1 if str(row.get("relative_path") or "").startswith("Enums\\") else 0, str(row.get("relative_path") or ""))


def main() -> int:
    parser = argparse.ArgumentParser(description="Build 1C enum presentation map.")
    parser.add_argument("--index", type=Path, required=True)
    parser.add_argument("--output", type=Path, required=True)
    args = parser.parse_args()

    index = load_json(args.index)
    enums: dict[str, dict[str, Any]] = {}
    for guid, item in (index.get("objects") or {}).items():
        tops = [
            top
            for top in item.get("xml_top_objects") or []
            if top.get("xml_kind") == "Enum" and top.get("name") and top.get("path")
        ]
        if not tops:
            continue
        tops.sort(key=lambda top: (not is_base_config(top), top.get("relative_path") or ""))
        top = tops[0]
        path = Path(top["path"])
        if not path.is_file():
            continue
        try:
            values = enum_values(path)
        except ET.ParseError as error:
            values = []
            parse_error = str(error)
        else:
            parse_error = None
        key = str(top["name"])
        candidate = {
            "guid": guid,
            "name": top.get("name"),
            "synonym": top.get("synonym"),
            "relative_path": top.get("relative_path"),
            "path": top.get("path"),
            "parse_error": parse_error,
            "values": values,
            "by_order": {str(value["order"]): value for value in values},
            "by_uuid": {value["uuid"]: value for value in values if value.get("uuid")},
        }
        existing = enums.get(key)
        if existing is None or route_score(candidate) > route_score(existing):
            enums[key] = candidate

    result = {
        "schema": "onec_enum_presentation_map.v1",
        "index": str(args.index),
        "enum_count": len(enums),
        "enums": dict(sorted(enums.items())),
    }
    args.output.parent.mkdir(parents=True, exist_ok=True)
    args.output.write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
    print(json.dumps({"output": str(args.output), "enum_count": len(enums)}, ensure_ascii=False))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
