"""PRD §5.1 FRFA-CO015–017 — auditor archived-awards list view."""
from __future__ import annotations

from datetime import timedelta
from decimal import Decimal

import pytest
from django.contrib.auth import get_user_model
from django.urls import reverse
from django.utils import timezone

from apps.core.authentication.models import Institution, MFADevice
from apps.core.permissions.roles import UserRole
from apps.rims.grants.models import Application, Award, GrantCall
from apps.rims.grants.services import (
    award_application,
    shortlist_application,
    submit_application,
)


User = get_user_model()


@pytest.fixture
def institution(db):
    return Institution.objects.create(name="Phase5 institution", country="Uganda", is_member=True)


@pytest.fixture
def applicant_user(db, institution):
    u = User.objects.create_user(email="applicant.phase5@example.com", password="pw-phase5")
    u.institution = institution
    u.role = UserRole.SCHOLAR
    u.save()
    return u


@pytest.fixture
def auditor_user(db):
    u = User.objects.create_user(email="auditor.phase5@example.com", password="pw-phase5")
    u.role = UserRole.AUDITOR
    u.save()
    return u


@pytest.fixture
def grants_manager_user(db):
    u = User.objects.create_user(email="gm.phase5@example.com", password="pw-phase5")
    u.role = UserRole.GRANTS_MANAGER
    u.save()
    return u


def _bypass_mfa(user):
    MFADevice.objects.get_or_create(
        user=user,
        device_type=MFADevice.DeviceType.TOTP,
        defaults={"name": "Test TOTP", "secret": "JBSWY3DPEHPK3PXP", "is_verified": True},
    )


def _build_archived_award(applicant_user, institution) -> Award:
    call = GrantCall.objects.create(
        title="Archived award call",
        slug=f"archived-{int(timezone.now().timestamp() * 1000) % 10_000_000}",
        call_type="grant",
        opens_at=timezone.now() - timedelta(days=400),
        closes_at=timezone.now() + timedelta(days=10),
        status=GrantCall.Status.PUBLISHED,
    )
    app = Application.objects.create(call=call, applicant=applicant_user, institution=institution)
    submit_application(app)
    app = Application.objects.get(pk=app.pk)
    shortlist_application(app)
    award_application(app, Decimal("100"), timezone.now().date() - timedelta(days=100), narrative="")
    award = Application.objects.get(pk=app.pk).award
    award.status = Award.Status.CLOSED
    award.closed_at = timezone.now() - timedelta(days=90)
    award.archived_at = timezone.now() - timedelta(days=5)
    award.save(update_fields=["status", "closed_at", "archived_at"])
    return award


@pytest.mark.django_db
def test_auditor_can_view_archived_awards(client, applicant_user, institution, auditor_user):
    award = _build_archived_award(applicant_user, institution)
    _bypass_mfa(auditor_user)
    client.force_login(auditor_user)
    resp = client.get(reverse("rims_operations:archived_awards"))
    assert resp.status_code == 200
    assert award.application.call.title.encode() in resp.content


@pytest.mark.django_db
def test_grants_manager_cannot_view_archived_awards(
    client, applicant_user, institution, grants_manager_user
):
    _build_archived_award(applicant_user, institution)
    _bypass_mfa(grants_manager_user)
    client.force_login(grants_manager_user)
    resp = client.get(reverse("rims_operations:archived_awards"))
    # AuditorReadOnlyMixin blocks non-auditor roles with 403.
    assert resp.status_code == 403


@pytest.mark.django_db
def test_non_archived_awards_are_filtered_out(client, applicant_user, institution, auditor_user):
    """Award without archived_at must NOT appear in the list."""
    # Build an archived one + one closed-but-not-archived one.
    archived = _build_archived_award(applicant_user, institution)
    live_call = GrantCall.objects.create(
        title="Active call",
        slug=f"live-{int(timezone.now().timestamp() * 1000) % 10_000_000}",
        call_type="grant",
        opens_at=timezone.now() - timedelta(days=10),
        closes_at=timezone.now() + timedelta(days=10),
        status=GrantCall.Status.PUBLISHED,
    )
    inst2 = Institution.objects.create(name="Other inst", country="Uganda", is_member=True)
    other_applicant = User.objects.create_user(
        email="other.applicant@example.com", password="pw"
    )
    other_applicant.institution = inst2
    other_applicant.role = UserRole.SCHOLAR
    other_applicant.save()
    app = Application.objects.create(call=live_call, applicant=other_applicant, institution=inst2)
    submit_application(app)
    app = Application.objects.get(pk=app.pk)
    shortlist_application(app)
    award_application(
        app, Decimal("50"), timezone.now().date() + timedelta(days=100), narrative=""
    )
    not_archived = Application.objects.get(pk=app.pk).award

    _bypass_mfa(auditor_user)
    client.force_login(auditor_user)
    resp = client.get(reverse("rims_operations:archived_awards"))
    assert resp.status_code == 200
    assert archived.application.call.title.encode() in resp.content
    assert b"Active call" not in resp.content


@pytest.mark.django_db
def test_csv_export_works_for_auditor(client, applicant_user, institution, auditor_user):
    _build_archived_award(applicant_user, institution)
    _bypass_mfa(auditor_user)
    client.force_login(auditor_user)
    resp = client.get(reverse("rims_operations:archived_awards") + "?export=csv")
    assert resp.status_code == 200
    assert resp["Content-Type"].startswith("text/csv")
    assert b"Archived at" in resp.content
