# Copyright 2024 The Debusine Developers
# See the AUTHORS file at the top-level directory of this distribution
#
# This file is part of Debusine. It is subject to the license terms
# in the LICENSE file found in the top-level directory of this
# distribution. No part of Debusine, including this file, may be copied,
# modified, propagated, or distributed except according to the terms
# contained in the LICENSE file.

"""Views for the server application: workflows."""

import logging

from django.db.models import QuerySet
from django.http import (
    Http404,
)


from rest_framework import status, views
from rest_framework.exceptions import (
    NotFound,
    PermissionDenied as DRFPermissionDenied,
)
from rest_framework.parsers import JSONParser
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import BaseSerializer

from debusine.db.models import (
    DEFAULT_WORKSPACE_NAME,
    WorkRequest,
    WorkflowTemplate,
)
from debusine.server.serializers import (
    CreateWorkflowRequestSerializer,
    WorkRequestSerializer,
    WorkflowTemplateSerializer,
)
from debusine.server.views.base import (
    CreateAPIViewBase,
    DestroyAPIViewBase,
    IsTokenUserAuthenticated,
    IsTokenUserAuthenticatedDjangoModelPermissions,
    ProblemResponse,
    RetrieveAPIViewBase,
    UpdateAPIViewBase,
)

logger = logging.getLogger(__name__)


class WorkflowTemplateView(
    CreateAPIViewBase[WorkflowTemplate],
    RetrieveAPIViewBase[WorkflowTemplate],
    UpdateAPIViewBase[WorkflowTemplate],
    DestroyAPIViewBase[WorkflowTemplate],
):
    """Return, create and delete workflow templates."""

    permission_classes = [IsTokenUserAuthenticatedDjangoModelPermissions]
    serializer_class = WorkflowTemplateSerializer
    parser_classes = [JSONParser]
    pagination_class = None

    def get_queryset(self) -> QuerySet[WorkflowTemplate]:
        """Get the query set for this view."""
        # TODO: We should check permissions on the workspace somewhere, but
        # there's no infrastructure for that yet:
        # https://salsa.debian.org/freexian-team/debusine/-/issues/80
        if self.request.method == "GET":
            workspace_name = self.request.GET.get(
                "workspace", DEFAULT_WORKSPACE_NAME
            )
        else:
            workspace_name = self.request.data.get(
                "workspace", DEFAULT_WORKSPACE_NAME
            )

        return WorkflowTemplate.objects.filter(workspace__name=workspace_name)

    def get_object(self) -> WorkflowTemplate:
        """Override to return more API-friendly errors."""
        try:
            return super().get_object()
        except Http404 as exc:
            raise NotFound(str(exc))

    def _check_permissions(self, serializer: BaseSerializer[WorkflowTemplate]):
        """Only users with appropriate permissions may set priorities."""
        priority = serializer.validated_data.get("priority")
        if priority is not None and priority > 0:
            token = IsTokenUserAuthenticated().token(self.request)
            # permission_classes is declared such that we won't get this far
            # unless the request has an enabled token with an associated
            # user.
            assert token is not None
            assert token.user is not None
            if not token.user.has_perm("db.manage_workrequest_priorities"):
                raise DRFPermissionDenied(
                    "You are not permitted to set positive priorities"
                )

    def perform_create(self, serializer: BaseSerializer[WorkflowTemplate]):
        """Create a workflow template."""
        self._check_permissions(serializer)
        super().perform_create(serializer)

    def perform_update(self, serializer: BaseSerializer[WorkflowTemplate]):
        """Update a workflow template."""
        self._check_permissions(serializer)
        super().perform_update(serializer)


class WorkflowView(views.APIView):
    """Create workflows from a template."""

    permission_classes = [IsTokenUserAuthenticated]

    def post(self, request: Request):
        """Create a new workflow from a template."""
        serializer = CreateWorkflowRequestSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        try:
            template = WorkflowTemplate.objects.get(
                name=serializer.validated_data["template_name"],
                workspace=serializer.validated_data["workspace"],
            )
        except WorkflowTemplate.DoesNotExist:
            return ProblemResponse(
                "Workflow template not found",
                status_code=status.HTTP_404_NOT_FOUND,
            )

        token = IsTokenUserAuthenticated().token(request)
        # permission_classes is declared such that we won't get this far
        # unless the request has an enabled token with an associated user.
        assert token is not None
        assert token.user is not None

        workflow = WorkRequest.objects.create_workflow(
            template=template,
            data=serializer.validated_data["task_data"],
            created_by=token.user,
        )
        return Response(
            WorkRequestSerializer(workflow).data, status=status.HTTP_201_CREATED
        )
