"""Establishment app views."""
from django.db.models.query_utils import Q
from django.http import Http404
from django.shortcuts import get_object_or_404
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import generics, status
from rest_framework.response import Response

from account.models import User
from establishment import filters, models, serializers
from establishment.models import EstablishmentEmployee
from timetable.models import Timetable
from timetable.serialziers import ScheduleCreateSerializer, ScheduleRUDSerializer
from utils.methods import get_permission_classes
from utils.permissions import (
    IsEstablishmentManager, IsEstablishmentAdministrator, )
from utils.views import CreateDestroyGalleryViewMixin


class MenuRUDMixinViews:
    """Menu mixin"""

    def get_object(self):
        instance = self.get_queryset().filter(
            Q(establishment__slug=self.kwargs.get('slug')) | Q(establishment__id=self.kwargs.get('pk'))
        ).first()

        if instance is None:
            raise Http404

        return instance


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

    def get_queryset(self):
        """Overridden method 'get_queryset'."""
        queryset = models.Establishment.objects.with_base_related
        if hasattr(self, 'request') and \
                (hasattr(self.request, 'user') and hasattr(self.request, 'country_code')):
            return queryset().available_establishments(self.request.user, self.request.country_code)
        return queryset().none()


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

    filter_class = filters.EstablishmentFilter
    serializer_class = serializers.EstablishmentListCreateSerializer
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator,
    )


class EmployeeEstablishmentPositionsView(generics.ListAPIView):
    """Establishment by employee view."""

    queryset = models.EstablishmentEmployee.objects.all()
    serializer_class = serializers.EstablishmentEmployeePositionsSerializer
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator
    )

    def get_queryset(self):
        employee_pk = self.kwargs.get('pk')
        return super().get_queryset().filter(employee__id=employee_pk).all().prefetch_related(
            'establishment').select_related('position')


class EmployeeEstablishmentsListView(generics.ListAPIView):
    """Establishment by employee list view."""
    serializer_class = serializers.EstablishmentListCreateSerializer
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator,
    )

    def get_queryset(self):
        pk = self.kwargs.get('pk')
        employee = get_object_or_404(models.Employee, pk=pk)
        return employee.establishments.with_extended_related()


class EmployeePositionsListView(generics.ListAPIView):
    """Establishment position by employee list view."""

    queryset = models.Establishment.objects.all()
    serializer_class = serializers.EstablishmentPositionListSerializer
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator
    )

    def get_queryset(self):
        pk = self.kwargs.get('pk')
        employee = get_object_or_404(models.Employee, pk=pk)
        return employee.establishments.with_extended_related()


class EstablishmentRUDView(EstablishmentMixinViews, generics.RetrieveUpdateDestroyAPIView):
    lookup_field = 'slug'
    serializer_class = serializers.EstablishmentRUDSerializer
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator,
    )

    def get_queryset(self):
        """Overridden get_queryset method."""
        qs = super(EstablishmentRUDView, self).get_queryset()
        return qs.prefetch_related(
            'establishmentemployee_set',
            'establishmentemployee_set__establishment',
        )


class EstablishmentScheduleRUDView(EstablishmentMixinViews, generics.RetrieveUpdateDestroyAPIView):
    """Establishment schedule RUD view"""
    lookup_field = 'slug'
    serializer_class = ScheduleRUDSerializer
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator,
    )

    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=super(EstablishmentScheduleRUDView, self).get_queryset(),
                                          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 = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator,
    )


class MenuListCreateView(generics.ListCreateAPIView):
    """Menu list create view."""
    serializer_class = serializers.MenuSerializers
    queryset = models.Menu.objects.all()
    filter_backends = (DjangoFilterBackend,)
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator,
    )
    filterset_fields = (
        'establishment__id',
        'establishment__slug',
    )

    def get_queryset(self):
        return super().get_queryset().prefetch_related('establishment')


class MenuRUDView(MenuRUDMixinViews, generics.RetrieveUpdateDestroyAPIView):
    """Menu RUD view."""
    lookup_field = None
    serializer_class = serializers.MenuRUDSerializers
    queryset = models.Menu.objects.all()
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator,
    )


class MenuFilesListCreateView(generics.ListCreateAPIView):
    """Menu files list create view."""
    serializer_class = serializers.MenuFilesSerializers
    queryset = models.MenuFiles.objects.all()
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator
    )


class MenuFilesRUDView(generics.RetrieveDestroyAPIView):
    """Menu files RUD view."""
    serializer_class = serializers.MenuFilesSerializers
    queryset = models.MenuFiles.objects.all()
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator
    )


class SocialChoiceListCreateView(generics.ListCreateAPIView):
    """SocialChoice list create view."""
    serializer_class = serializers.SocialChoiceSerializers
    queryset = models.SocialChoice.objects.all()
    pagination_class = None
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator,
    )


class SocialChoiceRUDView(generics.RetrieveUpdateDestroyAPIView):
    """SocialChoice RUD view."""
    serializer_class = serializers.SocialChoiceSerializers
    queryset = models.SocialChoice.objects.all()
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator,
    )


class SocialListCreateView(generics.ListCreateAPIView):
    """Social list create view."""
    serializer_class = serializers.SocialNetworkSerializers
    queryset = models.SocialNetwork.objects.all()
    pagination_class = None
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator,
    )


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


class PlateListCreateView(generics.ListCreateAPIView):
    """Plate list create view."""
    serializer_class = serializers.PlatesSerializers
    queryset = models.Plate.objects.all()
    pagination_class = None
    permission_classes = get_permission_classes(
        IsEstablishmentAdministrator,
        IsEstablishmentManager,
    )


