"""Tests for django-axes failed-login lockout integration."""
from __future__ import annotations

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

User = get_user_model()


@pytest.fixture
def user(db):
    return User.objects.create_user(
        email="locked@example.com",
        password="correct-horse",
        first_name="A",
        last_name="B",
        email_verified=True,
    )


@pytest.fixture
def axes_on(settings):
    settings.AXES_ENABLED = True
    settings.AXES_FAILURE_LIMIT = 3  # tighter for fast tests
    yield


def _login_attempt(client: Client, email: str, password: str):
    return client.post(
        reverse("accounts:login"),
        data={"email": email, "password": password},
    )


@pytest.mark.django_db
def test_repeated_failures_lock_the_account(axes_on, user):
    from axes.utils import reset

    reset()  # clear any cross-test state
    c = Client()
    # Failures up to (limit - 1) just re-render the form; the limit-th failure
    # triggers lockout. axes 8.x returns 429 by default with the lockout template.
    resp = _login_attempt(c, user.email, "wrong")
    assert resp.status_code == 200
    resp = _login_attempt(c, user.email, "wrong")
    assert resp.status_code == 200
    resp = _login_attempt(c, user.email, "wrong")
    # Locked out — axes returns 429 (Too Many Requests) or 403 (Forbidden) depending on
    # configuration. Either way, the lockout template renders in the body.
    assert resp.status_code in (403, 429)
    assert b"temporarily locked" in resp.content.lower()


@pytest.mark.django_db
def test_successful_login_resets_counter(axes_on, user, settings):
    from axes.models import AccessAttempt
    from axes.utils import reset

    reset()
    c = Client()
    _login_attempt(c, user.email, "wrong")
    _login_attempt(c, user.email, "wrong")
    # Successful login resets
    resp = _login_attempt(c, user.email, "correct-horse")
    assert resp.status_code == 302  # redirect to dashboard
    # Counter cleared (no remaining failed-attempt rows for this principal)
    assert AccessAttempt.objects.filter(username=user.email).count() == 0


@pytest.mark.django_db
def test_disabled_axes_does_not_lock(settings, user):
    settings.AXES_ENABLED = False
    c = Client()
    for _ in range(10):
        resp = _login_attempt(c, user.email, "wrong")
        assert resp.status_code == 200
