import sys
from typing import (
    Iterator,
    Optional,
    TypeVar,
    Union,
    overload,
)

if sys.version_info < (3, 12):
    from typing_extensions import Buffer
else:
    from collections.abc import Buffer

_T = TypeVar("_T")

# Value returned by get/key/value/item etc.  bytes when buffers=False
# (the default), memoryview when buffers=True.
_Val = Union[bytes, memoryview]

__version__: str

# Module-level functions

def version() -> tuple[int, int, int]: ...
def enable_drop_gil() -> None: ...

# Exceptions

class Error(Exception):
    def __init__(self, what: str, code: int = ...) -> None: ...

class KeyExistsError(Error): ...
class NotFoundError(Error): ...
class PageNotFoundError(Error): ...
class CorruptedError(Error): ...
class PanicError(Error): ...
class VersionMismatchError(Error): ...
class InvalidError(Error): ...
class MapFullError(Error): ...
class DbsFullError(Error): ...
class ReadersFullError(Error): ...
class TlsFullError(Error): ...
class TxnFullError(Error): ...
class CursorFullError(Error): ...
class PageFullError(Error): ...
class MapResizedError(Error): ...
class IncompatibleError(Error): ...
class BadDbiError(Error): ...
class BadRslotError(Error): ...
class BadTxnError(Error): ...
class BadValsizeError(Error): ...
class ReadonlyError(Error): ...
class InvalidParameterError(Error): ...
class LockError(Error): ...
class MemoryError(Error): ...
class DiskError(Error): ...

# Core classes

class Environment:
    readonly: bool

    def __init__(
        self,
        path: str,
        map_size: int = ...,
        subdir: bool = ...,
        readonly: bool = ...,
        metasync: bool = ...,
        sync: bool = ...,
        map_async: bool = ...,
        mode: int = ...,
        create: bool = ...,
        readahead: bool = ...,
        writemap: bool = ...,
        meminit: bool = ...,
        max_readers: int = ...,
        max_dbs: int = ...,
        max_spare_txns: int = ...,
        lock: bool = ...,
    ) -> None: ...
    def __enter__(self) -> Environment: ...
    def __exit__(self, *args: object) -> None: ...
    def close(self) -> None: ...
    def path(self) -> str: ...
    def copy(
        self, path: str, compact: bool = ..., txn: Optional[Transaction] = ...
    ) -> None: ...
    def copyfd(
        self, fd: int, compact: bool = ..., txn: Optional[Transaction] = ...
    ) -> None: ...
    def sync(self, force: bool = ...) -> None: ...
    def stat(self) -> dict[str, int]: ...
    def info(self) -> dict[str, int]: ...
    def flags(self) -> dict[str, bool]: ...
    def max_key_size(self) -> int: ...
    def max_readers(self) -> int: ...
    def readers(self) -> str: ...
    def reader_check(self) -> int: ...
    def set_mapsize(self, map_size: int) -> None: ...
    def dbs(self, txn: Optional[Transaction] = ...) -> list[bytes]: ...
    def open_db(
        self,
        key: Optional[bytes] = ...,
        txn: Optional[Transaction] = ...,
        reverse_key: bool = ...,
        dupsort: bool = ...,
        create: bool = ...,
        integerkey: bool = ...,
        integerdup: bool = ...,
        dupfixed: bool = ...,
    ) -> _Database: ...
    def begin(
        self,
        db: Optional[_Database] = ...,
        parent: Optional[Transaction] = ...,
        write: bool = ...,
        buffers: bool = ...,
    ) -> Transaction: ...

open = Environment

class _Database:
    def flags(self) -> dict[str, bool]: ...

class Transaction:
    def __init__(
        self,
        env: Environment,
        db: Optional[_Database] = ...,
        parent: Optional[Transaction] = ...,
        write: bool = ...,
        buffers: bool = ...,
    ) -> None: ...
    def __enter__(self) -> Transaction: ...
    def __exit__(self, *args: object) -> None: ...
    def id(self) -> int: ...
    def stat(self, db: Optional[_Database] = ...) -> dict[str, int]: ...
    def drop(self, db: _Database, delete: bool = ...) -> None: ...
    def commit(self) -> None: ...
    def abort(self) -> None: ...
    @overload
    def get(
        self, key: Buffer, default: None = ..., db: Optional[_Database] = ...
    ) -> Optional[_Val]: ...
    @overload
    def get(
        self, key: Buffer, default: _T = ..., db: Optional[_Database] = ...
    ) -> Union[_Val, _T]: ...
    def put(
        self,
        key: Buffer,
        value: Buffer,
        dupdata: bool = ...,
        overwrite: bool = ...,
        append: bool = ...,
        db: Optional[_Database] = ...,
    ) -> bool: ...
    def replace(
        self, key: Buffer, value: Buffer, db: Optional[_Database] = ...
    ) -> Optional[_Val]: ...
    def pop(
        self, key: Buffer, db: Optional[_Database] = ...
    ) -> Optional[_Val]: ...
    def delete(
        self, key: Buffer, value: Buffer = ..., db: Optional[_Database] = ...
    ) -> bool: ...
    def cursor(self, db: Optional[_Database] = ...) -> Cursor: ...

