"""Phase 2.4 — RIMS grant linkage form validation + detail rendering (FRREP-MCL009).

The submit form stores the picked ``public_grant_id`` into ``Document.grant_reference``
and rejects an id that doesn't resolve to an active/closed funding record. The
document detail page surfaces the linked grant's title (deep-linked for users who
can read RIMS funding).
"""
from __future__ import annotations

from datetime import date, timedelta
from decimal import Decimal

import pytest
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import Client
from django.urls import reverse

from apps.core.permissions.roles import UserRole
from apps.repository.documents import services
from apps.repository.documents.forms import DocumentMetadataEditForm, DocumentSubmitForm
from apps.repository.documents.models import Document
from apps.rims.grants.models import FundingRecord

PDF_BYTES = (
    b"%PDF-1.4\n%\xe2\xe3\xcf\xd3\n1 0 obj<</Type/Catalog>>endobj\ntrailer<<>>\n%%EOF\n"
)


def _grant(public_grant_id, title, status=FundingRecord.Status.APPROVED):
    return FundingRecord.objects.create(
        public_grant_id=public_grant_id,
        title=title,
        amount=Decimal("1000"),
        start_date=date.today(),
        end_date=date.today() + timedelta(days=365),
        status=status,
    )


def _base_data(collection_pk):
    return {
        "title": "Grant-linked thesis",
        "abstract": "Work funded by a RUFORUM grant.",
        "document_type": Document.DocumentType.THESIS,
        "license_type": Document.License.CC_BY,
        "language": "en",
        "year": 2026,
        "collection": collection_pk,
        "authors_text": "Kato, Amina",
        "staged_token": "tok",
    }


@pytest.mark.django_db
def test_form_accepts_linkable_grant(public_collection):
    _grant("RU/2021/GRG/01", "Maize resilience")
    data = _base_data(public_collection.pk)
    data["grant_reference"] = "RU/2021/GRG/01"
    form = DocumentSubmitForm(data=data)
    assert form.is_valid(), form.errors
    assert form.cleaned_data["grant_reference"] == "RU/2021/GRG/01"


@pytest.mark.django_db
def test_form_rejects_unknown_grant(public_collection):
    data = _base_data(public_collection.pk)
    data["grant_reference"] = "RU/9999/NOPE"
    form = DocumentSubmitForm(data=data)
    assert not form.is_valid()
    assert "grant_reference" in form.errors


@pytest.mark.django_db
def test_form_rejects_draft_grant(public_collection):
    _grant("RU/2022/DRAFT", "Draft", status=FundingRecord.Status.DRAFT)
    data = _base_data(public_collection.pk)
    data["grant_reference"] = "RU/2022/DRAFT"
    form = DocumentSubmitForm(data=data)
    assert not form.is_valid()
    assert "grant_reference" in form.errors


@pytest.mark.django_db
def test_blank_grant_is_allowed(public_collection):
    data = _base_data(public_collection.pk)
    data["grant_reference"] = ""
    form = DocumentSubmitForm(data=data)
    assert form.is_valid(), form.errors


@pytest.mark.django_db
def test_detail_links_grant_for_privileged_user(public_collection, manager_user):
    grant = _grant("RU/2021/GRG/01", "Maize resilience")
    doc = Document.objects.create(
        title="Linked doc",
        abstract="x",
        document_type=Document.DocumentType.THESIS,
        license_type=Document.License.CC_BY,
        language="en",
        year=2026,
        collection=public_collection,
        visibility=Document.Visibility.PUBLIC_OPEN,
        status=Document.Status.PUBLISHED,
        grant_reference="RU/2021/GRG/01",
        submitted_by=manager_user,
        file=SimpleUploadedFile("d.pdf", PDF_BYTES, content_type="application/pdf"),
    )
    manager_user.role = UserRole.GRANTS_MANAGER
    manager_user.save(update_fields=["role"])

    client = Client()
    client.force_login(manager_user)
    resp = client.get(reverse("repo_documents:document_detail", kwargs={"uid": doc.document_uid}))
    assert resp.status_code == 200
    ctx = resp.context["linked_grant"]
    assert ctx["title"] == "Maize resilience"
    assert ctx["can_view"] is True
    body = resp.content.decode()
    assert reverse("rims_grants:funding_detail", kwargs={"pk": grant.pk}) in body


