# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.

import datetime
import typing

T = typing.TypeVar("T")

def decode_der(cls: type[T], value: bytes) -> T: ...
def encode_der(value: typing.Any) -> bytes: ...
def non_root_python_to_rust(cls: type) -> Type: ...

# Type is a Rust enum with tuple variants. For now, we express the type
# annotations like this:
class Type:
    Sequence: typing.ClassVar[type]
    SequenceOf: typing.ClassVar[type]
    Set: typing.ClassVar[type]
    SetOf: typing.ClassVar[type]
    Option: typing.ClassVar[type]
    Choice: typing.ClassVar[type]
    ValueSet: typing.ClassVar[type]
    PyBool: typing.ClassVar[type]
    PyInt: typing.ClassVar[type]
    PyBytes: typing.ClassVar[type]
    PyStr: typing.ClassVar[type]

class Annotation:
    default: typing.Any | None
    encoding: Encoding | None
    size: Size | None
    def __new__(
        cls,
        default: typing.Any | None = None,
        encoding: Encoding | None = None,
        size: Size | None = None,
    ) -> Annotation: ...
    def is_empty(self) -> bool: ...

# Encoding is a Rust enum with tuple variants. For now, we express the type
# annotations like this:
class Encoding:
    Implicit: typing.ClassVar[type]
    Explicit: typing.ClassVar[type]

class Size:
    min: int
    max: int | None

    def __new__(cls, min: int, max: int | None) -> Size: ...
    @staticmethod
    def exact(n: int) -> Size: ...

class AnnotatedType:
    inner: Type
    annotation: Annotation

    def __new__(cls, inner: Type, annotation: Annotation) -> AnnotatedType: ...

class AnnotatedTypeObject:
    annotated_type: AnnotatedType
    value: typing.Any

    def __new__(
        cls, annotated_type: AnnotatedType, value: typing.Any
    ) -> AnnotatedTypeObject: ...

class Variant:
    python_class: type
    ann_type: AnnotatedType
    tag_name: str | None

    def __new__(
        cls,
        python_class: type,
        ann_type: AnnotatedType,
        tag_name: str | None,
    ) -> Variant: ...

class PrintableString:
    def __new__(cls, inner: str) -> PrintableString: ...
    def __repr__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...
    def __hash__(self) -> int: ...
    def as_str(self) -> str: ...

class IA5String:
    def __new__(cls, inner: str) -> IA5String: ...
    def __repr__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...
    def __hash__(self) -> int: ...
    def as_str(self) -> str: ...

class UTCTime:
    def __new__(cls, inner: datetime.datetime) -> UTCTime: ...
    def __repr__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...
    def __hash__(self) -> int: ...
    def as_datetime(self) -> datetime.datetime: ...

class GeneralizedTime:
    def __new__(cls, inner: datetime.datetime) -> GeneralizedTime: ...
    def __repr__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...
    def __hash__(self) -> int: ...
    def as_datetime(self) -> datetime.datetime: ...

class BitString:
    def __new__(cls, data: bytes, padding_bits: int) -> BitString: ...
    def __repr__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...
    def __hash__(self) -> int: ...
    def as_bytes(self) -> bytes: ...
    def padding_bits(self) -> int: ...

class Tlv:
    @property
    def tag_bytes(self) -> bytes: ...
    @property
    def data(self) -> memoryview: ...
    def parse(self, cls: type): ...

class SetOf(typing.Generic[T]):
    def __new__(cls, inner: list[T]) -> SetOf[T]: ...
    def as_list(self) -> list[T]: ...
    def __eq__(self, other: object) -> bool: ...
    def __repr__(self) -> str: ...

class Null:
    def __new__(cls) -> Null: ...
    def __repr__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...
