from django.shortcuts import get_object_or_404
from django.utils.translation import gettext_lazy as _
from rest_framework import generics, mixins, permissions, status, viewsets
from rest_framework.response import Response

from collection import filters, models, serializers, tasks
from utils.methods import get_permission_classes
from utils.views import BindObjectMixin


class CollectionViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    """ViewSet for Collection model."""

    # pagination_class = None
    serializer_class = serializers.CollectionBackOfficeSerializer
    permission_classes = (permissions.AllowAny,)

    def get_queryset(self):
        """Overridden method 'get_queryset'."""
        qs = models.Collection.objects.all().order_by('-created').with_base_related()
        if self.request.country_code:
            qs = qs.by_country_code(self.request.country_code)
        return qs


class GuideBaseView(generics.GenericAPIView):
    """ViewSet for Guide model."""
    serializer_class = serializers.GuideBaseSerializer
    permission_classes = get_permission_classes()

    def get_queryset(self):
        """An overridden get_queryset method."""
        queryset = models.Guide.objects.with_base_related
        if hasattr(self.request, 'country_code'):
            return queryset().by_country_code(self.request.country_code).order_by('-created')
        return queryset().none()


class GuideFilterBaseView(generics.GenericAPIView):
    """ViewSet for GuideFilter model."""
    pagination_class = None
    queryset = models.GuideFilter.objects.all()
    serializer_class = serializers.GuideFilterBaseSerializer
    permission_classes = get_permission_classes()


class GuideElementBaseView(generics.GenericAPIView):
    """Base view for GuideElement model."""
    pagination_class = None
    queryset = models.GuideElement.objects.all()
    serializer_class = serializers.GuideElementBaseSerializer
    permission_classes = get_permission_classes()


class AdvertorialBaseView(generics.GenericAPIView):
    """Base view for Advertorial model."""
    pagination_class = None
    queryset = models.Advertorial.objects.all()
    serializer_class = serializers.AdvertorialBaseSerializer
    permission_classes = get_permission_classes()


class CollectionBackOfficeViewSet(mixins.CreateModelMixin,
                                  mixins.UpdateModelMixin,
                                  mixins.DestroyModelMixin,
                                  mixins.RetrieveModelMixin,
                                  BindObjectMixin,
                                  CollectionViewSet):
    """ViewSet for Collections list for BackOffice users and Collection create."""

    queryset = models.Collection.objects.with_base_related().order_by('-created')
    filter_class = filters.CollectionFilterSet
    serializer_class = serializers.CollectionBackOfficeSerializer
    bind_object_serializer_class = serializers.CollectionBindObjectSerializer
    permission_classes = (permissions.AllowAny, )

    def perform_binding(self, serializer):
        data = serializer.validated_data
        collection = data.pop('collection')
        obj_type = data.get('type')
        related_object = data.get('related_object')
        if obj_type == self.bind_object_serializer_class.ESTABLISHMENT:
            collection.establishments.add(related_object)
        elif obj_type == self.bind_object_serializer_class.PRODUCT:
            collection.products.add(related_object)

    def perform_unbinding(self, serializer):
        data = serializer.validated_data
        collection = data.pop('collection')
        obj_type = data.get('type')
        related_object = data.get('related_object')
        if obj_type == self.bind_object_serializer_class.ESTABLISHMENT:
            collection.establishments.remove(related_object)
        elif obj_type == self.bind_object_serializer_class.PRODUCT:
            collection.products.remove(related_object)


class CollectionBackOfficeList(CollectionBackOfficeViewSet):
    """ViewSet for Collections list for BackOffice users and Collection create."""
    pagination_class = None


class GuideListCreateView(GuideBaseView, generics.ListCreateAPIView):
    """
    ## Guide list/create view.
    ### Request
    For creating new instance of Guide model, need to pass the following data in the request:
    required fields:
    * name (str) - guide name
    * start (str) - guide start date (datetime in a format `ISO-8601`)
    * vintage (str) - valid year
    * guide_type (int) - guide type enum: `0 (Restaurant), 1 (Artisan), 2 (Wine)`
    * site (int) - identifier of site
    non-required fields:
    * slug - generated automatically if not provided
    * state - state enum`: `0 (Built), 1 (Waiting), 2 (Removing), 3 (Building)` (service states)
    * end - guide end date (datetime in a format `ISO-8601`)

    ### Response
    Return paginated list of guides.
    I.e.:
    ```
    {
      "count": 58,
      "next": 2,
      "previous": null,
      "results": [
        {
            "id": 1,
            ...
        }
      ]
    }
    ```

    ### Description
    *GET*
    Return paginated list of guides with the opportunity of filtering by next fields:
    * establishment_id (int) - identifier of establishment,
    * guide_type (int) - guide type enum: `0 (Restaurant), 1 (Artisan), 2 (Wine)`

    *POST*
    Create a new instance of guide.
    """
    filter_class = filters.GuideFilterSet

    def create(self, request, *args, **kwargs):
        """Overridden create method."""
        super(GuideListCreateView, self).create(request, *args, **kwargs)
        return Response(status=status.HTTP_201_CREATED)


