from __future__ import annotations

from collections.abc import Callable, ItemsView, Iterable, KeysView, ValuesView
from typing import Any, Generic, Literal, TypeVar, Union
from weakref import ReferenceType

from ..utils.types import TRAV_ORDER

__all__: list[str]

_KT = TypeVar("_KT")
_VT = TypeVar("_VT")
_T = TypeVar("_T")

NodeContent = Union[_VT, "LattixNode[_KT, _VT]"]

class LattixNode(Generic[_KT, _VT]):
    """Hierarchical node supporting parent-child relationships."""

    # ========== Class-level constants ==========
    _parent: ReferenceType[LattixNode[_KT, _VT]] | None
    _children: dict[_KT, NodeContent[_KT, _VT]]
    _key: str

    # ========== Init ==========
    def __init__(
        self, key: str = ..., parent: LattixNode[_KT, _VT] | None = None
    ) -> None: ...

    # ========== Parent / Children Properties ==========
    @property
    def key(self) -> str: ...
    @property
    def parent(self) -> LattixNode[_KT, _VT] | None: ...
    @parent.setter
    def parent(self, value: LattixNode[_KT, _VT] | None) -> None: ...
    @property
    def children(self) -> dict[_KT, NodeContent[_KT, _VT]]: ...

    # ========== Dict-like API ==========
    def __len__(self) -> int: ...
    def __contains__(self, key: object, /) -> bool: ...
    def keys(self) -> KeysView[_KT]: ...
    def values(self) -> ValuesView[NodeContent[_KT, _VT]]: ...
    def items(self) -> ItemsView[_KT, NodeContent[_KT, _VT]]: ...
    def empty(self) -> bool: ...

    # ========== Hierarchy operations ==========
    def detach(self) -> None: ...
    def attach(self, parent: LattixNode[_KT, _VT]) -> None: ...
    def transplant(self, parent: LattixNode[_KT, _VT], key: _KT = ...) -> None: ...

    # ========== Validation ==========
    @staticmethod
    def _validate_parent_node(parent: Any) -> Literal[True]: ...
    @staticmethod
    def _validate_attachable_node(
        obj: LattixNode[_KT, _VT], parent: LattixNode[_KT, _VT]
    ) -> Literal[True]: ...

    # ========== Ancestors / Tree utils ==========
    def is_root(self) -> bool: ...
    def get_parent(self) -> LattixNode[_KT, _VT] | None: ...
    def _ancestors(self) -> Iterable[LattixNode[_KT, _VT]]: ...
    def get_root(self) -> LattixNode[_KT, _VT]: ...
    def is_cycled(self) -> bool: ...

    # ========== Walk / Traverse ==========
    def walk(
        self, path: tuple[_KT, ...] = ...
    ) -> Iterable[tuple[tuple[_KT, ...], NodeContent[_KT, _VT]]]: ...
    def traverse(
        self, order: TRAV_ORDER = ..., _seen: set[int] | None = None
    ) -> Iterable[LattixNode[_KT, _VT]]: ...

    # ========== Leaf Utilities ==========
    def leaf_keys(self) -> Iterable[str]: ...
    def leaf_values(self) -> Iterable[_VT]: ...
    def map_leaves(self, func: Callable[[_VT], _VT]) -> None: ...
    def filter_leaves(self, func: Callable[[_VT], bool]) -> None: ...
    def purge(self) -> bool: ...

    # ========== Flatten records ==========
    def to_records(self) -> list[tuple[str, _VT]]: ...

    # ========== Representation ==========
    def __repr__(self) -> str: ...
