from typing import Any, Callable, Coroutine, Generic, List, Optional, TypeVar, Union
from typing_extensions import Final

from .audit_logs import AuditLogEntry
from .guild import Guild
from .http import _GuildDict, _GuildMemberDict
from .member import Member
from .message import Message
from .object import Object
from .user import User

OLDEST_OBJECT: Final[Object]

_IT = TypeVar('_IT')
_AIT = TypeVar('_AIT', bound=_AsyncIterator[Any])
_OIT = TypeVar('_OIT')
_VT = TypeVar('_VT')

class _AsyncIterator(Generic[_IT]):
    def get(self, **attrs: Any) -> Coroutine[Any, Any, Optional[_IT]]: ...
    async def find(
        self, predicate: Callable[[_IT], Union[bool, Coroutine[Any, Any, bool]]]
    ) -> Optional[_IT]: ...
    def chunk(self, max_size: int) -> _ChunkedAsyncIterator[_IT]: ...
    def map(
        self, func: Callable[[_IT], Union[_OIT, Coroutine[Any, Any, _OIT]]]
    ) -> _MappedAsyncIterator[_OIT]: ...
    def filter(
        self, predicate: Callable[[_IT], Union[bool, Coroutine[Any, Any, bool]]]
    ) -> _FilteredAsyncIterator[_IT]: ...
    async def flatten(self) -> List[_IT]: ...
    def __aiter__(self: _AIT) -> _AIT: ...
    async def __anext__(self) -> _IT: ...

def _identity(x: _VT) -> _VT: ...

class _ChunkedAsyncIterator(_AsyncIterator[List[_IT]]):
    async def next(self) -> List[_IT]: ...

class _MappedAsyncIterator(_AsyncIterator[_IT]):
    async def next(self) -> _IT: ...

class _FilteredAsyncIterator(_AsyncIterator[_IT]):
    async def next(self) -> _IT: ...

class ReactionIterator(_AsyncIterator[Union[User, Member]]):
    async def next(self) -> Union[User, Member]: ...
    async def fill_users(self) -> None: ...

class HistoryIterator(_AsyncIterator[Message]):
    async def next(self) -> Message: ...
    async def flatten(self) -> List[Message]: ...
    async def fill_messages(self) -> None: ...

class AuditLogIterator(_AsyncIterator[AuditLogEntry]):
    async def next(self) -> AuditLogEntry: ...

class GuildIterator(_AsyncIterator[Guild]):
    async def next(self) -> Guild: ...
    def create_guild(self, data: _GuildDict) -> Guild: ...
    async def flatten(self) -> List[Guild]: ...
    async def fill_guilds(self) -> None: ...

class MemberIterator(_AsyncIterator[Member]):
    async def next(self) -> Member: ...
    async def fill_members(self) -> None: ...
    async def create_member(self, data: _GuildMemberDict) -> Member: ...
