import asyncio
from typing import Any, Callable, ClassVar, Dict, Optional, Tuple

from .abc import Connectable
from .channel import VoiceChannel
from .client import Client
from .gateway import DiscordVoiceWebSocket
from .guild import Guild
from .player import AudioSource
from .user import ClientUser

class VoiceProtocol:
    client: Client
    channel: Connectable
    def __init__(self, client: Client, channel: Connectable) -> None: ...
    async def on_voice_state_update(self, data: Dict[str, Any]) -> None: ...
    async def on_voice_server_update(self, data: Dict[str, Any]) -> None: ...
    async def connect(self, *, timeout: float, reconnect: bool) -> None: ...
    async def disconnect(self, *, force: bool) -> None: ...
    def cleanup(self) -> None: ...

class VoiceClient(VoiceProtocol):
    warn_nacl: ClassVar[bool]
    supported_modes: ClassVar[Tuple[str, ...]]

    session_id: str
    token: str
    endpoint: str
    channel: Connectable
    loop: asyncio.AbstractEventLoop
    source: Optional[AudioSource]
    @property
    def guild(self) -> Optional[Guild]: ...
    @property
    def user(self) -> ClientUser: ...
    def checked_add(self, attr: str, value: int, limit: int) -> None: ...
    async def on_voice_state_update(self, data: Dict[str, Any]) -> None: ...
    async def on_voice_server_update(self, data: Dict[str, Any]) -> None: ...
    async def voice_connect(self) -> None: ...
    async def voice_disconnect(self) -> None: ...
    def prepare_handshake(self) -> None: ...
    def finish_handshake(self) -> None: ...
    async def connect_websocket(self) -> DiscordVoiceWebSocket: ...
    async def connect(self, *, timeout: float, reconnect: bool) -> None: ...
    async def potential_reconnect(self) -> bool: ...
    @property
    def latency(self) -> float: ...
    @property
    def average_latency(self) -> float: ...
    async def poll_voice_ws(self, reconnect: bool) -> None: ...
    async def disconnect(self, *, force: bool = ...) -> None: ...
    async def move_to(self, channel: VoiceChannel) -> None: ...
    def is_connected(self) -> bool: ...
    def play(
        self,
        source: AudioSource,
        *,
        after: Optional[Callable[[Optional[Exception]], None]] = ...,
    ) -> None: ...
    def is_playing(self) -> bool: ...
    def is_paused(self) -> bool: ...
    def stop(self) -> None: ...
    def pause(self) -> None: ...
    def resume(self) -> None: ...
    def send_audio_packet(self, data: bytes, *, encode: bool = ...) -> None: ...
