"""Tests for MFA mandate on privileged roles."""
from __future__ import annotations

import pytest
from django.contrib.auth import get_user_model
from django.test import Client
from django.urls import reverse

from apps.core.authentication.models import MFADevice
from apps.core.permissions.roles import UserRole

User = get_user_model()


def _make_user(role: str = "", with_mfa: bool = False):
    u = User.objects.create_user(
        email=f"{role or 'plain'}-{id(role)}@example.com",
        password="x",
        first_name="A",
        last_name="B",
    )
    if role:
        u.role = role
        u.save(update_fields=["role"])
    if with_mfa:
        MFADevice.objects.create(
            user=u,
            device_type=MFADevice.DeviceType.TOTP,
            name="Auth",
            secret="JBSWY3DPEHPK3PXP",
            is_verified=True,
        )
    return u


@pytest.fixture(autouse=True)
def _disable_axes(settings):
    """Disable axes lockout for these tests so login flows aren't gated."""
    settings.AXES_ENABLED = False
    yield


@pytest.mark.django_db
def test_privileged_user_without_mfa_is_redirected_to_enrol_on_dashboard():
    u = _make_user(role=UserRole.ADMIN.value)
    c = Client()
    c.force_login(u)
    resp = c.get(reverse("core:dashboard"))
    assert resp.status_code == 302
    assert resp.headers["Location"] == reverse("accounts:mfa_enroll")


@pytest.mark.django_db
def test_privileged_user_with_mfa_can_reach_dashboard():
    u = _make_user(role=UserRole.FINANCE_DIRECTOR.value, with_mfa=True)
    c = Client()
    c.force_login(u)
    resp = c.get(reverse("core:dashboard"))
    assert resp.status_code == 200


@pytest.mark.django_db
def test_non_privileged_user_without_mfa_is_unaffected():
    u = _make_user(role=UserRole.LEARNER.value)
    c = Client()
    c.force_login(u)
    resp = c.get(reverse("core:dashboard"))
    assert resp.status_code == 200


@pytest.mark.django_db
def test_privileged_user_can_reach_enrol_page_when_un_enrolled():
    u = _make_user(role=UserRole.GRANTS_MANAGER.value)
    c = Client()
    c.force_login(u)
    resp = c.get(reverse("accounts:mfa_enroll"))
    # Enrol page itself is allowed (otherwise they could never enrol).
    assert resp.status_code == 200


@pytest.mark.django_db
def test_privileged_user_can_logout_when_un_enrolled():
    u = _make_user(role=UserRole.PROGRAM_DIRECTOR.value)
    c = Client()
    c.force_login(u)
    resp = c.get(reverse("accounts:logout"))
    # logout is in the bypass list — should succeed (200 or 302).
    assert resp.status_code in (200, 302)
