"""Pure reverse index for 1C common-command group membership."""

from __future__ import annotations

import re
from collections.abc import Iterable, Mapping
from typing import Any

from .payload import decode_payload_lossless, parse_brace_text


_GUID_RE = re.compile(
    r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
)


def _tree_item_at_path(tree: Any, path: tuple[int, ...]) -> Any | None:
    node = tree
    for index in path:
        if not isinstance(node, dict) or not isinstance(node.get("items"), list):
            return None
        items = node["items"]
        if index < 0 or index >= len(items):
            return None
        node = items[index]
    return node


def _tree_scalar_at_path(tree: Any, path: tuple[int, ...]) -> str:
    node = _tree_item_at_path(tree, path)
    if isinstance(node, dict) and node.get("type") in {"atom", "string"}:
        return str(node.get("value") or "")
    return ""


def common_command_group_guid(tree: Any) -> str | None:
    """Return the group GUID stored in an observed CommonCommand Config tree."""
    body = _tree_item_at_path(tree, (1, 1, 2))
    group_guid = _tree_scalar_at_path(body, (7, 1)).strip().lower()
    return group_guid if _GUID_RE.fullmatch(group_guid) else None


def parse_common_command_tree(data: bytes) -> Any | None:
    """Decode a CommonCommand payload without raising on unsupported data."""
    try:
        decoded = decode_payload_lossless(data)
        text = decoded.get("text")
        if not text or "{" not in text:
            return None
        return parse_brace_text(text)
    except Exception:
        return None


def index_common_command_groups(
    commands: Iterable[Mapping[str, Any]],
    payloads: Mapping[str, bytes],
) -> dict[str, Any]:
    """Build ``CommandGroup GUID -> CommonCommand rows`` from Config payloads."""
    command_rows = [dict(item) for item in commands]
    normalized_payloads = {str(key).strip().lower(): value for key, value in payloads.items()}
    groups: dict[str, list[dict[str, Any]]] = {}
    source_missing = 0
    undecodable = 0
    unassigned = 0

    for item in command_rows:
        guid = str(item.get("guid") or "").strip().lower()
        data = normalized_payloads.get(guid)
        if not data:
            source_missing += 1
            continue
        tree = parse_common_command_tree(data)
        if tree is None:
            undecodable += 1
            continue
        group_guid = common_command_group_guid(tree)
        if group_guid is None:
            unassigned += 1
            continue
        groups.setdefault(group_guid, []).append(item)

    return {
        "groups": groups,
        "scanned": len(command_rows),
        "source_missing": source_missing,
        "undecodable": undecodable,
        "unassigned": unassigned,
    }
