import pytest

from src.middlewares.rate_limiter import RateLimiter


class TestRateLimiterPathNormalization:
    def test_get_rate_limit_matches_versioned_api_prefix(self):
        limiter = RateLimiter()
        limit, window = limiter.get_rate_limit("/api/v1/generations/image")
        assert (limit, window) == (10, 60)

    def test_normalize_path_reduces_dynamic_segments(self):
        limiter = RateLimiter()
        assert limiter._normalize_path("/api/v1/projects/123") == "/projects/{id}"
        assert (
            limiter._normalize_path("/api/v1/tasks/550e8400-e29b-41d4-a716-446655440000")
            == "/tasks/{id}"
        )


@pytest.mark.asyncio
class TestRateLimiterLocalFallback:
    async def test_local_fallback_limits_critical_endpoint_when_redis_unavailable(self):
        limiter = RateLimiter()
        limiter._connected = False
        limiter.rate_limits["/generations/image"] = (2, 60)

        limited_1, _, _, _ = await limiter.is_rate_limited("ip:test", "/api/v1/generations/image")
        limited_2, _, _, _ = await limiter.is_rate_limited("ip:test", "/api/v1/generations/image")
        limited_3, _, limit, _ = await limiter.is_rate_limited("ip:test", "/api/v1/generations/image")

        assert limited_1 is False
        assert limited_2 is False
        assert limited_3 is True
        assert limit == 2

    async def test_local_fallback_not_used_for_non_critical_endpoint(self):
        limiter = RateLimiter()
        limiter._connected = False

        limited, count, limit, reset = await limiter.is_rate_limited("ip:test", "/api/v1/health")
        assert limited is False
        assert count == 0
        assert limit == 0
        assert reset == 0
