from typing import Optional, Union, Any, BinaryIO, List, Dict, final
import os

__all__ = [
    "EntryName", "FileMetadata", "MLAWriter", "MLAReader",
    "WriterConfig", "ReaderConfig", "SignatureConfig",
    "PublicKeys", "PrivateKeys", "DEFAULT_COMPRESSION_LEVEL",
    # Exceptions
    "MLAError", "WrongMagic", "UnsupportedVersion", "InvalidKeyFormat",
    "WrongBlockSubFileType", "UTF8ConversionError", "EntryNameTooLong",
    "WrongArchiveWriterState", "WrongReaderState", "WrongWriterState",
    "RandError", "PrivateKeyNeeded", "DeserializationError", "SerializationError",
    "MissingMetadata", "BadAPIArgument", "EndOfStream", "ConfigError",
    "DuplicateEntryName", "AuthenticatedDecryptionWrongTag", "HKDFInvalidKeyLength",
    "HPKEError", "InvalidLastTag", "WrongEndMagic", "NoValidSignatureFound",
    "SignatureVerificationAskedButNoSignatureLayerFound",
    "MissingEndOfEncryptedInnerLayerMagic", "TruncatedTag", "UnknownTagPosition",
    "MLAOther"
]

@final
class EntryName:
    def __new__(cls, str_path: str) -> "EntryName": ...
    @staticmethod
    def from_path(path: os.PathLike[str]) -> "EntryName": ...
    @staticmethod
    def from_arbitrary_bytes(bytes: bytes) -> "EntryName": ...
    @property
    def arbitrary_bytes(self) -> bytes: ...
    def raw_content_to_escaped_string(self) -> str: ...
    def to_pathbuf(self) -> str: ...
    def to_pathbuf_escaped_string(self) -> str: ...
    def __hash__(self) -> int: ...
    def __eq__(self, other: object) -> bool: ...
    def __ne__(self, other: object) -> bool: ...
    def __repr__(self) -> str: ...

@final
class FileMetadata:
    size: Optional[int]
    hash: Optional[bytes]

@final
class MLAWriter:
    def __new__(cls, path: str, config: "WriterConfig") -> "MLAWriter": ...
    def __repr__(self) -> str: ...
    def __setitem__(self, key: EntryName, value: bytes) -> None: ...
    def finalize(self) -> None: ...
    _buffered_type: Any
    def add_entry_from(self, key: EntryName, src: Union[str, BinaryIO], chunk_size: int = 4194304) -> None: ...
    def __enter__(self) -> "MLAWriter": ...
    def __exit__(self, exc_type: Optional[type] = ..., _exc_value: Optional[BaseException] = ..., _traceback: Optional[Any] = ...) -> bool: ...

@final
class MLAReader:
    def __new__(cls, path: str, config: "ReaderConfig") -> "MLAReader": ...
    def __repr__(self) -> str: ...
    def __getitem__(self, key: EntryName) -> bytes: ...
    def __contains__(self, key: EntryName) -> bool: ...
    def __len__(self) -> int: ...
    def keys(self) -> List[EntryName]: ...
    def list_entries(self, include_size: bool = False, include_hash: bool = False) -> Union[List[EntryName], Dict[EntryName, FileMetadata]]: ...
    def write_entry_to(self, key: EntryName, dest: Union[str, BinaryIO], chunk_size: int = 4194304) -> None: ...
    def __enter__(self) -> "MLAReader": ...
    def __exit__(self, _exc_type: Optional[type] = ..., _exc_value: Optional[BaseException] = ..., _traceback: Optional[Any] = ...) -> bool: ...

@final
class WriterConfig:
    def __new__(cls, private_keys: "PrivateKeys", public_keys: "PublicKeys") -> "WriterConfig": ...
    @classmethod
    def without_encryption_without_signature(cls) -> "WriterConfig": ...
    @classmethod
    def with_encryption_without_signature(cls, public_keys: "PublicKeys") -> "WriterConfig": ...
    @classmethod
    def without_encryption_with_signature(cls, private_keys: "PrivateKeys") -> "WriterConfig": ...
    def with_compression_level(self, compression_level: int) -> "WriterConfig": ...
    def without_compression(self) -> "WriterConfig": ...

@final
class ReaderConfig:
    def __new__(cls, private_keys: Optional["PrivateKeys"], signature_config: "SignatureConfig") -> "ReaderConfig": ...
    @classmethod
    def without_encryption(cls, signature_config: "SignatureConfig") -> "ReaderConfig": ...
    @classmethod
    def with_private_keys_accept_unencrypted(cls, private_keys: "PrivateKeys", signature_config: "SignatureConfig") -> "ReaderConfig": ...

@final
class SignatureConfig:
    def __new__(cls, public_keys: "PublicKeys") -> "SignatureConfig": ...
    @classmethod
    def without_signature_verification(cls) -> "SignatureConfig": ...

@final
class PublicKeys:
    def __new__(cls, *keys: Union[bytes, str]) -> "PublicKeys": ...
    keys: List[str]

@final
class PrivateKeys:
    def __new__(cls, *keys: Union[bytes, str]) -> "PrivateKeys": ...
    keys: List[str]

# Constants
DEFAULT_COMPRESSION_LEVEL: int

# Exceptions
class MLAError(Exception): ...
class WrongMagic(MLAError): ...
class UnsupportedVersion(MLAError): ...
class InvalidKeyFormat(MLAError): ...
class WrongBlockSubFileType(MLAError): ...
class UTF8ConversionError(MLAError): ...
class EntryNameTooLong(MLAError): ...
class WrongArchiveWriterState(MLAError): ...
class WrongReaderState(MLAError): ...
class WrongWriterState(MLAError): ...
class RandError(MLAError): ...
class PrivateKeyNeeded(MLAError): ...
class DeserializationError(MLAError): ...
class SerializationError(MLAError): ...
class MissingMetadata(MLAError): ...
class BadAPIArgument(MLAError): ...
class EndOfStream(MLAError): ...
class ConfigError(MLAError): ...
class DuplicateEntryName(MLAError): ...
class AuthenticatedDecryptionWrongTag(MLAError): ...
class HKDFInvalidKeyLength(MLAError): ...
class HPKEError(MLAError): ...
class InvalidLastTag(MLAError): ...
class WrongEndMagic(MLAError): ...
class NoValidSignatureFound(MLAError): ...
class SignatureVerificationAskedButNoSignatureLayerFound(MLAError): ...
class MissingEndOfEncryptedInnerLayerMagic(MLAError): ...
class TruncatedTag(MLAError): ...
class UnknownTagPosition(MLAError): ...
class MLAOther(MLAError): ...
