import sys
from collections.abc import Callable, Iterator, Mapping, Sequence
from datetime import date, datetime, tzinfo
from decimal import Decimal
from email.mime.text import MIMEText
from fractions import Fraction
from ipaddress import (
    IPv4Address,
    IPv4Interface,
    IPv4Network,
    IPv6Address,
    IPv6Interface,
    IPv6Network,
)
from re import Pattern
from typing import IO, Any, Generic, TypeAlias, final, overload
from uuid import UUID

if sys.hexversion < 51314855:
    @final
    class frozendict(Generic[_KT, _VT_co], Mapping[_KT, _VT_co]):
        def __new__(cls, *args: Any, **kwargs: Any) -> Self: ...
        def __getitem__(self, key: _KT, /) -> _VT_co: ...
        def __len__(self) -> int: ...
        def __iter__(self) -> Iterator[_T_co]: ...

if sys.version_info >= (3, 13):
    from typing import TypeVar
else:
    from typing_extensions import TypeVar

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

_T = TypeVar("_T")
_T_co = TypeVar("_T_co", covariant=True)
_KT = TypeVar("_KT")
_VT_co = TypeVar("_VT_co", covariant=True)
_TContainer = TypeVar("_TContainer", default=None)

TagHook: TypeAlias = Callable[[CBORTag, bool], Any]
SemanticDecoderCallback: TypeAlias = Callable[[Any, bool], Any]
ObjectHook: TypeAlias = Callable[[Mapping[Any, Any], bool], Any]
EncoderHook: TypeAlias = Callable[[CBOREncoder, Any], Any]
ShareableDecoderCallback: TypeAlias = Callable[[Any], Any]
ShareableDecoderInitializer: TypeAlias = Callable[[bool], tuple[Any, ShareableDecoderCallback]]

@final
class CBOREncoder:
    datetime_as_timestamp: bool
    timezone: tzinfo | None
    value_sharing: bool
    default: EncoderHook | None
    canonical: bool
    date_as_datetime: bool
    string_referencing: bool
    indefinite_containers: bool
    def __new__(
        cls,
        fp: IO[bytes],
        *,
        datetime_as_timestamp: bool = ...,
        timezone: tzinfo | None = ...,
        value_sharing: bool = ...,
        encoders: Mapping[type, EncoderHook] | None = ...,
        default: EncoderHook | None = ...,
        canonical: bool = ...,
        date_as_datetime: bool = ...,
        string_referencing: bool = ...,
        indefinite_containers: bool = ...,
    ) -> Self: ...
    fp: IO[bytes]
    def flush(self) -> None: ...
    def write(self, buf: bytes, /) -> int: ...
    def encode(self, obj: object, /) -> None: ...
    def encode_to_bytes(self, obj: object, /) -> bytes: ...
    def encode_length(self, major_tag: int, length: int | None) -> None: ...
    def encode_string(self, obj: str) -> None: ...
    def encode_bytes(self, obj: bytes) -> None: ...
    def encode_bytearray(self, obj: bytearray) -> None: ...
    def encode_array(self, obj: Sequence[Any]) -> None: ...
    def encode_map(self, obj: Mapping[Any, Any]) -> None: ...
    def encode_break(self) -> None: ...
    def encode_int(self, obj: int) -> None: ...
    def encode_bool(self, obj: bool) -> None: ...
    def encode_none(self) -> None: ...
    def encode_undefined(self) -> None: ...
    def encode_semantic(self, tag: int, value: Any) -> None: ...
    def encode_set(self, obj: set[Any]) -> None: ...
    def encode_frozenset(self, obj: frozenset[Any]) -> None: ...
    def encode_datetime(self, obj: datetime) -> None: ...
    def encode_date(self, obj: date) -> None: ...
    def encode_rational(self, obj: Fraction) -> None: ...
    def encode_regexp(self, obj: Pattern[str]) -> None: ...
    def encode_mime(self, obj: MIMEText) -> None: ...
    def encode_uuid(self, obj: UUID) -> None: ...
    def encode_decimal(self, obj: Decimal) -> None: ...
    def encode_ipv4_address(self, obj: IPv4Address) -> None: ...
    def encode_ipv4_network(self, obj: IPv4Network) -> None: ...
    def encode_ipv4_interface(self, obj: IPv4Interface) -> None: ...
    def encode_ipv6_address(self, obj: IPv6Address) -> None: ...
    def encode_ipv6_network(self, obj: IPv6Network) -> None: ...
    def encode_ipv6_interface(self, obj: IPv6Interface) -> None: ...
    def encode_simple_value(self, obj: CBORSimpleValue) -> None: ...
    def encode_float(self, obj: float) -> None: ...
    def encode_complex(self, obj: complex) -> None: ...

