from typing import Any, Dict, Iterable, List, Mapping, Optional, Sequence, Tuple, Union, overload

from bson.code import Code
from pymongo.client_session import ClientSession
from pymongo.collation import Collation
from pymongo.collection import Collection

class CursorType:
    NON_TAILABLE: int = ...
    TAILABLE: int = ...
    TAILABLE_AWAIT: int = ...
    EXHAUST: int = ...

_Sort = Sequence[Tuple[str, Union[int, str, Mapping[str, Any]]]]
_Hint = Union[str, _Sort]
_Collation = Union[Mapping[str, Any], Collation]
_DocumentOut = Any

class Cursor:
    def __init__(
        self,
        collection: Collection,
        filter: Optional[Mapping[str, Any]] = ...,
        projection: Optional[Union[Mapping[str, Any], Iterable[str]]] = ...,
        skip: int = ...,
        limit: int = ...,
        no_cursor_timeout: bool = ...,
        cursor_type: int = ...,
        sort: Optional[_Sort] = ...,
        allow_partial_results: bool = ...,
        oplog_replay: bool = ...,
        modifiers: Optional[Mapping[str, Any]] = ...,
        batch_size: int = ...,
        manipulate: bool = ...,
        collation: Optional[_Collation] = ...,
        hint: Optional[_Hint] = ...,
        max_scan: Optional[int] = ...,
        max_time_ms: Optional[int] = ...,
        max: Optional[_Sort] = ...,
        min: Optional[_Sort] = ...,
        return_key: Optional[bool] = ...,
        show_record_id: Optional[bool] = ...,
        snapshot: Optional[bool] = ...,
        comment: Any = ...,
        session: Optional[ClientSession] = ...,
        allow_disk_use: Optional[bool] = ...,
    ) -> None: ...
    @property
    def collection(self) -> Collection: ...
    @property
    def retrieved(self) -> int: ...
    def __del__(self) -> None: ...
    def rewind(self) -> Cursor: ...
    def clone(self) -> Cursor: ...
    def close(self) -> None: ...
    def add_option(self, mask: int) -> Cursor: ...
    def remove_option(self, mask: int) -> Cursor: ...
    def allow_disk_use(self, allow_disk_use: bool): ...
    def limit(self, limit: int) -> Cursor: ...
    def batch_size(self, batch_size: int) -> Cursor: ...
    def skip(self, skip: int) -> Cursor: ...
    def max_time_ms(self, max_time_ms: Optional[int]) -> Cursor: ...
    def max_await_time_ms(self, max_await_time_ms: Optional[int]) -> Cursor: ...
    @overload
    def __getitem__(self, index: int) -> _DocumentOut: ...
    @overload
    def __getitem__(self, index: slice) -> Cursor: ...
    def max_scan(self, max_scan: Optional[int]) -> Cursor: ...
    def max(self, spec: _Sort) -> Cursor: ...
    def min(self, spec: _Sort) -> Cursor: ...
    def sort(self, key_or_list: _Hint, direction: Optional[Union[int, str]] = ...) -> Cursor: ...
    def count(self, with_limit_and_skip: bool = ...) -> int: ...
    def distinct(self, key: str) -> List[Any]: ...
    def explain(self) -> _DocumentOut: ...
    def hint(self, index: Optional[_Hint]) -> Cursor: ...
    def comment(self, comment: Any) -> Cursor: ...
    def where(self, code: Union[str, Code]) -> Cursor: ...
    def collation(self, collation: Optional[_Collation]) -> Cursor: ...
    @property
    def alive(self) -> bool: ...
    @property
    def cursor_id(self) -> Optional[int]: ...
    @property
    def address(self) -> Optional[Tuple[str, Any]]: ...
    @property
    def session(self) -> Optional[ClientSession]: ...
    def __iter__(self) -> Cursor: ...
    def next(self) -> _DocumentOut: ...
    def __next__(self) -> _DocumentOut: ...
    def __enter__(self) -> Cursor: ...
    def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None: ...
    def __copy__(self) -> Cursor: ...
    def __deepcopy__(self, memo: Any) -> Any: ...

class RawBatchCursor(Cursor):
    def next(self) -> bytes: ...
    def __next__(self) -> bytes: ...
