"""Result container for HOL queries with children and/or parent objects."""

from __future__ import annotations

from typing import Any, Generic, TypeVar, overload

from ecmind_blue_client.ecm.model._ecm_model import _ECMModelBase
from ecmind_blue_client.ecm.model._ecm_hol_spec import ECMChildSpec

_MainT = TypeVar("_MainT", bound=_ECMModelBase)
_ChildT = TypeVar("_ChildT", bound=_ECMModelBase)


class ECMHolResult(Generic[_MainT]):
    """Container for a single result of a HOL query with children and/or parents.

    When ``with_children()`` is active, ``main`` is the queried object and
    ``children_of()`` returns its direct children.

    When ``with_parents()`` is active, the server response is structured from the
    outermost parent down. ``main`` is therefore the **outermost parent** (first spec
    passed to ``with_parents()``). The originally queried objects and all intermediate
    ancestor types are accessible as descendants via ``children_of()``.

    Attributes:
        main: The top-level model instance — the queried object when no parents are
            active, or the outermost parent when ``with_parents()`` was called.

    Example (children only)::

        results = (
            ecm.dms.select(Register)
            .where(Register.Name == "Subreg1")
            .with_children(ECMChildSpec(Document), export_depth=1)
            .limit(50)
            .execute()
        )
        for r in results:
            docs = r.children_of(ECMChildSpec(Document))   # list[Document]

    Example (parents — main is the outermost parent)::

        results = (
            ecm.dms.select(Document)
            .where(Document.Name == "Invoice")
            .with_parents(ECMParentSpec(FolderModel), ECMParentSpec(RegisterModel))
            .limit(50)
            .execute()
        )
        for r in results:
            folder   = r.main                                    # FolderModel
            register = r.children_of(ECMChildSpec(RegisterModel))[0]
            doc      = r.children_of(ECMChildSpec(Document))[0]
    """

    def __init__(
        self,
        main: _MainT,
        children: dict[str | int, list[Any]],
    ) -> None:
        self.main = main
        self._children = children

    @overload
    def children_of(self, spec: str | int) -> list[_ECMModelBase]: ...

    @overload
    def children_of(self, spec: ECMChildSpec[_ChildT]) -> list[_ChildT]: ...  # type: ignore[misc]

    def children_of(self, spec: Any) -> list[Any]:
        """Return child or descendant objects for the given spec or identifier.

        When ``with_children()`` was active, this returns only **direct** children of
        the queried main object. When ``with_parents()`` was active, this searches
        **all nesting levels** recursively, so the queried objects and any intermediate
        ancestor types are all accessible here regardless of their depth.

        The key used for lookup is the spec's ``identifier()`` value (internal name or
        type ID). Both the string and integer forms are stored, so either can be used.

        Args:
            spec: ``ECMChildSpec`` instance, ECM internal name (str), or type ID (int).

        Returns:
            List of model instances; empty list if no objects of that type are present.
        """
        if isinstance(spec, (str, int)):
            return self._children.get(spec, [])
        return self._children.get(spec.identifier(), [])

    def __repr__(self) -> str:
        return f"<ECMHolResult main={self.main!r} children={list(self._children.keys())}>"
