from django.contrib.auth import get_user_model
from django.db.models import Q

from rest_framework.exceptions import ParseError as BadRequest
from rest_framework.response import Response

from intranet.femida.src.api.core.pagination import CursorPagination, PageNumberPagination
from intranet.femida.src.api.core.views import BaseView
from intranet.femida.src.applications.models import Application
from intranet.femida.src.candidates.models import Candidate
from intranet.femida.src.candidates.helpers import candidate_is_current_employee_subquery
from intranet.femida.src.core.shortcuts import get_object_or_40x
from intranet.femida.src.isearch.acl import get_acl_for_search
from .fetchers import CandidatesFetcher
from .permissions import ISearchPermission

User = get_user_model()


class CandidateListView(BaseView):

    model_class = Candidate
    pagination_class = CursorPagination
    permission_classes = [ISearchPermission]

    @property
    def paginator(self):
        """
        Сделаем так, что если в ручку передается `page`, то будем пагинировать
        по страницам, а если нет, то по курсору.
        """
        if not hasattr(self, '_paginator'):
            if 'page' in self.request.query_params:
                self._paginator = PageNumberPagination()
            else:
                self._paginator = CursorPagination()
        return self._paginator

    def get_queryset(self):
        return (
            self.model_class.unsafe
            .order_by('-id')
            .annotate(
                is_current_employee=candidate_is_current_employee_subquery,
            )
            .values(
                'id',
                'first_name',
                'middle_name',
                'last_name',
                'gender',
                'birthday',
                'country',
                'city',
                'status',
                'is_from_submission',
                'is_duplicate',
                'created',
                'modified',
                'is_hidden',
                'is_locked',
                'login',
                'is_current_employee',
            )
        )

    def filter_queryset(self, queryset):
        self.candidates_by_vacancy_qs = None
        vacancy_id = self.request.query_params.get('vacancy')
        if vacancy_id:
            try:
                vacancy_id = int(vacancy_id)
            except ValueError:
                return queryset.none()

            self.candidates_by_vacancy_qs = (
                Application.unsafe.filter(vacancy_id=vacancy_id).values('candidate_id')
            )
            queryset = queryset.filter(id__in=self.candidates_by_vacancy_qs)
        return queryset

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginator.paginate_queryset(queryset, request, view=self)
        if self.candidates_by_vacancy_qs is not None:
            extra_query = Q(candidate_id__in=self.candidates_by_vacancy_qs)
        else:
            extra_query = None
        data = CandidatesFetcher(page, extra_query=extra_query).data
        return self.paginator.get_paginated_response(data)

    def get(self, request, *args, **kwargs):
        """
        Список канидатов для внутреннего поиска
        """
        return self.list(request, *args, **kwargs)


class CandidateDetailView(CandidateListView):

    def retrieve(self, request, *args, **kwargs):
        instance = get_object_or_40x(self.get_queryset(), pk=self.kwargs['pk'])
        data = CandidatesFetcher([instance]).data
        return Response(data[0])

    def get(self, request, *args, **kwargs):
        """
        Детализация по кандидату для индексатора
        """
        return self.retrieve(request, *args, **kwargs)


class CandidateACLView(BaseView):

    permission_classes = [ISearchPermission]

    def get(self, request, *args, **kwargs):
        """
        Отдаем информацию о правах пользователя на получение кандидатов
        """
        login = request.query_params.get('login')
        if not login:
            raise BadRequest('Login is required')

        try:
            user = User.objects.get(username=login)
        except User.DoesNotExist:
            raise BadRequest('There is no such user')

        data = {
            'allowed': True,
            'restrictions': get_acl_for_search(user),
        }
        return Response(data)
