"""Mechanical section summaries for Config brace trees.

This module intentionally does not name sections as attributes, tabular
sections, forms, etc. It only reports paths, shapes, strings, and GUIDs so a
higher-level validator can attach semantics using XML or other evidence.
"""

from __future__ import annotations

from dataclasses import asdict, dataclass
from typing import Any

from .payload import GUID_RE, collect_strings, scalar


@dataclass(frozen=True)
class SectionSummary:
    path: str
    node_type: str
    list_len: int | None
    first_scalars: list[str]
    string_count_sampled: int
    guid_count_sampled: int
    strings_sample: list[str]
    guids_sample: list[str]

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


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


def _atoms(node: Any, limit: int) -> list[str]:
    values: list[str] = []

    def walk(value: Any) -> None:
        if len(values) >= limit:
            return
        if isinstance(value, dict) and value.get("type") in {"atom", "string"}:
            text = scalar(value)
            if text:
                values.append(text)
            return
        for child in _children(value):
            walk(child)

    walk(node)
    return values


def summarize_section(node: Any, path: str, *, limit: int = 200) -> SectionSummary:
    children = _children(node)
    atoms = _atoms(node, limit)
    strings = collect_strings(node, limit=limit)
    guids = sorted(set(value.lower() for value in atoms if GUID_RE.fullmatch(value)))
    return SectionSummary(
        path=path,
        node_type=node.get("type") if isinstance(node, dict) else type(node).__name__,
        list_len=len(children) if children else None,
        first_scalars=[scalar(child) for child in children[:12]],
        string_count_sampled=len(strings),
        guid_count_sampled=len(guids),
        strings_sample=strings[:50],
        guids_sample=guids[:50],
    )


def summarize_sections(tree: Any, *, max_depth: int = 2, limit: int = 200) -> list[SectionSummary]:
    summaries: list[SectionSummary] = []

    def walk(node: Any, path: list[int], depth: int) -> None:
        if depth > max_depth:
            return
        if path:
            summaries.append(summarize_section(node, ".".join(str(part) for part in path), limit=limit))
        for index, child in enumerate(_children(node)):
            walk(child, [*path, index], depth + 1)

    walk(tree, [], 0)
    return summaries
