"""Establishment app views."""
from django.http import Http404, HttpResponse
from django.shortcuts import get_object_or_404
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import generics, permissions, status

from account.models import User
from establishment import filters, models, serializers
from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer
from utils.permissions import IsCountryAdmin, IsEstablishmentManager, IsWineryReviewer
from utils.views import CreateDestroyGalleryViewMixin
from timetable.models import Timetable
from rest_framework import status
from rest_framework.response import Response


class EstablishmentMixinViews:
    """Establishment mixin."""

    def get_queryset(self):
        """Overrided method 'get_queryset'."""
        return models.Establishment.objects.published().with_base_related()


class EstablishmentListCreateView(EstablishmentMixinViews, generics.ListCreateAPIView):
    """Establishment list/create view."""

    filter_class = filters.EstablishmentFilter

    permission_classes = [IsWineryReviewer | IsCountryAdmin | IsEstablishmentManager]
    queryset = models.Establishment.objects.all()
    serializer_class = serializers.EstablishmentListCreateSerializer


class EstablishmentRUDView(generics.RetrieveUpdateDestroyAPIView):
    lookup_field = 'slug'
    queryset = models.Establishment.objects.all()
    serializer_class = serializers.EstablishmentRUDSerializer
    permission_classes = [IsWineryReviewer | IsCountryAdmin | IsEstablishmentManager]


class EstablishmentScheduleRUDView(generics.RetrieveUpdateDestroyAPIView):
    """Establishment schedule RUD view"""
    lookup_field = 'slug'
    serializer_class = ScheduleRUDSerializer
    permission_classes = [IsWineryReviewer | IsEstablishmentManager]

    def get_object(self):
        """
        Returns the object the view is displaying.
        """
        establishment_slug = self.kwargs['slug']
        schedule_id = self.kwargs['schedule_id']

        establishment = get_object_or_404(klass=models.Establishment.objects.all(),
                                          slug=establishment_slug)
        schedule = get_object_or_404(klass=establishment.schedule,
                                     id=schedule_id)

        # May raise a permission denied
        self.check_object_permissions(self.request, establishment)
        self.check_object_permissions(self.request, schedule)

        return schedule


class EstablishmentScheduleCreateView(generics.CreateAPIView):
    """Establishment schedule Create view"""
    lookup_field = 'slug'
    serializer_class = ScheduleCreateSerializer
    queryset = Timetable.objects.all()
    permission_classes = [IsWineryReviewer | IsEstablishmentManager]


class MenuListCreateView(generics.ListCreateAPIView):
    """Menu list create view."""
    serializer_class = serializers.MenuSerializers
    queryset = models.Menu.objects.all()
    permission_classes = [IsWineryReviewer | IsEstablishmentManager]
    filter_backends = (DjangoFilterBackend,)
    filterset_fields = (
        'establishment',
        'establishment__slug',
    )


class MenuRUDView(generics.RetrieveUpdateDestroyAPIView):
    """Menu RUD view."""
    serializer_class = serializers.MenuRUDSerializers
    queryset = models.Menu.objects.all()
    permission_classes = [IsWineryReviewer | IsEstablishmentManager]


class SocialChoiceListCreateView(generics.ListCreateAPIView):
    """SocialChoice list create view."""
    serializer_class = serializers.SocialChoiceSerializers
    queryset = models.SocialChoice.objects.all()
    pagination_class = None
    permission_classes = [permissions.IsAdminUser]


class SocialChoiceRUDView(generics.RetrieveUpdateDestroyAPIView):
    """SocialChoice RUD view."""
    serializer_class = serializers.SocialChoiceSerializers
    queryset = models.SocialChoice.objects.all()
    permission_classes = [permissions.IsAdminUser]


class SocialListCreateView(generics.ListCreateAPIView):
    """Social list create view."""
    serializer_class = serializers.SocialNetworkSerializers
    queryset = models.SocialNetwork.objects.all()
    pagination_class = None
    permission_classes = [permissions.IsAdminUser]


class SocialRUDView(generics.RetrieveUpdateDestroyAPIView):
    """Social RUD view."""
    serializer_class = serializers.SocialNetworkSerializers
    queryset = models.SocialNetwork.objects.all()
    permission_classes = [IsEstablishmentManager]


class PlateListCreateView(generics.ListCreateAPIView):
    """Plate list create view."""
    serializer_class = serializers.PlatesSerializers
    queryset = models.Plate.objects.all()
    pagination_class = None
    permission_classes = [IsWineryReviewer | IsEstablishmentManager]


class PlateRUDView(generics.RetrieveUpdateDestroyAPIView):
    """Plate RUD view."""
    serializer_class = serializers.PlatesSerializers
    queryset = models.Plate.objects.all()
    permission_classes = [IsWineryReviewer | IsEstablishmentManager]


