"""Tests for RateLimitMiddleware — per-IP sliding window + auth bypass (#655).

Тестируем middleware в изоляции на минимальном FastAPI-приложении, чтобы не
тянуть тяжёлый app.main (DB / scheduler / sentry). Лимит/окно читаются из
settings на каждый dispatch → monkeypatch'им их в маленькие значения.
"""

import os

os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://test:test@localhost:5432/test")

import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient

from app.core import config
from app.core.ratelimit import RateLimitMiddleware


@pytest.fixture
def client(monkeypatch):
    """Минимальное приложение с лимитом 3 запроса / 60 с (для быстрого 429)."""
    monkeypatch.setattr(config.settings, "rate_limit", 3)
    monkeypatch.setattr(config.settings, "rate_limit_window_s", 60.0)

    app = FastAPI()
    app.add_middleware(RateLimitMiddleware)

    @app.get("/api/v1/ping")
    def ping() -> dict[str, bool]:
        return {"ok": True}

    return TestClient(app)


def test_anonymous_throttled_past_limit(client):
    # Первые rate_limit запросов проходят, следующий — 429.
    for _ in range(3):
        assert client.get("/api/v1/ping").status_code == 200
    resp = client.get("/api/v1/ping")
    assert resp.status_code == 429
    assert resp.json() == {"detail": "Слишком много запросов. Попробуйте позже."}
    assert "Retry-After" in resp.headers


def test_authenticated_user_bypasses_limit(client):
    # X-Authenticated-User (Caddy basic_auth) → лимит не применяется.
    headers = {"X-Authenticated-User": "pilot@example.com"}
    for _ in range(10):  # сильно больше rate_limit=3
        assert client.get("/api/v1/ping", headers=headers).status_code == 200


def test_empty_auth_header_does_not_bypass(client):
    # Пустой заголовок не должен no-op'ить лимит (header present но falsy).
    headers = {"X-Authenticated-User": ""}
    for _ in range(3):
        assert client.get("/api/v1/ping", headers=headers).status_code == 200
    assert client.get("/api/v1/ping", headers=headers).status_code == 429
