from types import SimpleNamespace
from unittest.mock import AsyncMock, MagicMock

import pytest
from src.core import turnstile
from src.core.exceptions import ForbiddenError


@pytest.fixture
def settings(monkeypatch):
    value = SimpleNamespace(
        turnstile_secret="test-widget-secret",
        turnstile_expected_hostnames="p2hs.com,dashboard.p2hs.com",
        is_dev=False,
    )
    monkeypatch.setattr(turnstile, "get_settings", lambda: value)
    return value


@pytest.mark.asyncio
@pytest.mark.parametrize(
    "field,env_name",
    [
        ("turnstile_secret", "TURNSTILE_SECRET"),
        ("turnstile_expected_hostnames", "TURNSTILE_EXPECTED_HOSTNAMES"),
    ],
)
async def test_missing_config_fails_closed_with_safe_log(settings, monkeypatch, field, env_name):
    setattr(settings, field, " ")
    logger = MagicMock()
    client = MagicMock()
    monkeypatch.setattr(turnstile, "logger", logger)
    monkeypatch.setattr(turnstile.httpx, "AsyncClient", client)
    with pytest.raises(ForbiddenError, match="temporarily unavailable"):
        await turnstile.verify_turnstile("token", action="login", remote_ip=None)
    client.assert_not_called()
    logger.error.assert_called_once_with("turnstile_configuration_missing", setting=env_name)


@pytest.mark.asyncio
@pytest.mark.parametrize(
    "result,allowed",
    [
        ({"success": True, "action": "login", "hostname": "dashboard.p2hs.com"}, True),
        ({"success": True, "action": "signup", "hostname": "dashboard.p2hs.com"}, False),
        ({"success": True, "action": "login", "hostname": "attacker.example"}, False),
        ({"success": False, "error-codes": ["timeout-or-duplicate"]}, False),
        ([], False),
    ],
)
async def test_requires_verified_action_and_hostname(settings, monkeypatch, result, allowed):
    response = MagicMock()
    response.json.return_value = result
    client = AsyncMock()
    client.post.return_value = response
    context = MagicMock()
    context.__aenter__ = AsyncMock(return_value=client)
    context.__aexit__ = AsyncMock(return_value=False)
    monkeypatch.setattr(turnstile.httpx, "AsyncClient", lambda **kwargs: context)
    if allowed:
        await turnstile.verify_turnstile("token", action="login", remote_ip=None)
    else:
        with pytest.raises(ForbiddenError):
            await turnstile.verify_turnstile("token", action="login", remote_ip=None)
    assert client.post.call_args.kwargs["data"] == {
        "secret": settings.turnstile_secret,
        "response": "token",
    }
