from typing import Any, Callable, Dict, List, Mapping, NamedTuple, Optional, Tuple

from bson.objectid import ObjectId
from pymongo.read_preferences import _ServerMode
from pymongo.server_description import ServerDescription

_Address = Tuple[str, Optional[int]]
_ServerSelector = Callable[[List[ServerDescription]], List[ServerDescription]]

class _TopologyType(NamedTuple):
    Single: int
    ReplicaSetNoPrimary: int
    ReplicaSetWithPrimary: int
    Sharded: int
    Unknown: int

TOPOLOGY_TYPE: _TopologyType
SRV_POLLING_TOPOLOGIES: Tuple[int, ...]

class TopologyDescription:
    def __init__(
        self,
        topology_type: int,
        server_descriptions: Mapping[_Address, ServerDescription],
        replica_set_name: Optional[str],
        max_set_version: Optional[int],
        max_election_id: Optional[ObjectId],
        topology_settings: Any,
    ) -> None: ...
    def check_compatible(self) -> None: ...
    def has_server(self, address: _Address) -> bool: ...
    def reset_server(self, address: _Address) -> TopologyDescription: ...
    def reset(self) -> TopologyDescription: ...
    def server_descriptions(self) -> Dict[_Address, ServerDescription]: ...
    @property
    def topology_type(self) -> int: ...
    @property
    def topology_type_name(self) -> str: ...
    @property
    def replica_set_name(self) -> Optional[str]: ...
    @property
    def max_set_version(self) -> Optional[int]: ...
    @property
    def max_election_id(self) -> Optional[ObjectId]: ...
    @property
    def logical_session_timeout_minutes(self) -> Optional[int]: ...
    @property
    def known_servers(self) -> List[ServerDescription]: ...
    @property
    def has_known_servers(self) -> bool: ...
    @property
    def readable_servers(self) -> List[ServerDescription]: ...
    @property
    def common_wire_version(self) -> Optional[int]: ...
    @property
    def heartbeat_frequency(self) -> int: ...
    def apply_selector(
        self, selector: Any, address: Optional[_Address], custom_selector: Optional[_ServerSelector] = ...
    ) -> List[ServerDescription]: ...
    def has_readable_server(self, read_preference: _ServerMode = ...) -> bool: ...
    def has_writable_server(self) -> bool: ...

def updated_topology_description(
    topology_description: TopologyDescription, server_description: ServerDescription
) -> TopologyDescription: ...
