"""
Auth gate tests for R1-B+D.

Covers:
- /api/admin/* requires bearer token (401 without, not 401 with valid).
- Mutating routes on family routers require a session cookie.
- /api/auth/login + /api/auth/logout round-trip with the shared password.
"""

from __future__ import annotations

import os

import pytest


# Configure auth secrets BEFORE app import. conftest.py runs first and sets
# DATABASE_URL; we layer auth env on top here.
os.environ.setdefault("ADMIN_TOKEN", "test-admin-token")
os.environ.setdefault("SESSION_PASSWORD", "test-family-password")
os.environ.setdefault("SECRET_KEY", "test-secret-key-do-not-use-in-prod")


@pytest.fixture(autouse=True)
def _reload_settings(monkeypatch):
    """Force ``settings`` to re-read env (test isolation)."""
    monkeypatch.setenv("ADMIN_TOKEN", "test-admin-token")
    monkeypatch.setenv("SESSION_PASSWORD", "test-family-password")
    monkeypatch.setenv("SECRET_KEY", "test-secret-key-do-not-use-in-prod")
    # Re-instantiate the singleton so dependents pick up env.
    from app import config as app_config

    app_config.settings = app_config.Settings()
    yield


# ---------------------------------------------------------------------------
# Admin bearer token
# ---------------------------------------------------------------------------
@pytest.mark.requires_postgres
def test_admin_requires_token(client):
    """No bearer → 401. Valid bearer → not 401 (handler runs)."""
    r = client.post("/api/admin/scrape")
    assert r.status_code == 401, r.text

    r = client.post(
        "/api/admin/scrape",
        headers={"Authorization": "Bearer test-admin-token"},
    )
    # Handler may 200/202/500 (Playwright not installed in CI), but NOT 401.
    assert r.status_code != 401, r.text


@pytest.mark.requires_postgres
def test_admin_logs_requires_token(client):
    r = client.get("/api/admin/logs")
    assert r.status_code == 401

    r = client.get(
        "/api/admin/logs", headers={"Authorization": "Bearer test-admin-token"}
    )
    assert r.status_code == 200


# ---------------------------------------------------------------------------
# Session-gated mutations
# ---------------------------------------------------------------------------
@pytest.mark.requires_postgres
def test_session_required_for_mutation(client):
    """POST /api/profile/members without cookie → 401."""
    r = client.post(
        "/api/profile/members",
        json={"name": "x", "email": "x@y.z", "role": "voter"},
    )
    assert r.status_code == 401, r.text


@pytest.mark.requires_postgres
def test_session_open_for_reads(client):
    """GET /api/profile is NOT auth-gated (reads stay open)."""
    r = client.get("/api/profile")
    # Either 200 (profile exists) or 404 (no profile yet) — never 401.
    assert r.status_code in (200, 404), r.text


# ---------------------------------------------------------------------------
# Login / logout
# ---------------------------------------------------------------------------
@pytest.mark.requires_postgres
def test_session_login_logout(client):
    # Wrong password
    r = client.post("/api/auth/login", json={"password": "nope"})
    assert r.status_code == 401

    # Right password sets the cookie
    r = client.post(
        "/api/auth/login", json={"password": "test-family-password"}
    )
    assert r.status_code == 204
    assert "mp_session" in r.cookies, r.headers

    # With cookie, mutation succeeds (or fails for non-auth reasons)
    cookie_value = r.cookies.get("mp_session")
    client.cookies.set("mp_session", cookie_value)
    r2 = client.post(
        "/api/profile/members",
        json={"name": "x", "email": "test@example.com", "role": "voter"},
    )
    # 401 means the cookie was rejected — that's the bug we're guarding.
    assert r2.status_code != 401, r2.text

    # Logout clears the cookie
    r3 = client.post("/api/auth/logout")
    assert r3.status_code == 204