@final
class CBORDecoder:
    fp: IO[bytes]
    tag_hook: TagHook | None
    object_hook: ObjectHook | None
    str_errors: str
    def __new__(
        cls,
        fp: IO[bytes],
        *,
        tag_hook: TagHook | None = ...,
        object_hook: ObjectHook | None = ...,
        semantic_decoders: Mapping[int, SemanticDecoderCallback | ShareableDecoderInitializer]
        | None = ...,
        str_errors: str = ...,
        read_size: int = ...,
        max_depth: int = ...,
        allow_indefinite: bool = ...,
    ) -> Self: ...

    # Properties
    @property
    def read_size(self) -> int: ...
    @property
    def max_depth(self) -> int: ...
    @property
    def allow_indefinite(self) -> bool: ...
    def decode(self, *, immutable: bool = ...) -> Any: ...
    def read(self, amount: int, /) -> bytes: ...

class CBORError(Exception): ...
class CBOREncodeError(CBORError): ...
class CBOREncodeTypeError(CBOREncodeError, TypeError): ...
class CBOREncodeValueError(CBOREncodeError, ValueError): ...
class CBORDecodeError(CBORError): ...
class CBORDecodeEOF(CBORDecodeError, EOFError): ...

@final
class CBORTag:
    tag: int
    value: Any

    def __new__(cls, tag: int, value: Any) -> Self: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: object) -> bool: ...
    def __le__(self, other: object, /) -> bool: ...
    def __gt__(self, other: object, /) -> bool: ...
    def __ge__(self, other: object, /) -> bool: ...

@final
class CBORSimpleValue:
    value: int

    def __new__(cls, value: int) -> Self: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __lt__(self, other: object) -> bool: ...
    def __le__(self, other: object, /) -> bool: ...
    def __gt__(self, other: object, /) -> bool: ...
    def __ge__(self, other: object, /) -> bool: ...

@final
class UndefinedType: ...

undefined: UndefinedType

def dump(
    obj: object,
    fp: IO[bytes],
    *,
    datetime_as_timestamp: bool = ...,
    timezone: tzinfo | None = ...,
    value_sharing: bool = ...,
    encoders: Mapping[type, EncoderHook] | None = ...,
    default: EncoderHook | None = ...,
    canonical: bool = ...,
    date_as_datetime: bool = ...,
    string_referencing: bool = ...,
    indefinite_containers: bool = ...,
) -> None: ...
def dumps(
    obj: object,
    *,
    datetime_as_timestamp: bool = ...,
    timezone: tzinfo | None = ...,
    value_sharing: bool = ...,
    encoders: Mapping[type, EncoderHook] | None = ...,
    default: EncoderHook | None = ...,
    canonical: bool = ...,
    date_as_datetime: bool = ...,
    string_referencing: bool = ...,
    indefinite_containers: bool = ...,
) -> bytes: ...
def load(
    fp: IO[bytes],
    *,
    tag_hook: TagHook | None = ...,
    object_hook: ObjectHook | None = ...,
    semantic_decoders: Mapping[int, SemanticDecoderCallback | ShareableDecoderInitializer]
    | None = ...,
    str_errors: str = ...,
    read_size: int = ...,
    max_depth: int = ...,
    allow_indefinite: bool = ...,
    immutable: bool = ...,
) -> Any: ...
def loads(
    data: bytes,
    *,
    tag_hook: TagHook | None = ...,
    object_hook: ObjectHook | None = ...,
    semantic_decoders: Mapping[int, SemanticDecoderCallback | ShareableDecoderInitializer]
    | None = ...,
    str_errors: str = ...,
    max_depth: int = ...,
    allow_indefinite: bool = ...,
    immutable: bool = ...,
) -> Any: ...
def shareable_encoder(
    wraps: Callable[[CBOREncoder, _T], None], /
) -> Callable[[CBOREncoder, _T], None]: ...
@overload
def shareable_decoder(func: ShareableDecoderInitializer, /) -> ShareableDecoderInitializer: ...
@overload
def shareable_decoder(
    *, name: str | None = ..., immutable: bool = ...
) -> Callable[[ShareableDecoderInitializer], ShareableDecoderCallback]: ...