class GuideListView(generics.ListAPIView):
    """View for Guides list."""
    pagination_class = None
    serializer_class = serializers.GuideShortSerializer
    filter_class = filters.GuideFilterSet

    def get_queryset(self):
        """An overridden get_queryset method."""
        if hasattr(self.request, 'country_code'):
            return (
                models.Guide.objects.by_country_code(self.request.country_code)
                                    .order_by('-created')
            )
        return models.Guide.objects.none()


class GuideBackOfficeList(BindObjectMixin, GuideBaseView):
    """ViewSet for Guides list for BackOffice users"""
    pagination_class = None
    filter_class = filters.GuideFilterSet
    bind_object_serializer_class = serializers.GuideBindObjectSerializer

    def perform_binding(self, serializer):
        data = serializer.validated_data
        guide = data.pop('guide')
        obj_type = data.get('type')
        related_object = data.get('related_object')

        if obj_type == self.bind_object_serializer_class.GUIDE:
            guide.establishments.add(related_object)

        elif obj_type == self.bind_object_serializer_class.PRODUCT:
            guide.products.add(related_object)

    def perform_unbinding(self, serializer):
        data = serializer.validated_data
        guide = data.pop('guide')
        obj_type = data.get('type')
        related_object = data.get('related_object')

        if obj_type == self.bind_object_serializer_class.GUIDE:
            guide.establishments.remove(related_object)

        elif obj_type == self.bind_object_serializer_class.PRODUCT:
            guide.products.remove(related_object)


class GuideFilterCreateView(GuideFilterBaseView,
                            generics.CreateAPIView):
    """View for GuideFilter model for BackOffice users."""

    def post(self, request, *args, **kwargs):
        super().create(request, *args, **kwargs)
        return Response(status=status.HTTP_200_OK)


class GuideElementListView(GuideElementBaseView,
                           generics.ListAPIView):
    """View for model GuideElement for back office users."""

    def get_queryset(self):
        """Overridden get_queryset method."""
        guide = get_object_or_404(models.Guide.objects.all(), pk=self.kwargs.get('pk'))
        node = models.GuideElement.objects.get_root_node(guide)
        if node:
            return node.get_children()
        else:
            return models.GuideElement.objects.none()


class GuideUpdateView(GuideBaseView):
    """View for model GuideElement for back office users."""

    def get(self, request, *args, **kwargs):
        """POST-method to regenerate elements of guide instance."""
        guide = get_object_or_404(models.Guide.objects.all(),
                                  pk=self.kwargs.get('pk'))
        guide.regenerate_elements()
        return Response(status=status.HTTP_200_OK)


class AdvertorialCreateView(AdvertorialBaseView,
                            generics.CreateAPIView):
    """View for model Advertorial for back office users."""

    def post(self, request, *args, **kwargs):
        """Overridden post method."""
        super(AdvertorialCreateView, self).create(request, *args, **kwargs)
        return Response(status=status.HTTP_200_OK)


class AdvertorialDestroyView(AdvertorialBaseView,
                             generics.DestroyAPIView):
    """View for model Advertorial for back office users."""
    lookup_url_kwarg = 'advertorial_pk'

    def delete(self, request, *args, **kwargs):
        """Overridden delete method."""
        return self.destroy(request, *args, **kwargs)


class GuideElementExportCSVView(generics.ListAPIView):
    """Guide element export csv view."""
    pagination_class = None
    queryset = models.GuideElement.objects.all()
    serializer_class = serializers.GuideElementBaseSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

    def get(self, request, *args, **kwargs):
        """Overridden get_queryset method."""
        guide = get_object_or_404(
            models.Guide.objects.all(), pk=self.kwargs.get('pk'))
        tasks.export_guide(guide_id=guide.id, user_id=request.user.id)
        return Response({"success": _('The file will be sent to your email.')},
                        status=status.HTTP_200_OK)


class GuideElementExportXMLView(generics.ListAPIView):
    """Guide element export xml view."""
    pagination_class = None
    queryset = models.GuideElement.objects.all()
    serializer_class = serializers.GuideElementBaseSerializer
    permission_classes = get_permission_classes()

    def get(self, request, *args, **kwargs):
        """Overridden get_queryset method."""
        guide = get_object_or_404(
            models.Guide.objects.all(), pk=self.kwargs.get('pk'))
        tasks.export_guide(guide_id=guide.id, user_id=request.user.id, file_type='xml')
        return Response({"success": _('The file will be sent to your email.')},
                        status=status.HTTP_200_OK)


class GuideElementExportDOCView(generics.ListAPIView):
    """Guide element export doc view."""
    pagination_class = None
    queryset = models.GuideElement.objects.all()
    serializer_class = serializers.GuideElementBaseSerializer
    permission_classes = get_permission_classes()

    def get(self, request, *args, **kwargs):
        """Overridden get_queryset method."""
        guide = get_object_or_404(
            models.Guide.objects.all(), pk=self.kwargs.get('pk'))
        guide.export_to_file(user_id=request.user.id, file_type='doc')
        return Response({"success": _('The file will be sent to your email.')},
                        status=status.HTTP_200_OK)
