"""Production configuration guard (task 8.8).

Regression test for a bug found the first time the stack ran for real: compose's
`--env-file` feeds ${...} interpolation but does not put variables inside the container,
so the API started on its built-in defaults without complaining. In dev that is merely
wrong; in prod it would mean signing session cookies with a secret committed to this repo.
"""

import pytest

from app.config import Settings

REAL_VALUES = {
    "session_secret": "a-real-generated-secret",
    # At least 32 characters: the guard enforces HS256's key floor, not just "not the
    # placeholder", because a short key weakens every signature it makes.
    "jwt_secret": "a-real-generated-jwt-secret-of-sufficient-length",
    "seed_super_admin_email": "owner@example.com",
    "token_pepper": "a-real-generated-pepper",
    "google_client_id": "123.apps.googleusercontent.com",
    "email_provider_api_key": "re_live_key",
    "email_webhook_secret": "whsec_cmVhbC1zZWNyZXQ=",
    "turnstile_secret_key": "0x4AAAAAAAreal",
    "app_base_url": "https://wedding.example.com",
}


@pytest.fixture(autouse=True)
def _isolated_environment(monkeypatch: pytest.MonkeyPatch) -> None:
    """Build Settings from the arguments alone, ignoring the ambient environment.

    Without this the suite passes on a laptop and fails in the container, where
    `.env.dev` has already exported AUTH_DEV_BYPASS and the placeholder keys — so a test
    asserting "GOOGLE_CLIENT_ID is missing" would see the container's value instead and
    fail for a reason that has nothing to do with the guard.
    """
    for field in Settings.model_fields:
        monkeypatch.delenv(field.upper(), raising=False)


def test_dev_tolerates_placeholders() -> None:
    """Local development must stay frictionless — the guard applies to prod only."""
    Settings(environment="dev").assert_production_ready()


def test_prod_rejects_every_placeholder_at_once() -> None:
    settings = Settings(environment="prod")
    with pytest.raises(RuntimeError) as exc:
        settings.assert_production_ready()

    message = str(exc.value)
    for name in (
        "SESSION_SECRET",
        "TOKEN_PEPPER",
        "GOOGLE_CLIENT_ID",
        "EMAIL_PROVIDER_API_KEY",
        "TURNSTILE_SECRET_KEY",
    ):
        assert name in message


@pytest.mark.parametrize("field", sorted(REAL_VALUES))
def test_prod_rejects_each_placeholder_individually(field: str) -> None:
    """One missing secret must fail even when everything else is set."""
    values = dict(REAL_VALUES)
    del values[field]
    with pytest.raises(RuntimeError, match=field.upper()):
        Settings(environment="prod", **values).assert_production_ready()


def test_prod_accepts_a_fully_configured_environment() -> None:
    Settings(environment="prod", **REAL_VALUES).assert_production_ready()


def test_a_localhost_base_url_is_rejected_in_prod() -> None:
    """Every link preview, invitation URL and unsubscribe link is built from this value.
    Left on the default they all point at the guest's own machine, and development cannot
    reveal the mistake because in development the default is correct."""
    values = dict(REAL_VALUES, app_base_url="http://localhost")
    with pytest.raises(RuntimeError, match="APP_BASE_URL"):
        Settings(environment="prod", **values).assert_production_ready()


def test_a_plaintext_base_url_is_rejected_in_prod() -> None:
    """A token in a URL is a bearer secret; sending it over plain HTTP hands it to anyone
    on the path."""
    values = dict(REAL_VALUES, app_base_url="http://wedding.example.com")
    with pytest.raises(RuntimeError, match="APP_BASE_URL"):
        Settings(environment="prod", **values).assert_production_ready()


def test_turnstile_test_key_is_rejected_in_prod() -> None:
    """Cloudflare's 1x0000... key always passes, so shipping it disables bot protection
    entirely while still looking configured."""
    values = dict(REAL_VALUES, turnstile_secret_key="1x0000000000000000000000000000000AA")
    with pytest.raises(RuntimeError, match="TURNSTILE_SECRET_KEY"):
        Settings(environment="prod", **values).assert_production_ready()
