from __future__ import annotations

import sys
from collections.abc import (
    ItemsView,
    Iterable,
    Iterator,
    KeysView,
    Mapping,
    ValuesView,
)
from threading import RLock as RLockType
from typing import Any, ClassVar, SupportsIndex, TypeVar, Union, overload

from ..core.base import LattixNode
from ..core.interfaces import MutableLattixMapping
from ..core.meta import LattixMeta
from ..core.mixins import FormatterMixin, LogicalMixin, ThreadingMixin
from ..utils.types import JOIN_METHOD, MERGE_METHOD, ClassAttrSet

if sys.version_info >= (3, 11):
    from typing import Self  # Python 3.11+
else:
    from typing_extensions import Self

__all__: list[str]

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

LattixValue = Union[_VT, "Lattix[_KT, _VT]"]

class Lattix(
    MutableLattixMapping[_KT, _VT],
    LattixNode[_KT, _VT],
    ThreadingMixin,
    LogicalMixin,
    FormatterMixin,
    metaclass=LattixMeta,
):
    """A hierarchical, thread-safe, and observable mapping structure."""

    # ========== Class-level constants ==========
    __INTERNAL_ATTRS__: ClassVar[ClassAttrSet]
    __CLASS_ATTRS__: ClassVar[ClassAttrSet]

    # ========== Constructors & Classmethods ==========
    def __init__(
        self,
        data: Any = ...,
        *,
        key: str = "",
        parent: Any = ...,
        sep: str = "/",
        lazy_create: bool = ...,
        enable_lock: bool = ...,
        frozen: bool = ...,
        **kwargs: Any,
    ) -> None: ...
    def __init_subclass__(cls, **kwargs: Any) -> None: ...
    def __new__(cls, *args: Any, **kwargs: Any) -> Self: ...
    def _config(self) -> tuple[str, bool, bool]: ...
    @classmethod
    def _construct(
        cls,
        mapping: Any,
        config: tuple[str, Any, str, bool, bool] = ...,
        /,
        **kwargs: Any,
    ) -> Self: ...
    def __getstate__(self) -> dict[str, str | bool | dict[str, _VT] | None]: ...
    def __setstate__(self, state: dict[str, Any], /) -> None: ...
    def __reduce__(
        self,
    ) -> tuple[type[Self], tuple[()], dict[str, Any]]: ...
    def __reduce_ex__(
        self, protocol: SupportsIndex, /
    ) -> tuple[type[Self], tuple[()], dict[str, Any]]: ...
    @classmethod
    def __class_getitem__(cls, item: Any, /) -> Any: ...

    # ========== Factories ==========
    @classmethod
    def fromkeys(cls, iterable: Iterable[_T], value: Any = ...) -> Self: ...
    @classmethod
    def from_dict(cls, d: dict[_KT, _VT], sep: str = ...) -> Self: ...
    @classmethod
    def from_json(
        cls, data: str | bytes, encoding: str = ..., *, from_file: bool = ...
    ) -> Self: ...
    @classmethod
    def from_orjson(cls, data: str | bytes, /) -> Self: ...
    @classmethod
    def from_msgpack(cls, data: str | bytes, /) -> Self: ...
    @classmethod
    def from_yaml(
        cls,
        data: str | bytes,
        encoding: str = ...,
        *,
        from_file: bool = ...,
        enhanced: bool = ...,
    ) -> Self: ...
    @classmethod
    def from_env(
        cls, prefix: str = ..., sep: str = ..., lowercase: bool = ..., **kwargs: Any
    ) -> Self: ...
    @classmethod
    def unflatten(
        cls, data: Mapping[str, Any], sep: str = ..., **kwargs: Any
    ) -> Self: ...
    @classmethod
    def _get_class_attrs(cls, refresh: bool = ...) -> ClassAttrSet: ...

    # ========== Properties ==========
    @property
    def sep(self) -> str: ...
    @sep.setter
    def sep(self, symbol: str, /) -> None: ...
    @property
    def lazy_create(self) -> bool: ...
    @lazy_create.setter
    def lazy_create(self, value: bool, /) -> None: ...

    # ========== Internal helpers ==========
    def _fast_set(self, key: _KT, value: Any) -> None: ...
    def _promote_child(
        self, key: _KT, value: Any, parent_node: Lattix[_KT, _VT]
    ) -> Lattix[_KT, _VT]: ...
    def _walk_path(
        self,
        path: str | Iterable[Any] = ...,
        stop_before_last: bool = ...,
        force_no_create: bool = ...,
    ) -> tuple[Lattix[_KT, _VT], _KT] | LattixValue[_KT, _VT]: ...
    @staticmethod
    def _convert_iterable(
        node: Lattix[_KT, _VT], key: str, iterable: Iterable[Any]
    ) -> Any: ...

    # ========== MutableMapping core (Mapping protocol / Basic dict-like) ==========
    def __getitem__(self, key: _KT, /) -> LattixValue[_KT, _VT]: ...
    def __setitem__(self, key: _KT, value: _VT, /) -> None: ...
    def __delitem__(self, key: _KT, /) -> None: ...
    def __iter__(self) -> Iterator[_KT]: ...
    def __len__(self) -> int: ...
    def __contains__(self, key: object, /) -> bool: ...
    def __reversed__(self) -> Iterator[_KT]: ...
    def __eq__(self, value: object, /) -> bool: ...

    # Standard dict methods
    def keys(self) -> KeysView[_KT]: ...
    def values(self) -> ValuesView[LattixValue[_KT, _VT]]: ...
    def items(self) -> ItemsView[_KT, LattixValue[_KT, _VT]]: ...
    def get(self, key: _KT, default: Any = ..., /) -> LattixValue[_KT, _VT] | _T: ...
    def setdefault(self, key: _KT, default: _VT = ..., /) -> _VT: ...
    @overload
    def pop(self, key: _KT, /) -> _VT: ...
    @overload
    def pop(self, key: _KT, default: _VT = ...) -> _VT: ...
    @overload
    def pop(self, key: _KT, default: _T = ..., /) -> _VT | _T: ...
    def popitem(self) -> tuple[_KT, _VT]: ...
    def clear(self) -> None: ...
    def update(self, other: Any = ..., /, **kwargs: Any) -> None: ...
    def copy(self) -> Self: ...

    # ========== Attribute-style access ==========
    def __getattr__(self, name: str, /) -> Any: ...
    def __setattr__(self, name: str, value: _VT, /) -> None: ...
    def __delattr__(self, name: str, /) -> None: ...
    def __dir__(self) -> list[str]: ...

    # ========== Comparison & Representation ==========
    def __repr__(self) -> str: ...
    def __str__(self) -> str: ...
    def __format__(self, format_spec: str, /) -> str: ...
    def _repr_pretty_(self, printer: Any, cycle: Any) -> None: ...
    def __pretty__(self, printer: Any, cycle: bool) -> None: ...

    # ========== Merge / Logical operators ==========
    # --- add (+) ---
    def __add__(self, other: Mapping[_KT, _VT], /) -> Self: ...
    def __iadd__(self, other: Mapping[_KT, _VT], /) -> Self: ...
    def merge(self, other: Mapping[_KT, _VT], overwrite: bool = ...) -> Self: ...
    def _set_operation(
        self, other: Mapping[_KT, _VT] | Any, op: str, inplace: bool = ...
    ) -> Self: ...

    # --- and (&) / intersection ---
    def _and_impl(self, other: Any, inplace: bool = ...) -> Self: ...

    # --- or (|) / union ---
    def _or_impl(self, other: Any, inplace: bool = ...) -> Self: ...

    # --- sub (-) / difference ---
    def _sub_impl(self, other: Any, inplace: bool = ...) -> Self: ...

    # --- xor (^) / symmetric difference ---
    def _xor_impl(self, other: Any, inplace: bool = ...) -> Self: ...

    # --- join ---
    def join(
        self,
        other: Mapping[_KT, _VT],
        how: JOIN_METHOD = ...,
        merge: MERGE_METHOD = ...,
    ) -> Self: ...

    # ========== Leaf / Traversal utilities ==========
    def get_path(
        self, path: str | list[_T] | tuple[_T, ...] = ..., default: _T = ..., /
    ) -> LattixValue[_KT, _VT] | _T: ...
    def has_path(self, path: str | list[_T] | tuple[_T, ...] = ..., /) -> bool: ...
    def is_leaf(self, path: str | list[_T] | tuple[_T, ...] = ..., /) -> bool: ...

    # ========== Serialization & Export ==========
    def to_dict(self) -> dict[_KT, _VT]: ...
    def to_list(self) -> list[tuple[_KT, _VT]]: ...
    def to_tuple(self) -> tuple[tuple[_KT, _VT], ...]: ...
    def flatten(self, sep: str = ...) -> dict[str, _VT]: ...
    def json(self, **kwargs: Any) -> str: ...
    def orjson(self, **kwargs: Any) -> bytes: ...
    def msgpack(self) -> Any: ...
    def yaml(self, enhanced: bool = ..., **kwargs: Any) -> str: ...

    # ========== Copy & Sort utilities ==========
    def __copy__(self) -> Self: ...
    def __deepcopy__(self, memo: dict[int, Any], /) -> Self: ...
    def clone(
        self,
        deep: bool = ...,
        keep_state: bool = ...,
        share_lock: bool = ...,
        memo: dict[int, Any] | None = ...,
    ) -> Self: ...
    def sort_by_key(self, reverse: bool = ..., recursive: bool = ...) -> Self: ...
    def sort_by_value(self, reverse: bool = ..., recursive: bool = ...) -> Self: ...

    # ========== Lifecycle & Cleanup ==========
    @staticmethod
    def _propagate_attrs(
        obj: Any,
        attrs: dict[str, Any] = ...,
        seen: set[int] | None = ...,
    ) -> None: ...
    @staticmethod
    def _propagate_lock(
        obj: Any,
        enable_lock: bool,
        lock: RLockType | None,
        seen: set[int] | None = ...,
    ) -> None: ...
    def freeze(self) -> None: ...
    def unfreeze(self) -> None: ...
    def detach(self, clear_locks: bool = ...) -> None: ...
    def attach(self, parent: Any) -> None: ...
    def transplant(self, parent: Any, key: _KT = ...) -> None: ...
    def __del__(self) -> None: ...
