"""SRS §4.1.7 "Monitoring Visit (Optional)" — closes the gap where no model
anywhere in the codebase captured visit scheduling, findings, evidence, or
GPS coordinates. Covers scheduling, recording findings, and the
lock-after-submission rule ("no edits allowed").
"""
from datetime import date, timedelta
from decimal import Decimal

import pytest
from django.core.exceptions import ValidationError
from django.utils import timezone

from apps.rims.grants.models import Application, GrantCall, MonitoringVisit, MonitoringVisitEvidence
from apps.rims.grants.services import (
    award_application,
    lock_monitoring_visit,
    record_monitoring_visit_findings,
    shortlist_application,
    submit_application,
)


def _award_for(applicant_user, institution, *, suffix="mv"):
    call = GrantCall.objects.create(
        title="Monitoring visit call",
        slug=f"mv-{suffix}-{int(timezone.now().timestamp())}",
        opens_at=timezone.now() - timedelta(days=1),
        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("1000"), date.today() + timedelta(days=180), narrative="")
    return Application.objects.get(pk=app.pk).award


@pytest.mark.django_db
def test_schedule_and_record_visit_with_gps(applicant_user, institution, grants_manager_user):
    award = _award_for(applicant_user, institution, suffix="gps")
    visit = MonitoringVisit.objects.create(
        award=award,
        initiated_by=grants_manager_user,
        visit_type=MonitoringVisit.VisitType.PHYSICAL,
        scheduled_for=timezone.now() + timedelta(days=3),
    )
    assert visit.is_locked is False

    record_monitoring_visit_findings(
        visit,
        findings="Farmers actively engaged in training.",
        strengths="Strong community turnout.",
        gaps="Delayed input delivery.",
        latitude=Decimal("0.313611"),
        longitude=Decimal("32.581111"),
    )
    visit = MonitoringVisit.objects.get(pk=visit.pk)
    assert visit.latitude == Decimal("0.313611")
    assert visit.findings == "Farmers actively engaged in training."

    MonitoringVisitEvidence.objects.create(visit=visit, caption="Group photo")
    assert visit.evidence.count() == 1


@pytest.mark.django_db
def test_lock_prevents_further_edits(applicant_user, institution, grants_manager_user):
    award = _award_for(applicant_user, institution, suffix="lock")
    visit = MonitoringVisit.objects.create(
        award=award,
        initiated_by=grants_manager_user,
        visit_type=MonitoringVisit.VisitType.VIRTUAL,
        scheduled_for=timezone.now(),
    )
    record_monitoring_visit_findings(visit, findings="Initial findings.")

    lock_monitoring_visit(visit)
    assert visit.is_locked is True
    assert visit.conducted_at is not None

    with pytest.raises(ValidationError):
        record_monitoring_visit_findings(visit, findings="Trying to edit after lock.")

    # Locking twice is a no-op, not an error.
    lock_monitoring_visit(visit)
