"""Conservative parser for top-level Config metadata object identity."""

from __future__ import annotations

from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Any

from .payload import GUID_RE, parse_payload_file, root_signature, scalar


@dataclass(frozen=True)
class MetadataObjectIdentity:
    guid: str
    name: str
    synonyms: dict[str, str]
    evidence_path: str

    def to_dict(self) -> dict[str, Any]:
        return asdict(self)


def _is_guid(value: str) -> bool:
    return bool(GUID_RE.fullmatch(value))


def _identity_guid(node: Any) -> str:
    if not (isinstance(node, dict) and node.get("type") == "list"):
        return ""
    items = node.get("items") or []
    if len(items) != 3:
        return ""
    if scalar(items[0]) != "1" or scalar(items[1]) != "0":
        return ""
    guid = scalar(items[2]).lower()
    return guid if _is_guid(guid) else ""


def _synonyms(node: Any) -> dict[str, str]:
    if not (isinstance(node, dict) and node.get("type") == "list"):
        return {}
    items = node.get("items") or []
    if not items:
        return {}
    try:
        declared_count = int(scalar(items[0]))
    except ValueError:
        return {}
    if declared_count < 0 or len(items) < 1 + declared_count * 2:
        return {}
    result = {}
    index = 1
    end = 1 + declared_count * 2
    while index + 1 < end:
        language = scalar(items[index])
        value = scalar(items[index + 1])
        if language and value:
            result[language] = value
        index += 2
    return result


def find_identity(tree: Any) -> MetadataObjectIdentity | None:
    """Find the observed object identity block in a generic brace tree."""

    def walk(node: Any, path: list[int]) -> MetadataObjectIdentity | None:
        if isinstance(node, dict) and node.get("type") == "list":
            items = node.get("items") or []
            for index in range(0, max(len(items) - 2, 0)):
                guid = _identity_guid(items[index])
                name = scalar(items[index + 1])
                synonym_node = items[index + 2]
                synonym_items = synonym_node.get("items") if isinstance(synonym_node, dict) and synonym_node.get("type") == "list" else None
                try:
                    synonym_count = int(scalar(synonym_items[0])) if synonym_items else -1
                except ValueError:
                    synonym_count = -1
                synonyms = _synonyms(synonym_node)
                if guid and name and synonym_count >= 0 and len(synonym_items or []) >= 1 + synonym_count * 2:
                    return MetadataObjectIdentity(
                        guid=guid,
                        name=name,
                        synonyms=synonyms,
                        evidence_path=".".join(str(part) for part in [*path, index]),
                    )
            for child_index, child in enumerate(items):
                found = walk(child, [*path, child_index])
                if found:
                    return found
        return None

    return walk(tree, [])


def parse_config_object_file(path: Path) -> dict[str, Any]:
    payload = parse_payload_file(path)
    tree = payload.get("tree")
    identity = find_identity(tree)
    return {
        "source_path": str(path),
        "compression": payload.get("compression"),
        "encoding": payload.get("encoding"),
        "raw_bytes": payload.get("raw_bytes"),
        "payload_bytes": payload.get("payload_bytes"),
        "root": root_signature(tree),
        "identity": identity.to_dict() if identity else None,
        "tree": tree,
    }
