from __future__ import annotations

from django.db.models import F, Q
from django.db.models.functions import Coalesce
from rest_framework import serializers, status
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from rest_framework.views import APIView

from apps.access.drf import TenantPermission
from apps.tasks import services
from apps.tasks.models import Task
from interfaces.api_v1.serializers import UserBriefSerializer


class TaskSerializer(serializers.ModelSerializer):
    assignee = UserBriefSerializer(read_only=True)
    created_by = UserBriefSerializer(read_only=True)
    reviewed_by = UserBriefSerializer(read_only=True)
    is_new = serializers.SerializerMethodField()

    def get_is_new(self, obj) -> bool:
        user = self.context.get("user")
        return bool(user and obj.assignee_id == user.pk and obj.assignee_seen_at is None)

    class Meta:
        model = Task
        fields = [
            "id", "title", "description", "status", "priority", "due_date",
            "assignee", "created_by", "created_at", "updated_at", "assigned_at", "review_note",
            "reviewed_by", "reviewed_at", "is_new", "quality", "rated_at",
        ]


class TaskInputSerializer(serializers.Serializer):
    title = serializers.CharField(max_length=200, required=False)
    description = serializers.CharField(required=False, allow_blank=True)
    status = serializers.CharField(required=False)
    priority = serializers.CharField(required=False)
    due_date = serializers.DateField(required=False, allow_null=True)
    assignee = serializers.IntegerField(required=False, allow_null=True)


class Pagination(PageNumberPagination):
    page_size = 50
    page_size_query_param = "page_size"
    max_page_size = 100


class TaskListCreateView(APIView):
    permission_classes = [TenantPermission]
    module_code = "tasks"
    permission_map = {"GET": "tasks.view", "POST": "tasks.create"}

    def get(self, request):
        qs = services.visible_tasks(request.tenant, "tasks.view")
        params = request.query_params
        if params.get("status") == "open":  # everything not finished yet (the board)
            qs = qs.exclude(status="done")
        elif params.get("status"):
            qs = qs.filter(status=params["status"])
        search = (params.get("search") or "").strip()
        if search:
            qs = qs.filter(
                Q(title__icontains=search) | Q(description__icontains=search)
                | Q(assignee__name__icontains=search) | Q(assignee__username__icontains=search)
                | Q(created_by__name__icontains=search)
            )
        if params.get("mine") == "1":
            qs = qs.filter(assignee=request.user)
        if params.get("status") == "done":  # history: most recently finished first
            qs = qs.annotate(finished_at=Coalesce("reviewed_at", "updated_at")).order_by("-finished_at", "-id")
        else:
            qs = qs.order_by(F("due_date").asc(nulls_last=True), "-id")  # soonest deadline first, undated last
        paginator = Pagination()
        page = paginator.paginate_queryset(qs, request)
        return paginator.get_paginated_response(TaskSerializer(page, many=True, context={"user": request.user}).data)

    def post(self, request):
        data = TaskInputSerializer(data=request.data)
        data.is_valid(raise_exception=True)
        task = services.create_task(request.tenant, data=data.validated_data, request=request)
        return Response(TaskSerializer(task, context={"user": request.user}).data, status=status.HTTP_201_CREATED)


class TaskDetailView(APIView):
    permission_classes = [TenantPermission]
    module_code = "tasks"
    permission_map = {"GET": "tasks.view", "PATCH": "tasks.update", "DELETE": "tasks.delete"}

    def get(self, request, pk):
        task = services.get_task(request.tenant, pk, "tasks.view")
        data = TaskSerializer(task, context={"user": request.user}).data  # is_new as it was before opening
        services.mark_seen(request.tenant, task)
        return Response(data)

    def patch(self, request, pk):
        task = services.get_task(request.tenant, pk, "tasks.update")
        data = TaskInputSerializer(data=request.data, partial=True)
        data.is_valid(raise_exception=True)
        task = services.update_task(request.tenant, task, data=data.validated_data, request=request)
        return Response(TaskSerializer(task, context={"user": request.user}).data)

    def delete(self, request, pk):
        task = services.get_task(request.tenant, pk, "tasks.delete")
        services.delete_task(request.tenant, task, request=request)
        return Response(status=status.HTTP_204_NO_CONTENT)


class AssigneeListView(APIView):
    """Who tasks can be assigned to (only for people allowed to assign)."""

    permission_classes = [TenantPermission]
    module_code = "tasks"
    permission_map = {"GET": "tasks.assign"}
    scope_map = {"GET": "organization"}

    def get(self, request):
        members = services.assignable_members(request.tenant)
        return Response([UserBriefSerializer(m.user).data for m in members])


class TaskSummaryView(APIView):
    permission_classes = [TenantPermission]
    module_code = "tasks"
    permission_map = {"GET": "tasks.view"}

    def get(self, request):
        return Response(services.summary(request.tenant))


class TaskRateView(APIView):
    """Rate the quality of a finished task (approvers only)."""

    permission_classes = [TenantPermission]
    module_code = "tasks"
    permission_map = {"POST": "tasks.approve"}
    scope_map = {"POST": "organization"}

    def post(self, request, pk):
        task = services.get_task(request.tenant, pk, "tasks.approve")
        task = services.rate_task(request.tenant, task, quality=str(request.data.get("quality", "")), request=request)
        return Response(TaskSerializer(task, context={"user": request.user}).data)


class TaskReviewView(APIView):
    """Approve (task is finished) or reject (it is not finished yet) a task awaiting approval."""

    permission_classes = [TenantPermission]
    module_code = "tasks"
    permission_map = {"POST": "tasks.approve"}
    scope_map = {"POST": "organization"}
    approve = True

    def post(self, request, pk):
        task = services.get_task(request.tenant, pk, "tasks.approve")
        note = str(request.data.get("note", "")) if not self.approve else ""
        task = services.review_task(request.tenant, task, approve=self.approve, note=note, request=request)
        return Response(TaskSerializer(task, context={"user": request.user}).data)