"""
Tests for HttpOnly cookie authentication and SlowAPI rate limiting (Phase 3).
"""

import pytest
import pytest_asyncio
from httpx import AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.security import hash_password
from app.models.lab import Lab
from app.models.user import User, UserRole


@pytest_asyncio.fixture
async def sec_lab(db_session: AsyncSession) -> Lab:
    lab = Lab(name="Security Branch", address="Kathmandu")
    db_session.add(lab)
    await db_session.commit()
    await db_session.refresh(lab)
    return lab


@pytest_asyncio.fixture
async def sec_user(db_session: AsyncSession, sec_lab: Lab) -> User:
    user = User(
        lab_id=sec_lab.id,
        name="Security Staff",
        phone="9811122233",
        email="secstaff@munal.test",
        role=UserRole.DOCTOR,
        hashed_password=hash_password("SuperSecretPass123!"),
        is_active=True,
    )
    db_session.add(user)
    await db_session.commit()
    await db_session.refresh(user)
    return user


@pytest.mark.asyncio
async def test_login_sets_httponly_cookies(client: AsyncClient, sec_user: User) -> None:
    """Login issues access_token and refresh_token as HttpOnly cookies."""
    res = await client.post(
        "/api/v1/auth/login",
        json={"phone": sec_user.phone, "password": "SuperSecretPass123!"},
    )
    assert res.status_code == 200
    assert "access_token" in res.cookies
    assert "refresh_token" in res.cookies


@pytest.mark.asyncio
async def test_auth_me_via_httponly_cookie(client: AsyncClient, sec_user: User) -> None:
    """User can authenticate to /api/v1/auth/me solely via access_token cookie without Bearer header."""
    login_res = await client.post(
        "/api/v1/auth/login",
        json={"phone": sec_user.phone, "password": "SuperSecretPass123!"},
    )
    assert login_res.status_code == 200
    access_token = login_res.cookies.get("access_token")
    assert access_token is not None

    # Request /me with cookie only, no Authorization header
    me_res = await client.get("/api/v1/auth/me", cookies={"access_token": access_token})
    assert me_res.status_code == 200
    body = me_res.json()
    assert body["success"] is True
    assert body["data"]["id"] == str(sec_user.id)


@pytest.mark.asyncio
async def test_logout_clears_cookies(client: AsyncClient, sec_user: User) -> None:
    """Logout deletes access_token and refresh_token cookies."""
    login_res = await client.post(
        "/api/v1/auth/login",
        json={"phone": sec_user.phone, "password": "SuperSecretPass123!"},
    )
    assert login_res.status_code == 200
    access_cookie = login_res.cookies.get("access_token")

    logout_res = await client.post(
        "/api/v1/auth/logout",
        cookies={"access_token": access_cookie},
    )
    assert logout_res.status_code == 200
    # Cookie should be cleared / expired
    set_cookie_headers = logout_res.headers.get_list("set-cookie")
    assert any("access_token" in h and "max-age=0" in h.lower() for h in set_cookie_headers) or any(
        "access_token=" in h and "expires=" in h.lower() for h in set_cookie_headers
    )


@pytest.mark.asyncio
async def test_login_rate_limiting(client: AsyncClient) -> None:
    """Public login endpoint limits brute-force attempts with HTTP 429 RATE_LIMIT_EXCEEDED."""
    from app.core.rate_limit import limiter

    # Temporarily enable limiter for this explicit rate limit test
    prev_enabled = limiter.enabled
    limiter.enabled = True
    try:
        hit_429 = False
        for _ in range(10):
            res = await client.post(
                "/api/v1/auth/login",
                json={"phone": "9800000999", "password": "WrongPassword!"},
            )
            if res.status_code == 429:
                hit_429 = True
                body = res.json()
                assert body["success"] is False
                assert body["error"]["code"] == "RATE_LIMIT_EXCEEDED"
                break
        assert hit_429, "Rate limiter did not throttle requests after 5 attempts"
    finally:
        limiter.enabled = prev_enabled