@pytest.mark.django_db
def test_detail_shows_grant_title_without_link_for_unprivileged(
    public_collection, submitter_user, manager_user
):
    _grant("RU/2021/GRG/01", "Maize resilience")
    doc = Document.objects.create(
        title="Linked doc",
        abstract="x",
        document_type=Document.DocumentType.THESIS,
        license_type=Document.License.CC_BY,
        language="en",
        year=2026,
        collection=public_collection,
        visibility=Document.Visibility.PUBLIC_OPEN,
        status=Document.Status.PUBLISHED,
        grant_reference="RU/2021/GRG/01",
        submitted_by=manager_user,
        file=SimpleUploadedFile("d.pdf", PDF_BYTES, content_type="application/pdf"),
    )
    client = Client()
    client.force_login(submitter_user)
    resp = client.get(reverse("repo_documents:document_detail", kwargs={"uid": doc.document_uid}))
    assert resp.status_code == 200
    ctx = resp.context["linked_grant"]
    assert ctx["can_view"] is False
    assert "Maize resilience" in resp.content.decode()


# ── FRREP-MCL009 — the edit form's grant picker (previously an empty,
# non-functional `<select data-s2>` since grant_reference is a bare
# CharField, not an FK) ─────────────────────────────────────────────────────


@pytest.mark.django_db
def test_edit_form_grant_reference_is_hidden_input_not_broken_select():
    form = DocumentMetadataEditForm()
    rendered = str(form["grant_reference"])
    assert 'type="hidden"' in rendered
    assert "<select" not in rendered


@pytest.mark.django_db
def test_edit_form_accepts_linkable_grant(public_collection, submitter_user):
    _grant("RU/2021/GRG/01", "Maize resilience")
    doc = Document.objects.create(
        title="Editable doc",
        abstract="x",
        document_type=Document.DocumentType.THESIS,
        license_type=Document.License.CC_BY,
        language="en",
        year=2026,
        collection=public_collection,
        visibility=Document.Visibility.PUBLIC_OPEN,
        status=Document.Status.PUBLISHED,
        submitted_by=submitter_user,
        file=SimpleUploadedFile("d.pdf", PDF_BYTES, content_type="application/pdf"),
    )
    from apps.repository.documents.models import Author

    doc.authors.add(Author.objects.create(first_name="A", last_name="One"))
    client = Client()
    client.force_login(submitter_user)
    resp = client.post(
        reverse("repo_documents:document_edit", kwargs={"uid": doc.document_uid}),
        data={
            "edit_token": services.document_edit_token(doc),
            "title": doc.title,
            "abstract": doc.abstract,
            "document_type": doc.document_type,
            "license_type": doc.license_type,
            "license_notes": "",
            "language": doc.language,
            "year": doc.year,
            "doi": "",
            "visibility": doc.visibility,
            "grant_reference": "RU/2021/GRG/01",
            "authors_text": "One, A",
        },
    )
    assert resp.status_code == 302
    doc = Document.objects.get(pk=doc.pk)
    assert doc.grant_reference == "RU/2021/GRG/01"


@pytest.mark.django_db
def test_edit_view_seeds_current_grant_title_for_widget(public_collection, submitter_user):
    _grant("RU/2021/GRG/01", "Maize resilience")
    doc = Document.objects.create(
        title="Editable doc",
        abstract="x",
        document_type=Document.DocumentType.THESIS,
        license_type=Document.License.CC_BY,
        language="en",
        year=2026,
        collection=public_collection,
        visibility=Document.Visibility.PUBLIC_OPEN,
        status=Document.Status.PUBLISHED,
        grant_reference="RU/2021/GRG/01",
        submitted_by=submitter_user,
        file=SimpleUploadedFile("d.pdf", PDF_BYTES, content_type="application/pdf"),
    )
    client = Client()
    client.force_login(submitter_user)
    resp = client.get(reverse("repo_documents:document_edit", kwargs={"uid": doc.document_uid}))
    assert resp.status_code == 200
    assert resp.context["current_grant"] == {"id": "RU/2021/GRG/01", "title": "Maize resilience"}
    assert "Maize resilience" in resp.content.decode()
