from collections.abc import Collection, Iterable
from typing import Any, Generic
from typing_extensions import override, Self
from caterpillar.abc import (
    _OT,
    _IT,
    _ArchLike,
    _EndianLike,
    _SupportsSetEndian,
    _ContextLike,
    _LengthT,
    _StructLike,
    _SwitchLike,
    _ContextLambda,
)

BIG_ENDIAN: c_Endian
HOST_ARCH: c_Arch
LITTLE_ENDIAN: c_Endian
NATIVE_ENDIAN: c_Endian

class c_Arch(_ArchLike):
    name: str
    ptr_size: int
    def __init__(self, name: str, ptr_size: int) -> None: ...
    def __eq__(self, other: object) -> bool: ...
    def __ge__(self, other: object) -> bool: ...
    def __gt__(self, other: object) -> bool: ...
    def __hash__(self) -> int: ...
    def __le__(self, other: object) -> bool: ...
    def __lt__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...

class c_Endian(_EndianLike):
    ch: str
    name: str
    def __init__(self, name: str, ch: int) -> None: ...
    def __add__(self, other: _SupportsSetEndian[_OT]) -> _OT: ...
    def __eq__(self, other: object) -> bool: ...
    def __ge__(self, other: object) -> bool: ...
    def __gt__(self, other: object) -> bool: ...
    def __hash__(self) -> int: ...
    def __le__(self, other: object) -> bool: ...
    def __lt__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __radd__(self, other: _SupportsSetEndian[_OT]) -> _OT: ...

class c_Option:
    name: str
    value: Any
    def __init__(self, name: str, value: Any = ...) -> None: ...
    @override
    def __eq__(self, value: object | c_Option, /) -> bool: ...
    @override
    def __hash__(self) -> int: ...

class c_Context(dict[str, Any]):
    def __init__(self, **kwargs: dict[str, Any]) -> None: ...
    def __context_getattr__(self, path: str) -> Any: ...
    def __context_setattr__(self, path: str, value: Any) -> None: ...
    @property
    def _root(self) -> _ContextLike: ...

class LengthInfo:
    length: int
    greedy: bool
    def __init__(self, length: int = ..., greedy: bool = ...) -> None: ...

class Atom(Generic[_IT, _OT]):
    def __pack__(self, obj: _IT, context: _ContextLike) -> None: ...
    def __pack_many__(
        self,
        obj: Iterable[_IT],
        context: _ContextLike,
        lengthinfo: LengthInfo,
    ) -> None: ...
    def __unpack__(self, context: _ContextLike) -> _OT: ...
    def __unpack_many__(
        self,
        context: _ContextLike,
        lengthinfo: LengthInfo,
    ) -> Iterable[_OT]: ...
    def __type__(self) -> type | str | None: ...
    def __size__(self, context: _ContextLike) -> int: ...
    def __bits__(self) -> int: ...

class BuiltinAtom(Atom[_IT, _OT]):
    def __getitem__(self, dim: _LengthT) -> Repeated[_IT, _OT]: ...
    def __rshift__(self, cases: _SwitchLike[Any, Any]) -> Switch: ...

class Repeated(BuiltinAtom[Collection[_IT], Collection[_OT]]):
    atom: _StructLike[_IT, _OT]
    length: _LengthT

    def __init__(self, atom: _StructLike[_IT, _OT], length: _LengthT) -> None: ...
    @override
    def __pack__(self, obj: Collection[_IT], context: _ContextLike) -> None: ...
    @override
    def __unpack__(self, context: _ContextLike) -> Collection[_OT]: ...
    @override
    def __size__(self, context: _ContextLike) -> int: ...
    @override
    def __bits__(self) -> int: ...
    @override
    def __type__(self) -> type[list[_OT]]: ...
    def __set_byteorder__(self, order: _EndianLike) -> Self: ...

class Switch(BuiltinAtom[Any, Any]):
    cases: _SwitchLike[Any, Any]
    atom: _StructLike[Any, Any] | _ContextLambda[Any]

    def __init__(
        self,
        atom: _StructLike[Any, Any] | _ContextLambda[Any],
        cases: _SwitchLike[Any, Any],
    ) -> None: ...
    @override
    def __pack__(self, obj: Any, context: _ContextLike) -> None: ...
    @override
    def __unpack__(self, context: _ContextLike) -> Any: ...
    @override
    def __type__(self) -> type | str | None: ...
    def __set_byteorder__(self, order: _EndianLike) -> Self: ...
    def eval_with_context(
        self,
        value: Any,
        context: _ContextLike,
    ) -> _StructLike[Any, Any]: ...

class Conditional(BuiltinAtom[_IT | None, _OT | None]):
    atom: _StructLike[_IT, _OT]
    condition: _ContextLambda[bool] | bool

    def __init__(
        self,
        atom: _StructLike[_IT, _OT],
        condition: _ContextLambda[bool] | bool,
    ) -> None: ...
    @override
    def __pack__(self, obj: _IT | None, context: _ContextLike) -> None: ...
    @override
    def __unpack__(self, context: _ContextLike) -> _OT | None: ...
    @override
    def __type__(self) -> type | str | None: ...
    def __set_byteorder__(self, order: _EndianLike) -> Self: ...
    def is_enabled(self, context: _ContextLike) -> bool: ...

class AtOffset(BuiltinAtom[_IT, _OT]):
    atom: _StructLike[_IT, _OT]
    offset: int | _ContextLambda[int]
    whence: int
    keep_pos: bool

    def __init__(
        self,
        atom: _StructLike[_IT, _OT],
        offset: int | _ContextLambda[int],
        whence: int = ...,
        keep_pos: bool = ...,
    ) -> None: ...
    @override
    def __pack__(self, obj: _IT, context: _ContextLike) -> None: ...
    @override
    def __unpack__(self, context: _ContextLike) -> _OT: ...
    @override
    def __type__(self) -> type | str | None: ...
    def __set_byteorder__(self, order: _EndianLike) -> Self: ...
    @property
    def is_number(self) -> bool: ...

__all__ = [
    "c_Arch",
    "c_Endian",
    "c_Option",
    "c_Context",
    "BIG_ENDIAN",
    "HOST_ARCH",
    "LITTLE_ENDIAN",
    "NATIVE_ENDIAN",
    "Atom",
    "LengthInfo",
    "Repeated",
    "Switch",
    "Conditional",
    "AtOffset",
    "BuiltinAtom",
]