class PhonesListCreateView(generics.ListCreateAPIView):
    """Phones list create view."""
    serializer_class = serializers.ContactPhoneBackSerializers
    queryset = models.ContactPhone.objects.all()
    pagination_class = None
    permission_classes = [IsWineryReviewer | IsEstablishmentManager]


class PhonesRUDView(generics.RetrieveUpdateDestroyAPIView):
    """Phones RUD view."""
    serializer_class = serializers.ContactPhoneBackSerializers
    queryset = models.ContactPhone.objects.all()
    permission_classes = [IsWineryReviewer | IsEstablishmentManager]


class EmailListCreateView(generics.ListCreateAPIView):
    """Email list create view."""
    serializer_class = serializers.ContactEmailBackSerializers
    queryset = models.ContactEmail.objects.all()
    pagination_class = None
    permission_classes = [IsWineryReviewer | IsEstablishmentManager]


class EmailRUDView(generics.RetrieveUpdateDestroyAPIView):
    """Email RUD view."""
    serializer_class = serializers.ContactEmailBackSerializers
    queryset = models.ContactEmail.objects.all()
    permission_classes = [IsWineryReviewer | IsEstablishmentManager]


class EmployeeListCreateView(generics.ListCreateAPIView):
    """Emplyoee list create view."""
    permission_classes = (permissions.AllowAny,)
    filter_class = filters.EmployeeBackFilter
    serializer_class = serializers.EmployeeBackSerializers
    queryset = models.Employee.objects.all()
    pagination_class = None


class EstablishmentEmployeeListView(generics.ListCreateAPIView):
    """Establishment emplyoees list view."""
    permission_classes = (permissions.AllowAny,)
    serializer_class = serializers.EstablishmentEmployeeBackSerializer

    def get_queryset(self):
        establishment_id = self.kwargs['establishment_id']
        return models.EstablishmentEmployee.objects.filter(establishment__id=establishment_id)


class EmployeeRUDView(generics.RetrieveUpdateDestroyAPIView):
    """Employee RUD view."""
    serializer_class = serializers.EmployeeBackSerializers
    queryset = models.Employee.objects.all()


class EstablishmentTypeListCreateView(generics.ListCreateAPIView):
    """Establishment type list/create view."""
    serializer_class = serializers.EstablishmentTypeBaseSerializer
    queryset = models.EstablishmentType.objects.all()
    pagination_class = None


class EstablishmentTypeRUDView(generics.RetrieveUpdateDestroyAPIView):
    """Establishment type retrieve/update/destroy view."""
    serializer_class = serializers.EstablishmentTypeBaseSerializer
    queryset = models.EstablishmentType.objects.all()


class EstablishmentSubtypeListCreateView(generics.ListCreateAPIView):
    """Establishment subtype list/create view."""
    serializer_class = serializers.EstablishmentSubTypeBaseSerializer
    queryset = models.EstablishmentSubType.objects.all()
    pagination_class = None


class EstablishmentSubtypeRUDView(generics.RetrieveUpdateDestroyAPIView):
    """Establishment subtype retrieve/update/destroy view."""
    serializer_class = serializers.EstablishmentSubTypeBaseSerializer
    queryset = models.EstablishmentSubType.objects.all()


class EstablishmentGalleryCreateDestroyView(EstablishmentMixinViews,
                                            CreateDestroyGalleryViewMixin):
    """Resource for a create|destroy gallery for establishment for back-office users."""
    lookup_field = 'slug'
    serializer_class = serializers.EstablishmentBackOfficeGallerySerializer

    def get_object(self):
        """
        Returns the object the view is displaying.
        """
        establishment_qs = self.filter_queryset(self.get_queryset())

        establishment = get_object_or_404(establishment_qs, slug=self.kwargs.get('slug'))
        gallery = get_object_or_404(establishment.establishment_gallery,
                                    image_id=self.kwargs.get('image_id'))

        # May raise a permission denied
        self.check_object_permissions(self.request, gallery)

        return gallery


class EstablishmentGalleryListView(EstablishmentMixinViews,
                                   generics.ListAPIView):
    """Resource for returning gallery for establishment for back-office users."""
    lookup_field = 'slug'
    serializer_class = serializers.ImageBaseSerializer

    def get_object(self):
        """Override get_object method."""
        qs = super(EstablishmentGalleryListView, self).get_queryset()
        establishment = get_object_or_404(qs, slug=self.kwargs.get('slug'))

        # May raise a permission denied
        self.check_object_permissions(self.request, establishment)

        return establishment

    def get_queryset(self):
        """Override get_queryset method."""
        return self.get_object().crop_gallery


