from __future__ import annotations

from typing import TYPE_CHECKING

import pyrogram
from pyrogram import raw, types

if TYPE_CHECKING:
    from collections.abc import AsyncGenerator


class GetChatEventLog:
    async def get_chat_event_log(
        self: pyrogram.Client,
        chat_id: int | str,
        query: str = "",
        offset_id: int = 0,
        limit: int = 0,
        filters: types.ChatEventFilter = None,
        user_ids: list[int | str] | None = None,
    ) -> AsyncGenerator[types.ChatEvent, None] | None:
        """Get the actions taken by chat members and administrators in the last 48h.

        Only available for supergroups and channels. Requires administrator rights.
        Results are returned in reverse chronological order (i.e., newest first).

        .. include:: /_includes/usable-by/users.rst

        Parameters:
            chat_id (``int`` | ``str``):
                Unique identifier (int) or username (str) of the target chat.
                You can also use chat public link in form of *t.me/<username>* (str).

            query (``str``, *optional*):
                Search query to filter events based on text.
                By default, an empty query is applied and all events will be returned.

            offset_id (``int``, *optional*):
                Offset event identifier from which to start returning results.
                By default, no offset is applied and events will be returned starting from the latest.

            limit (``int``, *optional*):
                Maximum amount of events to be returned.
                By default, all events will be returned.

            filters (:obj:`~pyrogram.types.ChatEventFilter`, *optional*):
                The types of events to return.
                By default, all types will be returned.

            user_ids (List of ``int`` | ``str``, *optional*):
                User identifiers (int) or usernames (str) by which to filter events.
                By default, events relating to all users will be returned.

        Yields:
            :obj:`~pyrogram.types.ChatEvent` objects.

        Example:
            .. code-block:: python

                async for event in app.get_chat_event_log(chat_id):
                    print(event)
        """
        current = 0
        total = abs(limit) or (1 << 31)
        limit = min(100, total)

        while True:
            r: raw.base.channels.AdminLogResults = await self.invoke(
                raw.functions.channels.GetAdminLog(
                    channel=await self.resolve_peer(chat_id),
                    q=query,
                    min_id=0,
                    max_id=offset_id,
                    limit=limit,
                    events_filter=filters.write() if filters else None,
                    admins=(
                        [await self.resolve_peer(i) for i in user_ids]
                        if user_ids is not None
                        else user_ids
                    ),
                ),
            )

            if not r.events:
                return

            last = r.events[-1]
            offset_id = last.id

            for event in r.events:
                yield await types.ChatEvent._parse(self, event, r.users, r.chats)

                current += 1

                if current >= total:
                    return
