import time
from collections.abc import Awaitable, Callable
from typing import Any

from aiogram import BaseMiddleware
from aiogram.types import CallbackQuery, Message, TelegramObject

RATE_LIMIT_SECONDS = 0.7
CLEANUP_AFTER = 3600


class ThrottlingMiddleware(BaseMiddleware):
    """Drops button/message spam so expensive calls are not repeated."""

    def __init__(self, rate: float = RATE_LIMIT_SECONDS) -> None:
        self.rate = rate
        self._last: dict[int, float] = {}

    async def __call__(
        self,
        handler: Callable[[TelegramObject, dict[str, Any]], Awaitable[Any]],
        event: TelegramObject,
        data: dict[str, Any],
    ) -> Any:
        user = data.get("event_from_user")
        if user is None:
            return await handler(event, data)

        now = time.monotonic()
        last = self._last.get(user.id, 0.0)
        if now - last < self.rate:
            if isinstance(event, CallbackQuery):
                await event.answer()
            return None

        self._last[user.id] = now
        if len(self._last) > 5000:
            self._last = {
                key: value for key, value in self._last.items() if now - value < CLEANUP_AFTER
            }

        if isinstance(event, (Message, CallbackQuery)):
            return await handler(event, data)
        return await handler(event, data)
