"""RIMS → Repository ingestion endpoint (PRD REPO-SP8)."""

from __future__ import annotations

from django.utils import timezone
from rest_framework import parsers, permissions, status
from rest_framework.response import Response
from rest_framework.views import APIView

from apps.repository.documents import services
from apps.repository.documents.ingestion import parse_rims_payload
from apps.repository.documents.models import Collection, IntegrationOutbox


def _log_rims_outbox(*, event_type: str, payload: dict, ok: bool, error: str = "") -> None:
    """FRREP-INT009 — RimsIngestView is an *inbound* path, so it never wrote an
    IntegrationOutbox row; the integration-status dashboard always showed 0
    sent / no last-sync for RIMS even while ingestion was actively
    succeeding or failing. Record every attempt here, success or failure, so
    RIMS shows up like every other integration target.
    """
    IntegrationOutbox.objects.create(
        target=IntegrationOutbox.Target.RIMS,
        event_type=event_type,
        payload=payload,
        status=IntegrationOutbox.Status.SENT if ok else IntegrationOutbox.Status.FAILED,
        error=error,
        sent_at=timezone.now() if ok else None,
    )


class RimsIngestView(APIView):
    """Accepts a grant close-out payload and creates a Document in DRAFT.

    Clients need the ``repository_documents.ingest_via_rims`` permission plus
    a valid JWT or session — RIMS's service account is the expected caller.
    """

    parser_classes = (parsers.MultiPartParser, parsers.FormParser, parsers.JSONParser)
    permission_classes = (permissions.IsAuthenticated,)

    def post(self, request):
        if not request.user.has_perm("repository_documents.ingest_via_rims") and not request.user.is_superuser:
            return Response({"detail": "Missing ingest permission."}, status=status.HTTP_403_FORBIDDEN)

        try:
            normalised = parse_rims_payload(request.data)
        except ValueError as exc:
            _log_rims_outbox(
                event_type="rims_ingest", payload=dict(request.data), ok=False, error=str(exc)
            )
            return Response({"detail": str(exc)}, status=status.HTTP_400_BAD_REQUEST)

        file = request.FILES.get("file")
        if not file:
            _log_rims_outbox(
                event_type="rims_ingest",
                payload=normalised,
                ok=False,
                error="A 'file' multipart field is required.",
            )
            return Response({"detail": "A 'file' multipart field is required."}, status=status.HTTP_400_BAD_REQUEST)

        collection_slug = request.data.get("collection_slug", "rims-closeout")
        collection = Collection.objects.filter(slug=collection_slug).first() or Collection.objects.filter(
            slug="reports"
        ).first()
        if collection is None:
            _log_rims_outbox(
                event_type="rims_ingest",
                payload=normalised,
                ok=False,
                error=f"Collection '{collection_slug}' does not exist.",
            )
            return Response(
                {"detail": f"Collection '{collection_slug}' does not exist."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        # Build author entities from the payload.
        authors = [
            services.register_author(
                name=payload_author["name"],
                orcid=payload_author.get("orcid"),
            )
            for payload_author in normalised.get("authors", [])
            if payload_author.get("name")
        ]

        try:
            document = services.ingest_document(
                file=file,
                title=normalised["title"],
                collection=collection,
                document_type=normalised["document_type"],
                abstract=normalised.get("abstract", ""),
                license_type=normalised.get("license_type", "cc_by"),
                language=normalised.get("language", "en"),
                year=normalised.get("year"),
                grant_reference=normalised.get("grant_reference", ""),
                authors=authors,
                submitted_by=request.user,
                source_system="rims",
                actor=request.user,
                request=request,
            )
        except services.DuplicateDocumentError as exc:
            _log_rims_outbox(
                event_type="rims_ingest",
                payload=normalised,
                ok=False,
                error=f"Duplicate of {exc.duplicate_of.public_document_id}.",
            )
            return Response(
                {
                    "detail": "Duplicate document.",
                    "existing_document_id": exc.duplicate_of.public_document_id,
                },
                status=status.HTTP_409_CONFLICT,
            )

        try:
            services.submit_for_qa(document, actor=request.user, request=request)
        except services.PreCheckFailedError as exc:
            # FRREP-QA001 — the document was created (DRAFT) but pre-checks
            # failed; report the specifics instead of a bare 500.
            _log_rims_outbox(
                event_type="rims_ingest",
                payload={**normalised, "document_id": document.public_document_id},
                ok=False,
                error="; ".join(exc.failures),
            )
            return Response(
                {
                    "detail": "Document created but failed QA pre-checks.",
                    "document_id": document.public_document_id,
                    "failures": exc.failures,
                },
                status=status.HTTP_422_UNPROCESSABLE_ENTITY,
            )

        _log_rims_outbox(
            event_type="rims_ingest",
            payload={"document_id": document.public_document_id, "title": normalised["title"]},
            ok=True,
        )
        return Response(
            {
                "document_id": document.public_document_id,
                "status": document.status,
                "uid": str(document.document_uid),
            },
            status=status.HTTP_201_CREATED,
        )


class GrantClosureNotifyView(APIView):
    """RIMS grant close-out → flag every linked Repository document (PRD REPO-SP5/SP8).

    FRREP-VL009 — ``services.apply_grant_closure_flag`` existed with a UI
    badge for ``Document.grant_closed_flag`` but no integration endpoint ever
    called it. Same auth pattern as :class:`RimsIngestView`: RIMS's service
    account needs ``repository_documents.ingest_via_rims`` (or superuser).
    """

    permission_classes = (permissions.IsAuthenticated,)

    def post(self, request):
        if not request.user.has_perm(
            "repository_documents.ingest_via_rims"
        ) and not request.user.is_superuser:
            return Response(
                {"detail": "Missing ingest permission."},
                status=status.HTTP_403_FORBIDDEN,
            )

        grant_reference = (
            request.data.get("grant_reference")
            or request.data.get("public_grant_id")
            or ""
        ).strip()
        if not grant_reference:
            return Response(
                {"detail": "'grant_reference' is required."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        updated = services.apply_grant_closure_flag(
            grant_reference, actor=request.user, request=request
        )
        return Response(
            {"grant_reference": grant_reference, "documents_flagged": updated},
            status=status.HTTP_200_OK,
        )