class PlateRUDView(generics.RetrieveUpdateDestroyAPIView):
    """Plate RUD view."""
    serializer_class = serializers.PlatesSerializers
    queryset = models.Plate.objects.all()
    permission_classes = get_permission_classes(
        IsEstablishmentAdministrator,
        IsEstablishmentManager,
    )


class PhonesListCreateView(generics.ListCreateAPIView):
    """Phones list create view."""
    serializer_class = serializers.ContactPhoneBackSerializers
    queryset = models.ContactPhone.objects.all()
    pagination_class = None
    permission_classes = get_permission_classes(
        IsEstablishmentAdministrator,
        IsEstablishmentManager,
    )


class PhonesRUDView(generics.RetrieveUpdateDestroyAPIView):
    """Phones RUD view."""
    serializer_class = serializers.ContactPhoneBackSerializers
    queryset = models.ContactPhone.objects.all()
    permission_classes = get_permission_classes(
        IsEstablishmentAdministrator,
        IsEstablishmentManager,
    )


class EmailListCreateView(generics.ListCreateAPIView):
    """Email list create view."""
    serializer_class = serializers.ContactEmailBackSerializers
    queryset = models.ContactEmail.objects.all()
    pagination_class = None
    permission_classes = get_permission_classes(
        IsEstablishmentAdministrator,
        IsEstablishmentManager,
    )


class EmailRUDView(generics.RetrieveUpdateDestroyAPIView):
    """Email RUD view."""
    serializer_class = serializers.ContactEmailBackSerializers
    queryset = models.ContactEmail.objects.all()
    permission_classes = get_permission_classes(
        IsEstablishmentAdministrator,
        IsEstablishmentManager,
    )


class EmployeeListCreateView(generics.ListCreateAPIView):
    """Employee list create view."""
    filter_class = filters.EmployeeBackFilter
    serializer_class = serializers.EmployeeBackSerializers
    queryset = models.Employee.objects.all().distinct().with_back_office_related()
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator,
    )


class EmployeesListSearchViews(generics.ListAPIView):
    """Employee search view"""
    pagination_class = None
    queryset = models.Employee.objects.all().with_back_office_related().select_related('photo')
    filter_class = filters.EmployeeBackSearchFilter
    serializer_class = serializers.EmployeeBackSerializers
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator,
    )


class EstablishmentEmployeeListView(generics.ListCreateAPIView):
    """Establishment emplyoees list view."""
    serializer_class = serializers.EstEmployeeBackSerializer
    pagination_class = None
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator,
    )

    def get_queryset(self):
        establishment_id = self.kwargs['establishment_id']
        return models.Employee.objects.filter(
            establishmentemployee__establishment_id=establishment_id,
        ).distinct()


class EmployeeRUDView(generics.RetrieveUpdateDestroyAPIView):
    """Employee RUD view."""
    serializer_class = serializers.EmployeeBackSerializers
    queryset = models.Employee.objects.with_back_office_related()
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator,
    )


class RemoveAwardView(generics.DestroyAPIView):
    lookup_field = 'pk'
    serializer_class = serializers.EmployeeBackSerializers
    queryset = models.Employee.objects.with_back_office_related()
    permission_classes = get_permission_classes()

    def get_object(self):
        employee = super().get_object()
        employee.remove_award(self.kwargs['award_id'])
        return employee

    def delete(self, request, *args, **kwargs):
        instance = self.get_object()
        return Response(status=status.HTTP_204_NO_CONTENT)


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


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


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


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


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

    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
    permission_classes = get_permission_classes()

    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
    permission_classes = get_permission_classes()

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

        establishment = get_object_or_404(filtered_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
    permission_classes = get_permission_classes()

    def get_object(self):
        """Returns the object the view is displaying."""
        establishment_qs = super(EstablishmentCompanyRUDView, self).get_queryset()
        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
    permission_classes = get_permission_classes(
        IsEstablishmentAdministrator,
        IsEstablishmentManager,
    )

    def get_object(self):
        """Returns the object the view is displaying."""
        establishment_qs = super(EstablishmentNoteListCreateView, self).get_queryset()
        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
    permission_classes = get_permission_classes(
        IsEstablishmentAdministrator,
        IsEstablishmentManager,
    )

    def get_object(self):
        """Returns the object the view is displaying."""
        establishment_qs = super(EstablishmentNoteRUDView, self).get_queryset()
        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()
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator
    )


class EstablishmentEmployeeDeleteView(generics.DestroyAPIView):
    queryset = EstablishmentEmployee.objects.all()
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator
    )


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

    pagination_class = None
    queryset = models.Position.objects.all()
    serializer_class = serializers.PositionBackSerializer
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator
    )


class EstablishmentAdminView(generics.ListAPIView):
    """Establishment admin list view."""
    serializer_class = serializers.EstablishmentAdminListSerializer
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator
    )

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


class MenuDishesListView(generics.ListAPIView):
    """Menu (dessert, main_course, starter) list create view."""
    serializer_class = serializers.MenuDishesSerializer
    queryset = models.Menu.objects.with_dishes()
    filter_class = filters.MenuDishesBackFilter
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator
    )


class MenuDishesRUDView(MenuRUDMixinViews, generics.RetrieveUpdateDestroyAPIView):
    """Menu (dessert, main_course, starter) RUD view."""
    lookup_field = None
    serializer_class = serializers.MenuDishesRUDSerializers
    queryset = models.Menu.objects.with_dishes()
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator
    )

class MenuDishesCreateView(generics.CreateAPIView):
    """Menu (dessert, main_course, starter) list create view."""
    serializer_class = serializers.MenuDishesCreateSerializer
    queryset = models.MenuDish.objects.all()
    filter_class = filters.MenuDishesBackFilter
    permission_classes = get_permission_classes(
        IsEstablishmentManager,
        IsEstablishmentAdministrator
    )
