"""This module holds viewsets for ``photostories`` app."""

from django.contrib import messages
from django.db.models.query import Prefetch
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.utils.functional import cached_property

from slugify import slugify

from rest_framework import filters, mixins, status, viewsets
from rest_framework.decorators import detail_route
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework_extensions.mixins import NestedViewSetMixin

from mtp.apps.accounts.apiv2.permissions import IsTrainerToCreate, IsTrainerToEdit
from mtp.apps.api.mixins import OrderableListMixin, SoftDestroyModelMixin
from mtp.apps.trainings.apiv2.views_utils import ConditionallyCachedRetrieveTrainingActivityMixin

from .filters import PhotostoryFilter
from .permissions import IsOwnerToEditStrip, IsStripOwnerToEditPhoto
from .serializers import PhotoSerializer, PhotostorySerializer, StripSerializer

from ..exports import StripExportError
from ..models import Photo, Photostory, Strip


class PhotostoryViewSet(ConditionallyCachedRetrieveTrainingActivityMixin,
                        mixins.CreateModelMixin,
                        mixins.ListModelMixin,
                        viewsets.GenericViewSet):
    """ViewSet for the ``Photostory`` model."""

    queryset = Photostory.objects.non_deleted()
    serializer_class = PhotostorySerializer
    permission_classes = (
        IsAuthenticated,
        IsTrainerToCreate,
        IsTrainerToEdit
    )
    filter_backends = (filters.DjangoFilterBackend,)
    filter_class = PhotostoryFilter


class StripViewSet(NestedViewSetMixin,
                   mixins.CreateModelMixin,
                   mixins.ListModelMixin,
                   mixins.RetrieveModelMixin,
                   viewsets.GenericViewSet):
    """ViewSet for the ``Strip`` model."""

    queryset = Strip.objects.prefetch_related(
        Prefetch(
            'photos',
            queryset=Photo.objects.non_deleted()
        )
    ).non_deleted()
    serializer_class = StripSerializer
    permission_classes = (IsAuthenticated, IsOwnerToEditStrip,)
    filter_backends = (filters.DjangoFilterBackend,)
    filter_fields = ('session', 'owner',)

    def perform_create(self, serializer):
        """Pass the current user as owner of the strip.

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

        """

        serializer.save(owner=self.request.user)

    @detail_route(methods=['post'])
    def publish(self, request, *args, **kwargs):  # pylint: disable=unused-argument
        """Endpoint to publish a strip.
        Only the owner can publish

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

        """

        strip = self.get_object()

        strip.publish()

        return Response(status=status.HTTP_200_OK)

    @detail_route(methods=['get'])
    def download(self, request, *args, **kwargs):  # pylint: disable=unused-argument
        """Endpoint to download a strip.

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

        """
        strip = self.get_object()

        try:
            archive = strip.create_archive()
        except StripExportError as error:
            messages.error(self.request, str(error))
            return Response(
                'Error during strip export.',
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

        response = HttpResponse(content_type=archive.content_type)
        response.write(archive.data)
        response['Content-Disposition'] = 'attachment; filename=%s.%s' % (
            slugify(strip.name),
            archive.extension
        )

        return response


class PhotoViewSet(NestedViewSetMixin,
                   SoftDestroyModelMixin,
                   OrderableListMixin,
                   viewsets.ModelViewSet):
    """ViewSet for the ``Photo`` model."""

    queryset = Photo.objects.non_deleted()
    serializer_class = PhotoSerializer
    permission_classes = (IsAuthenticated, IsStripOwnerToEditPhoto,)

    @cached_property
    def strip(self):
        """Get the provided strip."""

        return get_object_or_404(
            Strip,
            pk=self.get_parents_query_dict()['strip']
        )
