"""
ZXC - High-performance lossless compression

Copyright (c) 2025-2026 Bertrand Lebonnois and contributors.
SPDX-License-Identifier: BSD-3-Clause
"""

from typing import Protocol, Optional

# ---------- constants ----------
LEVEL_FASTEST: int
LEVEL_FAST: int
LEVEL_DEFAULT: int
LEVEL_BALANCED: int
LEVEL_COMPACT: int
LEVEL_DENSITY: int
LEVEL_ULTRA: int

# ---------- error codes ----------
ERROR_MEMORY: int
ERROR_DST_TOO_SMALL: int
ERROR_SRC_TOO_SMALL: int
ERROR_BAD_MAGIC: int
ERROR_BAD_VERSION: int
ERROR_BAD_HEADER: int
ERROR_BAD_CHECKSUM: int
ERROR_CORRUPT_DATA: int
ERROR_BAD_OFFSET: int
ERROR_OVERFLOW: int
ERROR_IO: int
ERROR_NULL_INPUT: int
ERROR_BAD_BLOCK_TYPE: int
ERROR_BAD_BLOCK_SIZE: int
ERROR_DICT_REQUIRED: int
ERROR_DICT_MISMATCH: int
ERROR_DICT_TOO_LARGE: int
ERROR_BAD_LEVEL: int

# ---------- types ----------
class FileLike(Protocol):
    """File-like object with a file descriptor.

    Note:
        This excludes in-memory streams like io.BytesIO.
        Use real file objects or objects wrapping OS file descriptors.
    """

    def fileno(self) -> int: ...
    def readable(self) -> bool: ...
    def writable(self) -> bool: ...

# ---------- functions ----------
def compress(
    data: bytes,
    level: int = LEVEL_DEFAULT,
    checksum: bool = False,
    dict: Optional[bytes] = None,
    dict_huf: Optional[bytes] = None,
) -> bytes: ...
def decompress(
    data: bytes,
    decompress_size: Optional[int] = None,
    checksum: bool = False,
    dict: Optional[bytes] = None,
    dict_huf: Optional[bytes] = None,
) -> bytes: ...
def stream_compress(
    src: FileLike,
    dst: FileLike,
    n_threads: int = 0,
    level: int = LEVEL_DEFAULT,
    checksum: bool = False,
    seekable: bool = False,
    dict: Optional[bytes] = None,
    dict_huf: Optional[bytes] = None,
) -> int: ...
def stream_decompress(
    src: FileLike, dst: FileLike, n_threads: int = 0, checksum: bool = False
) -> int: ...
def get_decompressed_size(data: bytes) -> int: ...

# ---------- pre-trained dictionaries ----------
def train_dict(samples: list[bytes], max_size: int = 65535) -> bytes: ...
def train_dict_huf(samples: list[bytes], dict: bytes) -> bytes: ...
def dict_id(content: bytes) -> int: ...
def get_dict_id(archive: bytes) -> int: ...
def dict_get_id(zxd: bytes) -> int: ...
def dict_save(content: bytes, huf_lengths: bytes) -> bytes: ...
def dict_load(zxd: bytes) -> tuple[bytes, int]: ...
def dict_huf(zxd: bytes) -> Optional[bytes]: ...

class Dictionary:
    content: bytes
    huf: bytes
    id: int
    def __init__(self, content: bytes, huf: bytes, id: int) -> None: ...
    @classmethod
    def train(cls, samples: list[bytes]) -> "Dictionary": ...
    @classmethod
    def load(cls, zxd: bytes) -> "Dictionary": ...
    def save(self) -> bytes: ...

def min_level() -> int: ...
def max_level() -> int: ...
def default_level() -> int: ...
def library_version() -> str: ...

# ---------- seekable random-access decompression ----------
class Seekable:
    """Random-access decompression of a seekable ZXC archive."""

    def __init__(self, source: bytes | bytearray | memoryview | object) -> None: ...
    @property
    def num_blocks(self) -> int: ...
    @property
    def decompressed_size(self) -> int: ...
    def block_compressed_size(self, block_idx: int) -> Optional[int]: ...
    def block_decompressed_size(self, block_idx: int) -> Optional[int]: ...
    def set_dict(self, dict: bytes, dict_huf: Optional[bytes] = None) -> None: ...
    def decompress_range(
        self, offset: int, length: int, *, n_threads: int = 0
    ) -> bytes: ...
    def close(self) -> None: ...
    def __enter__(self) -> "Seekable": ...
    def __exit__(self, exc_type, exc, tb) -> bool: ...

def seek_table_size(num_blocks: int) -> int: ...
def write_seek_table(comp_sizes: list[int]) -> bytes: ...

# ---------- push streaming ----------
class CStream:
    """Push-based, single-threaded compression stream."""

    def __init__(
        self, level: int = LEVEL_DEFAULT, checksum: bool = False, block_size: int = 0
    ) -> None: ...
    def compress(self, data: bytes) -> bytes: ...
    def end(self) -> bytes: ...
    @property
    def in_size(self) -> int: ...
    @property
    def out_size(self) -> int: ...
    def close(self) -> None: ...
    def __enter__(self) -> "CStream": ...
    def __exit__(self, exc_type, exc, tb) -> bool: ...

class DStream:
    """Push-based, single-threaded decompression stream."""

    def __init__(self, checksum: bool = False) -> None: ...
    def decompress(self, data: bytes) -> bytes: ...
    @property
    def finished(self) -> bool: ...
    @property
    def in_size(self) -> int: ...
    @property
    def out_size(self) -> int: ...
    def close(self) -> None: ...
    def __enter__(self) -> "DStream": ...
    def __exit__(self, exc_type, exc, tb) -> bool: ...

# ---------- io.RawIOBase adapters ----------
import io as _io
from typing import IO

def detect_zxc(data: bytes) -> bool: ...

class ZxcReader(_io.RawIOBase):
    """Decompresses a ZXC frame read from a binary file-like object."""

    def __init__(
        self,
        fileobj: IO[bytes],
        *,
        checksum: bool = False,
        buffer_size: int = 0,
    ) -> None: ...
    def readable(self) -> bool: ...
    def readinto(self, b: bytearray) -> Optional[int]: ...
    def close(self) -> None: ...

class ZxcWriter(_io.RawIOBase):
    """Compresses bytes written to it into a binary file-like object."""

    def __init__(
        self,
        fileobj: IO[bytes],
        *,
        level: int = LEVEL_DEFAULT,
        checksum: bool = False,
    ) -> None: ...
    def writable(self) -> bool: ...
    def write(self, b: bytes) -> int: ...
    def close(self) -> None: ...
