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,
)
from caterpillar import native_support

if native_support():

    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",
    ]
