import asyncio
import time


class AsyncRateLimiter:
    """Token-bucket rate limiter for async contexts.

    Tokens refill at `rate` per second up to `burst` capacity.
    When tokens are exhausted, callers sleep the minimum time needed.
    The lock is released before sleeping so other callers aren't blocked.
    """

    def __init__(self, rate: float = 10.0, burst: int = 10):
        self._rate = rate
        self._burst = burst
        self._tokens = float(burst)
        self._last = time.monotonic()
        self._lock = asyncio.Lock()

    async def acquire(self) -> None:
        wait = 0.0
        async with self._lock:
            now = time.monotonic()
            elapsed = now - self._last
            self._tokens = min(self._burst, self._tokens + elapsed * self._rate)
            self._last = now
            if self._tokens < 1:
                wait = (1 - self._tokens) / self._rate
                self._tokens = 0
            else:
                self._tokens -= 1
        # Sleep outside the lock so other callers aren't blocked
        if wait > 0:
            await asyncio.sleep(wait)
