"""P1 (assessment §3 #11) — Interview .ics builder + download view + auto-complete.

Coverage:
- ``build_interview_ics`` produces RFC 5545-shaped bytes (BEGIN:VCALENDAR …
  END:VCALENDAR with VEVENT, UID, DTSTART, DTEND).
- ``InterviewIcsView`` streams ``text/calendar`` to the applicant; staff get
  through too; unrelated users hit PermissionDenied.
- ``auto_complete_interviews`` flips past-due SCHEDULED interviews to
  COMPLETED and respects the grace window.
"""
from __future__ import annotations

from datetime import timedelta

import pytest
from django.urls import reverse
from django.utils import timezone

from apps.core.authentication.models import MFADevice
from apps.rims.grants.calendar_ics import build_interview_ics
from apps.rims.grants.models import Application, GrantCall, InterviewSchedule
from apps.rims.grants.tasks import auto_complete_interviews


def _bypass_mfa(user):
    """Privileged roles need a verified MFA device or the middleware redirects."""
    MFADevice.objects.get_or_create(
        user=user,
        device_type=MFADevice.DeviceType.TOTP,
        defaults={"name": "Test TOTP", "secret": "JBSWY3DPEHPK3PXP", "is_verified": True},
    )


def _make_interview(applicant, *, scheduled_for=None):
    call = GrantCall.objects.create(
        title="P1 ICS call",
        slug=f"p1-ics-{int(timezone.now().timestamp() * 1000) % 10_000_000}",
        opens_at=timezone.now(),
        closes_at=timezone.now() + timedelta(days=14),
        status=GrantCall.Status.PUBLISHED,
    )
    application = Application.objects.create(
        call=call,
        applicant=applicant,
        status=Application.Status.UNDER_REVIEW,
    )
    return InterviewSchedule.objects.create(
        application=application,
        scheduled_for=scheduled_for or (timezone.now() + timedelta(days=2)),
    )


@pytest.mark.django_db
def test_build_interview_ics_shape(applicant_user):
    interview = _make_interview(applicant_user)
    payload = build_interview_ics(interview)
    body = payload.decode("utf-8")
    assert body.startswith("BEGIN:VCALENDAR")
    assert "END:VCALENDAR" in body
    assert "BEGIN:VEVENT" in body
    assert "END:VEVENT" in body
    assert "DTSTART:" in body
    assert "DTEND:" in body
    assert "UID:interview-" in body
    assert "SUMMARY:" in body


@pytest.mark.django_db
def test_interview_ics_download_view_owner_can_access(client, applicant_user):
    interview = _make_interview(applicant_user)
    client.force_login(applicant_user)
    url = reverse("rims_grants:interview_ics", kwargs={"pk": interview.pk})
    resp = client.get(url)
    assert resp.status_code == 200
    assert resp["Content-Type"].startswith("text/calendar")
    assert "attachment" in resp["Content-Disposition"]
    assert ".ics" in resp["Content-Disposition"]


@pytest.mark.django_db
def test_interview_ics_view_blocks_unrelated_user(client, applicant_user, reviewer_user):
    interview = _make_interview(applicant_user)
    client.force_login(reviewer_user)  # reviewer not assigned to this interview
    url = reverse("rims_grants:interview_ics", kwargs={"pk": interview.pk})
    resp = client.get(url)
    assert resp.status_code in (302, 403)  # PermissionDenied raises 403; some mw redirects to login


@pytest.mark.django_db
def test_interview_ics_view_grants_manager_can_access(client, applicant_user, grants_manager_user):
    interview = _make_interview(applicant_user)
    _bypass_mfa(grants_manager_user)
    client.force_login(grants_manager_user)
    url = reverse("rims_grants:interview_ics", kwargs={"pk": interview.pk})
    resp = client.get(url)
    assert resp.status_code == 200


@pytest.mark.django_db
def test_auto_complete_interviews_flips_past_due(applicant_user):
    past = timezone.now() - timedelta(hours=2)
    interview = _make_interview(applicant_user, scheduled_for=past)
    assert interview.status == InterviewSchedule.Status.SCHEDULED
    flipped = auto_complete_interviews()
    interview.refresh_from_db()
    assert flipped == 1
    assert interview.status == InterviewSchedule.Status.COMPLETED


@pytest.mark.django_db
def test_auto_complete_interviews_respects_grace_window(applicant_user):
    # Within the grace window — should NOT flip
    near_past = timezone.now() - timedelta(minutes=5)
    interview = _make_interview(applicant_user, scheduled_for=near_past)
    flipped = auto_complete_interviews(grace_minutes=30)
    interview.refresh_from_db()
    assert flipped == 0
    assert interview.status == InterviewSchedule.Status.SCHEDULED
