"""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 .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(mixins.CreateModelMixin,
                        mixins.ListModelMixin,
                        mixins.RetrieveModelMixin,
                        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']
        )
