import uuid
from datetime import timedelta
from decimal import Decimal

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

from apps.core.permissions.roles import UserRole
from apps.rims.grants.models import Application, GrantCall
from apps.rims.grants.services import award_application, shortlist_application, submit_application
from apps.rims.projects.models import Milestone, Project


def _awarded_application(applicant_user, institution):
    call = GrantCall.objects.create(
        title="Milestone flow call",
        slug=f"milestone-flow-{uuid.uuid4().hex[:10]}",
        opens_at=timezone.now() - timedelta(days=1),
        closes_at=timezone.now() + timedelta(days=30),
        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"), timezone.now().date() + timedelta(days=180), narrative="")
    return Application.objects.get(pk=app.pk)


@pytest.mark.django_db
def test_project_create_auto_generates_milestones(client, grants_manager_user, applicant_user, institution):
    app = _awarded_application(applicant_user, institution)
    client.force_login(grants_manager_user)
    resp = client.post(
        reverse("rims_projects:project_create"),
        {
            "award": app.award.pk,
            "finance_budget": "",
            "title": "PRD project",
            "summary": "<p>Summary</p>",
            "start_date": timezone.now().date().isoformat(),
            "end_date": (timezone.now().date() + timedelta(days=180)).isoformat(),
            "status": "active",
        },
        follow=True,
    )
    assert resp.status_code == 200
    project = Project.objects.get(award=app.award)
    assert project.milestones.exists()
    assert project.lead == applicant_user


@pytest.mark.django_db
def test_milestone_review_requires_reviewer_role(client, grants_manager_user, applicant_user, institution):
    app = _awarded_application(applicant_user, institution)
    project = Project.objects.create(
        award=app.award,
        title="Review access project",
        summary="",
        start_date=timezone.now().date(),
        end_date=timezone.now().date() + timedelta(days=60),
        status=Project.Status.ACTIVE,
    )
    milestone = Milestone.objects.create(
        project=project,
        name="M1",
        due_date=timezone.now().date() + timedelta(days=7),
        report_due=True,
    )

    client.force_login(grants_manager_user)
    denied = client.post(
        reverse("rims_projects:milestone_review", kwargs={"project_pk": project.pk, "milestone_pk": milestone.pk}),
        {"decision": "accepted", "comment": "ok"},
    )
    assert denied.status_code == 403

    User = type(grants_manager_user)
    director = User.objects.create_user(email=f"pd-{uuid.uuid4().hex[:6]}@x.com", password="x")
    director.role = UserRole.PROGRAM_DIRECTOR
    director.save(update_fields=["role"])
    client.force_login(director)
    allowed = client.post(
        reverse("rims_projects:milestone_review", kwargs={"project_pk": project.pk, "milestone_pk": milestone.pk}),
        {"decision": "accepted", "comment": "ok"},
        follow=True,
    )
    assert allowed.status_code == 200
    milestone.refresh_from_db()
    assert milestone.status == Milestone.Status.ACCEPTED