class EstablishmentCompanyListCreateView(EstablishmentMixinViews,
                                         generics.ListCreateAPIView):
    """List|Create establishment company view."""

    lookup_field = 'slug'
    serializer_class = serializers.EstablishmentCompanyListCreateSerializer

    def get_object(self):
        """Returns the object the view is displaying."""
        establishment_qs = models.Establishment.objects.all()
        filtered_ad_qs = self.filter_queryset(establishment_qs)

        establishment = get_object_or_404(filtered_ad_qs, slug=self.kwargs.get('slug'))

        # May raise a permission denied
        self.check_object_permissions(self.request, establishment)

        return establishment

    def get_queryset(self):
        """Overridden get_queryset method."""
        return self.get_object().companies.all()


class EstablishmentCompanyRUDView(EstablishmentMixinViews,
                                  generics.RetrieveUpdateDestroyAPIView):
    """Create|Retrieve|Update|Destroy establishment company view."""

    lookup_field = 'slug'
    serializer_class = serializers.CompanyBaseSerializer

    def get_object(self):
        """Returns the object the view is displaying."""
        establishment_qs = models.Establishment.objects.all()
        filtered_ad_qs = self.filter_queryset(establishment_qs)

        establishment = get_object_or_404(filtered_ad_qs, slug=self.kwargs.get('slug'))
        company = get_object_or_404(establishment.companies.all(), pk=self.kwargs.get('company_pk'))

        # May raise a permission denied
        self.check_object_permissions(self.request, company)

        return company


class EstablishmentNoteListCreateView(EstablishmentMixinViews,
                                      generics.ListCreateAPIView):
    """Retrieve|Update|Destroy establishment note view."""

    lookup_field = 'slug'
    serializer_class = serializers.EstablishmentNoteListCreateSerializer

    def get_object(self):
        """Returns the object the view is displaying."""
        establishment_qs = models.Establishment.objects.all()
        filtered_establishment_qs = self.filter_queryset(establishment_qs)

        establishment = get_object_or_404(filtered_establishment_qs, slug=self.kwargs.get('slug'))

        # May raise a permission denied
        self.check_object_permissions(self.request, establishment)

        return establishment

    def get_queryset(self):
        """Overridden get_queryset method."""
        return self.get_object().notes.all()


class EstablishmentNoteRUDView(EstablishmentMixinViews,
                               generics.RetrieveUpdateDestroyAPIView):
    """Create|Retrieve|Update|Destroy establishment note view."""

    lookup_field = 'slug'
    serializer_class = serializers.EstablishmentNoteBaseSerializer

    def get_object(self):
        """Returns the object the view is displaying."""
        establishment_qs = models.Establishment.objects.all()
        filtered_establishment_qs = self.filter_queryset(establishment_qs)

        establishment = get_object_or_404(filtered_establishment_qs, slug=self.kwargs.get('slug'))
        note = get_object_or_404(establishment.notes.all(), pk=self.kwargs['note_pk'])

        # May raise a permission denied
        self.check_object_permissions(self.request, note)

        return note


class EstablishmentEmployeeCreateView(generics.CreateAPIView):
    serializer_class = serializers.EstablishmentEmployeeCreateSerializer
    queryset = models.EstablishmentEmployee.objects.all()
    # TODO send email to all admins and add endpoint for changing status


class EstablishmentEmployeeDeleteView(generics.DestroyAPIView):

    def _get_object_to_delete(self, establishment_id, employee_id):
        result_qs = models.EstablishmentEmployee \
            .objects \
            .filter(establishment_id=establishment_id, employee_id=employee_id)
        if not result_qs.exists():
            raise Http404
        return result_qs.first()

    def delete(self, request, *args, **kwargs):
        establishment_id = self.kwargs["establishment_id"]
        employee_id = self.kwargs["employee_id"]
        object_to_delete = self._get_object_to_delete(establishment_id, employee_id)
        object_to_delete.delete()
        return HttpResponse(status=status.HTTP_204_NO_CONTENT)


class EstablishmentPositionListView(generics.ListAPIView):
    """Establishment positions list view."""

    pagination_class = None
    permission_classes = (permissions.AllowAny,)
    queryset = models.Position.objects.all()
    serializer_class = serializers.PositionBackSerializer


class EstablishmentAdminView(generics.ListAPIView):
    """Establishment admin list view."""
    serializer_class = serializers.EstablishmentAdminListSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, )

    def get_queryset(self):
        establishment = get_object_or_404(
            models.Establishment, slug=self.kwargs['slug'])
        return User.objects.establishment_admin(establishment).distinct()
