import asyncio
import time

import pytest

from gsearch_mcp_cli.core.rate_limiter import RateLimiter


@pytest.mark.asyncio
async def test_burst_allows_immediate():
    limiter = RateLimiter(rate=2.0, burst=3)
    start = time.monotonic()
    for _ in range(3):
        await limiter.acquire()
    elapsed = time.monotonic() - start
    assert elapsed < 0.5, f"Burst of 3 should be near-instant, took {elapsed:.2f}s"


@pytest.mark.asyncio
async def test_throttle_after_burst():
    limiter = RateLimiter(rate=1.0, burst=2)
    await limiter.acquire()
    await limiter.acquire()
    start = time.monotonic()
    await limiter.acquire()
    elapsed = time.monotonic() - start
    assert elapsed >= 0.8, f"Should wait ~1s after burst, waited {elapsed:.2f}s"


@pytest.mark.asyncio
async def test_context_manager():
    limiter = RateLimiter(rate=2.0, burst=3)
    async with limiter:
        pass
    async with limiter:
        pass


@pytest.mark.asyncio
async def test_concurrent_access():
    limiter = RateLimiter(rate=0.5, burst=2)
    timestamps = []

    async def worker():
        async with limiter:
            timestamps.append(time.monotonic())

    await asyncio.gather(*[worker() for _ in range(4)])
    assert len(timestamps) == 4
    # First 2 should be near-instant (burst), rest should be throttled
    gap = timestamps[-1] - timestamps[0]
    assert gap >= 0.4, f"Should take at least 0.4s for 4 requests with burst=2, rate=0.5, took {gap:.2f}s"


@pytest.mark.asyncio
async def test_refill_after_wait():
    limiter = RateLimiter(rate=0.3, burst=1)
    await limiter.acquire()
    await asyncio.sleep(0.4)
    start = time.monotonic()
    await limiter.acquire()
    elapsed = time.monotonic() - start
    assert elapsed < 0.2, f"Should have refilled after waiting, took {elapsed:.2f}s"