class Cursor:
    def __init__(self, db: _Database, txn: Transaction) -> None: ...
    def __enter__(self) -> Cursor: ...
    def __exit__(self, *args: object) -> None: ...
    def __iter__(self) -> Iterator[tuple[_Val, _Val]]: ...
    def close(self) -> None: ...
    def key(self) -> _Val: ...
    def value(self) -> _Val: ...
    def item(self) -> tuple[_Val, _Val]: ...

    # Positioning
    def first(self) -> bool: ...
    def first_dup(self) -> bool: ...
    def last(self) -> bool: ...
    def last_dup(self) -> bool: ...
    def next(self) -> bool: ...
    def next_dup(self) -> bool: ...
    def next_nodup(self) -> bool: ...
    def prev(self) -> bool: ...
    def prev_dup(self) -> bool: ...
    def prev_nodup(self) -> bool: ...
    def set_key(self, key: Buffer) -> bool: ...
    def set_key_dup(self, key: Buffer, value: Buffer) -> bool: ...
    def set_range(self, key: Buffer) -> bool: ...
    def set_range_dup(self, key: Buffer, value: Buffer) -> bool: ...

    # Data operations
    @overload
    def get(self, key: Buffer, default: None = ...) -> Optional[_Val]: ...
    @overload
    def get(self, key: Buffer, default: _T = ...) -> Union[_Val, _T]: ...
    def getmulti(
        self,
        keys: list[Buffer],
        dupdata: bool = ...,
        dupfixed_bytes: Optional[int] = ...,
        keyfixed: bool = ...,
    ) -> list[tuple[_Val, _Val]]: ...
    def put(
        self,
        key: Buffer,
        val: Buffer,
        dupdata: bool = ...,
        overwrite: bool = ...,
        append: bool = ...,
    ) -> bool: ...
    def putmulti(
        self,
        items: list[tuple[Buffer, Buffer]],
        dupdata: bool = ...,
        overwrite: bool = ...,
        append: bool = ...,
    ) -> tuple[int, int]: ...
    def delete(self, dupdata: bool = ...) -> bool: ...
    def replace(self, key: Buffer, val: Buffer) -> Optional[_Val]: ...
    def pop(self, key: Buffer) -> Optional[_Val]: ...
    def count(self) -> int: ...

    # Iteration
    @overload
    def iternext(self) -> Iterator[tuple[_Val, _Val]]: ...
    @overload
    def iternext(
        self, keys: bool = ..., values: bool = ...
    ) -> Iterator[Union[_Val, tuple[_Val, _Val]]]: ...
    @overload
    def iternext_dup(self) -> Iterator[_Val]: ...
    @overload
    def iternext_dup(
        self, keys: bool = ..., values: bool = ...
    ) -> Iterator[Union[_Val, tuple[_Val, _Val]]]: ...
    @overload
    def iternext_nodup(self) -> Iterator[_Val]: ...
    @overload
    def iternext_nodup(
        self, keys: bool = ..., values: bool = ...
    ) -> Iterator[Union[_Val, tuple[_Val, _Val]]]: ...
    @overload
    def iterprev(self) -> Iterator[tuple[_Val, _Val]]: ...
    @overload
    def iterprev(
        self, keys: bool = ..., values: bool = ...
    ) -> Iterator[Union[_Val, tuple[_Val, _Val]]]: ...
    @overload
    def iterprev_dup(self) -> Iterator[_Val]: ...
    @overload
    def iterprev_dup(
        self, keys: bool = ..., values: bool = ...
    ) -> Iterator[Union[_Val, tuple[_Val, _Val]]]: ...
    @overload
    def iterprev_nodup(self) -> Iterator[_Val]: ...
    @overload
    def iterprev_nodup(
        self, keys: bool = ..., values: bool = ...
    ) -> Iterator[Union[_Val, tuple[_Val, _Val]]]: ...

    def _iter_from(
        self, k: Buffer, reverse: bool
    ) -> Iterator[tuple[_Val, _Val]]: ...

__all__: list[str]
