"""This module holds mixins for the ``api`` app."""

from django.db.models import Q

from rest_framework import status
from rest_framework.decorators import list_route
from rest_framework.exceptions import ValidationError
from rest_framework.mixins import DestroyModelMixin, ListModelMixin
from rest_framework.response import Response

from mtp.apps.sync.models import Syncable


class SoftDestroyModelMixin(DestroyModelMixin):
    """Override ``DestroyModelMixin`` to handle soft-deletion of ``Syncable`` instance."""

    def perform_destroy(self, instance):
        """Soft-delete ``Syncable`` instances and perform destroy others instances.

        For the parameters, see ``rest_framework.mixins.DestroyModelMixin``"""

        if isinstance(instance, Syncable):
            instance.remove()
        else:
            super().perform_destroy(instance)


class OrderableListMixin:
    """Mixin that saves the orders

    Your model should inherit from ``orderable.models.Orderable``.
    And you should use ``mtp.apps.api.routers.SimpleRouterWithNesting`` or
    ``rest_framework_extensions.routers.SimpleRouter``

    ``list_route`` decorator doesn't work with
    ``rest_framework_extensions.routers.ExtendedDefaultRouter``

    """

    @list_route(methods=['post'])
    def order(self, request, *args, **kwargs):  # pylint: disable=unused-argument
        """Endpoint to order photos.

        Parameters
        ----------
        For the parameters, see the ``viewsets.ModelViewSet`` class.

        Returns
        -------
        Response

        """

        order = 1
        for object_id in request.data.getlist('order'):
            obj = self.get_queryset().get(pk=object_id)
            obj.sort_order = order
            obj.save()
            order += 1

        return Response(status=status.HTTP_200_OK)


class ListLiveModelMixin(ListModelMixin):
    """Override ``ListModelMixin`` to enforce filtering on the session parameter"""

    def list(self, request, *args, **kwargs):
        """Filter the list of instances accordingly to the provided "session" GET param

        We don't use a generic filter since we want to enforce that the session param
        is provided only in the "list" case and raise if it's not provided.

        For the parameters, see ``rest_framework.mixins.ListModelMixin``

        Raises
        ------
        ValidationError
            If the "session" parameter is not provided

        """

        session = self.request.query_params.get('session')

        if not session:
            raise ValidationError('Session parameter is mandatory')

        queryset = self.filter_queryset(self.get_queryset()).filter(
            Q(session_id=session) | Q(session_id=None)
        )

        page = self.paginate_queryset(queryset)

        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)

        return Response(serializer.data)
