"""Mechanical child-record detection for 1C Config section containers."""

from __future__ import annotations

from dataclasses import asdict, dataclass
from typing import Any

from .payload import GUID_RE, scalar


@dataclass(frozen=True)
class ChildRecord:
    index: int
    path: str
    node: Any
    evidence: dict[str, set[str]]

    def to_dict(self) -> dict[str, Any]:
        data = asdict(self)
        data.pop("node", None)
        data["evidence"] = {key: sorted(value) for key, value in self.evidence.items()}
        return data


def children(node: Any) -> list[Any]:
    if isinstance(node, dict) and node.get("type") in {"list", "sequence"}:
        return node.get("items") or []
    return []


def collect_evidence(node: Any) -> dict[str, set[str]]:
    strings: set[str] = set()
    guids: set[str] = set()

    def walk(value: Any) -> None:
        if isinstance(value, dict) and value.get("type") in {"atom", "string"}:
            text = scalar(value)
            if not text:
                return
            if value.get("type") == "string":
                strings.add(text)
            if GUID_RE.fullmatch(text):
                guids.add(text.lower())
            return
        for child in children(value):
            walk(child)

    walk(node)
    return {"strings": strings, "guids": guids}


def declared_child_records(section: Any, section_path: str, *, include_evidence: bool = True) -> list[ChildRecord]:
    """Return records for the common `{marker, count, record...}` container.

    The function is deliberately structural. It does not assume that records are
    attributes, dimensions, enum values, or any other metadata category.
    """

    items = children(section)
    if len(items) < 2:
        return []
    try:
        declared_count = int(scalar(items[1]))
    except ValueError:
        return []
    if declared_count < 0:
        return []
    candidates = items[2 : 2 + declared_count]
    if len(candidates) != declared_count:
        return []
    return [
        ChildRecord(
            index=index,
            path=f"{section_path}.{index + 2}",
            node=record,
            evidence=collect_evidence(record) if include_evidence else {"strings": set(), "guids": set()},
        )
        for index, record in enumerate(candidates)
    ]
