from django_filters import rest_framework as filters
from django_filters.constants import EMPTY_VALUES
from drf_spectacular.utils import extend_schema

from django.contrib.auth import get_user_model
from django.db.models import Prefetch
from django.utils.translation import gettext

from lms.core.views.viewsets import ExternalModelViewSet

from ...users.permissions import IsTVMAuthenticated
from ..models import Course, CourseGroup, CourseStudent
from ..permissions import CourseAllowedTVMServicePermission
from ..serializers.courses import CourseListExternalSerializer
from ..serializers.student_course_progress import StudentCourseProgressListExternalSerializer

User = get_user_model()


# noinspection DuplicatedCode
class AvailableForEnrollFilter(filters.BooleanFilter):
    def filter(self, qs, value):
        if value in EMPTY_VALUES:
            return qs

        if value is True:
            qs = qs.available_for_enroll()

        return qs


class CourseFilter(filters.FilterSet):
    category = filters.CharFilter(field_name='categories__slug')
    study_mode = filters.CharFilter(field_name='study_mode__slug')
    city = filters.CharFilter(field_name='city__slug')
    name = filters.CharFilter(field_name='name', lookup_expr='icontains')
    payment_method = filters.ChoiceFilter(field_name='payment_method', choices=Course.PaymentMethodChoices.choices)
    course_format = filters.ChoiceFilter(field_name='format', choices=Course.FormatChoices.choices)
    available_for_enroll = AvailableForEnrollFilter()
    type = filters.ChoiceFilter(field_name='course_type', choices=Course.TypeChoices.choices)


class CourseExternalViewSet(ExternalModelViewSet):
    """Список курсов."""
    permission_classes = [
        IsTVMAuthenticated,
    ]
    serializer_class = CourseListExternalSerializer
    filter_backends = (filters.DjangoFilterBackend,)
    filterset_class = CourseFilter

    def get_queryset(self):
        tvm_service_id = getattr(self.request, 'tvm_service_id')
        # Требуется для фильтра `available_for_enroll`
        opened_groups = Prefetch(
            'groups',
            queryset=CourseGroup.objects.opened(),
            to_attr='_opened_groups',
        )
        qs = (Course.objects
              .filter(service_accounts__service_account__tvm_id=tvm_service_id)
              .select_related('occupancy', 'author', 'visibility')
              .prefetch_related('categories', 'tags', 'groups', opened_groups))
        return qs

    @extend_schema(
        summary=gettext("Список курсов"),
    )
    def list(self, request, *args, **kwargs):
        return super().list(request, *args, **kwargs)


class ChoiceInFilter(filters.BaseInFilter, filters.ChoiceFilter):
    """Поддерживает CSV в качестве значений фильтра."""
    pass


class CourseResultsFilter(filters.FilterSet):
    status = ChoiceInFilter(field_name='status',
                            choices=CourseStudent.StatusChoices.choices)
    isFinished = filters.BooleanFilter(field_name='is_passed')  # noqa: N815
    startedAt = filters.IsoDateTimeFromToRangeFilter(field_name='created')  # noqa: N815
    yandexLogin = filters.CharFilter(field_name='user__username',  # noqa: N815
                                     lookup_expr='icontains')


class CourseResultsExternalViewSet(ExternalModelViewSet):
    permission_classes = [CourseAllowedTVMServicePermission]
    serializer_class = StudentCourseProgressListExternalSerializer
    serializer_classes = {
        'list': StudentCourseProgressListExternalSerializer,
    }
    filter_backends = (filters.DjangoFilterBackend,)
    filterset_class = CourseResultsFilter

    def get_course_id(self):
        return self.kwargs['course_id']

    def get_queryset(self):
        queryset = (CourseStudent.objects
                    .select_related('user')
                    .order_by('pk')
                    .prefetch_related('course_progresses',
                                      'module_progresses'))
        if self.action == 'list':
            filter_kwargs = {'course_id': self.get_course_id()}
            queryset = queryset.filter(**filter_kwargs)
        return queryset

    @extend_schema(
        summary=gettext("Список студентов с их прогрессом по курсу и модулям")
    )
    def list(self, request, *args, **kwargs):
        return super().list(request, *args, **kwargs)
