"""Defense-in-depth: shared-secret gate поверх trusted-header auth (#2213).

Backend доверяет X-Authenticated-User (его ставит Caddy). На общей docker-сети
gendesign_shared любой контейнер мог бы отправить поддельный
`X-Authenticated-User: admin` напрямую на tradein-backend:8000, минуя Caddy.
Общий секрет X-Internal-Auth-Secret закрывает дыру: если TRADEIN_INTERNAL_AUTH_SECRET
задан, каждый запрос с X-Authenticated-User обязан нести валидный секрет (constant-time),
иначе 401. Пусто = fail-open (backward-compat до провижининга).

Использует РЕАЛЬНЫЙ rbac_guard (app/core/rbac.py) — тот же, что регистрирует
app/main.py в проде. Раньше здесь была hand-maintained копия ("MIRROR of
rbac_guard из app/main.py"); соседний test_rbac.py держал СВОЮ отдельную
копию, которая успела отстать (потеряла именно этот secret-gate) — регрессия
в реальном guard'е могла бы пройти CI незамеченной. См. app/core/rbac.py.
"""

from __future__ import annotations

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 auth as auth_mod
from app.core import config
from app.core.rbac import rbac_guard


@pytest.fixture(autouse=True)
def _reset_auth_cache() -> None:
    auth_mod.reset_cache_for_tests()


def _build_test_app() -> FastAPI:
    """Test app используя РЕАЛЬНЫЙ rbac_guard (с #2213 secret-gate)."""
    app = FastAPI()
    app.middleware("http")(rbac_guard)

    @app.get("/api/v1/ping")
    async def ping() -> dict:
        return {"ok": True}

    return app


@pytest.fixture
def client() -> TestClient:
    return TestClient(_build_test_app())


# ---------------------------------------------------------------------------
# (в) секрет НЕ задан → backward-compat: X-Authenticated-User достаточно.
# ---------------------------------------------------------------------------


def test_secret_unset_backward_compat(client: TestClient, monkeypatch) -> None:
    monkeypatch.setattr(config.settings, "tradein_internal_auth_secret", "")
    resp = client.get("/api/v1/ping", headers={"X-Authenticated-User": "admin"})
    assert resp.status_code == 200
    assert resp.json() == {"ok": True}


def test_secret_unset_ignores_provided_secret(client: TestClient, monkeypatch) -> None:
    # Если секрет не задан — присланный клиентом X-Internal-Auth-Secret игнорируется.
    monkeypatch.setattr(config.settings, "tradein_internal_auth_secret", "")
    resp = client.get(
        "/api/v1/ping",
        headers={"X-Authenticated-User": "admin", "X-Internal-Auth-Secret": "whatever"},
    )
    assert resp.status_code == 200


# ---------------------------------------------------------------------------
# (а) секрет задан + заголовок юзера БЕЗ секрета → 401.
# ---------------------------------------------------------------------------


def test_secret_set_missing_header_401(client: TestClient, monkeypatch) -> None:
    monkeypatch.setattr(config.settings, "tradein_internal_auth_secret", "s3cr3t-value")
    resp = client.get("/api/v1/ping", headers={"X-Authenticated-User": "admin"})
    assert resp.status_code == 401
    assert "internal auth secret" in resp.json()["detail"].lower()


def test_secret_set_wrong_secret_401(client: TestClient, monkeypatch) -> None:
    monkeypatch.setattr(config.settings, "tradein_internal_auth_secret", "s3cr3t-value")
    resp = client.get(
        "/api/v1/ping",
        headers={"X-Authenticated-User": "admin", "X-Internal-Auth-Secret": "wrong"},
    )
    assert resp.status_code == 401
    assert "internal auth secret" in resp.json()["detail"].lower()


# ---------------------------------------------------------------------------
# (б) секрет задан + оба заголовка корректны → 200 (существующее поведение).
# ---------------------------------------------------------------------------


def test_secret_set_correct_secret_200(client: TestClient, monkeypatch) -> None:
    monkeypatch.setattr(config.settings, "tradein_internal_auth_secret", "s3cr3t-value")
    resp = client.get(
        "/api/v1/ping",
        headers={"X-Authenticated-User": "admin", "X-Internal-Auth-Secret": "s3cr3t-value"},
    )
    assert resp.status_code == 200
    assert resp.json() == {"ok": True}


def test_secret_set_no_user_header_still_401(client: TestClient, monkeypatch) -> None:
    # Секрет без X-Authenticated-User — no-auth 401 (secret-gate не ослабляет базу).
    monkeypatch.setattr(config.settings, "tradein_internal_auth_secret", "s3cr3t-value")
    resp = client.get("/api/v1/ping", headers={"X-Internal-Auth-Secret": "s3cr3t-value"})
    assert resp.status_code == 401
    assert "no authenticated user" in resp.json()["detail"].lower()
