"""HTTP API for the workflow engine.

* ``GET /api/v1/workflow/definitions/``        — list registered definitions
* ``GET /api/v1/workflow/definitions/<name>/`` — single definition (latest version)
* ``GET /api/v1/workflow/instances/<uuid>/``   — instance snapshot
* ``POST /api/v1/workflow/instances/<uuid>/fire/``    — manual transition fire
* ``POST /api/v1/workflow/instances/<uuid>/approve/`` — record approval
"""

from __future__ import annotations

from rest_framework import status
from rest_framework.exceptions import NotFound, ValidationError
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView

from simorgh.apps.iam.permissions import HasPermission
from simorgh.apps.workflow.engine import (
    fire_transition,
    record_approval,
)
from simorgh.apps.workflow.models import WorkflowInstance
from simorgh.apps.workflow.registry import (
    WorkflowError,
    get_workflow,
    list_workflows,
)


class WorkflowDefinitionListView(APIView):
    permission_classes = (IsAuthenticated, HasPermission)
    required_permission = "workflow.instance.view"

    def get(self, _request: Request) -> Response:
        return Response({"results": [wf.serialize() for wf in list_workflows()]})


class WorkflowDefinitionDetailView(APIView):
    permission_classes = (IsAuthenticated, HasPermission)
    required_permission = "workflow.instance.view"

    def get(self, _request: Request, name: str) -> Response:
        try:
            wf = get_workflow(name)
        except WorkflowError as exc:
            raise NotFound(str(exc)) from exc
        return Response(wf.serialize())


def _instance_payload(instance: WorkflowInstance) -> dict:
    definition = get_workflow(instance.definition_name, instance.definition_version)
    available = [
        {
            "name": t.name,
            "label_key": t.label_key,
            "to_state": t.to_state,
            "requires_approval": t.requires_approval,
            "permission": t.permission,
        }
        for t in definition.transitions_from(instance.current_state)
        if not t.trigger  # only manual transitions
    ]
    return {
        "id": str(instance.public_id),
        "definition": instance.definition_name,
        "version": instance.definition_version,
        "subject_type": instance.subject_type,
        "current_state": instance.current_state,
        "status": instance.status,
        "data": instance.data,
        "available_transitions": available,
    }


class WorkflowInstanceDetailView(APIView):
    permission_classes = (IsAuthenticated, HasPermission)
    required_permission = "workflow.instance.view"

    def get(self, _request: Request, public_id: str) -> Response:
        try:
            instance = WorkflowInstance.objects.scoped().get(public_id=public_id)
        except WorkflowInstance.DoesNotExist as exc:
            raise NotFound("workflow instance not found") from exc
        return Response(_instance_payload(instance))


class WorkflowInstanceFireView(APIView):
    permission_classes = (IsAuthenticated, HasPermission)
    required_permission = "workflow.transition.fire"

    def post(self, request: Request, public_id: str) -> Response:
        try:
            instance = WorkflowInstance.objects.scoped().get(public_id=public_id)
        except WorkflowInstance.DoesNotExist as exc:
            raise NotFound("workflow instance not found") from exc
        transition_name = request.data.get("transition")
        if not transition_name:
            raise ValidationError({"transition": "required"})
        try:
            fire_transition(
                instance,
                str(transition_name),
                actor=request.user,
                payload=request.data.get("payload") or {},
            )
        except WorkflowError as exc:
            raise ValidationError({"detail": str(exc)}) from exc
        instance.refresh_from_db()
        return Response(_instance_payload(instance), status=status.HTTP_200_OK)


class WorkflowInstanceApprovalView(APIView):
    permission_classes = (IsAuthenticated, HasPermission)
    required_permission = "workflow.approval.grant"

    def post(self, request: Request, public_id: str) -> Response:
        try:
            instance = WorkflowInstance.objects.scoped().get(public_id=public_id)
        except WorkflowInstance.DoesNotExist as exc:
            raise NotFound("workflow instance not found") from exc
        transition_name = request.data.get("transition")
        decision = request.data.get("decision")
        if not transition_name or not decision:
            raise ValidationError({"detail": "transition and decision are required"})
        try:
            approval = record_approval(
                instance,
                str(transition_name),
                actor=request.user,
                decision=str(decision),
                role_code=str(request.data.get("role_code") or ""),
                note=str(request.data.get("note") or ""),
            )
        except WorkflowError as exc:
            raise ValidationError({"detail": str(exc)}) from exc
        return Response(
            {
                "id": str(approval.public_id),
                "transition": approval.transition_name,
                "decision": approval.decision,
                "consumed_at": approval.consumed_at,
            },
            status=status.HTTP_201_CREATED,
        )
