from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema_field

from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from lms.courses.models import Course, CourseGroup, CourseStudent
from lms.courses.serializers import CourseGroupInlineSerializer
from lms.tracker.models import EnrolledUserTrackerIssue

from ..models import EnrolledUser, Enrollment
from .enroll_survey import EnrollSurveyDataSerializer


class EnrolledUserListSerializer(serializers.ModelSerializer):
    class Meta:
        model = EnrolledUser
        fields = (
            'id', 'course_id', 'enrollment_id', 'user_id', 'group_id',
            'survey_id', 'status', 'created', 'modified',
        )
        read_only_fields = fields


class EnrolledUserCreateSerializer(serializers.ModelSerializer):
    enrollment_id = serializers.PrimaryKeyRelatedField(
        source='enrollment', queryset=Enrollment.objects.active(), required=False
    )
    group_id = serializers.PrimaryKeyRelatedField(
        source='group', queryset=CourseGroup.objects.available().not_full(), required=False
    )

    class Meta:
        model = EnrolledUser
        fields = (
            'enrollment_id', 'group_id', 'survey_data', 'comments',
        )

    def validate(self, attrs):
        course = self.context['course']
        request = self.context['request']
        instance = EnrolledUser(course=course, user=request.user, **attrs)
        instance.clean()

        # валидация полей анкеты
        survey = instance.survey
        if survey:
            context = self.context
            context['survey'] = survey
            survey_data = attrs.get('survey_data', {})
            serializer = EnrollSurveyDataSerializer(data=survey_data, context=context)
            if not serializer.is_valid(raise_exception=False):
                raise ValidationError({'survey_data': serializer.errors})

            survey_data.update(**serializer.validated_data)

        return attrs


# class UserEnrollListSerializer(serializers.ModelSerializer):
#     class Meta:
#         model = EnrolledUser
#         fields = (
#             'id', 'course_id', 'enrollment_id', 'group_id',
#             'survey_id', 'status', 'created', 'modified',
#         )
#         read_only_fields = fields


class DeprecatedEnrollmentDetailInUserEnrollSerializer(serializers.ModelSerializer):
    class Meta:
        model = Enrollment
        fields = (
            'id', 'course_id', 'survey_id', 'enroll_type', 'name',
        )
        read_only_fields = fields


class DeprecatedUserEnrollDetailSerializer(serializers.ModelSerializer):
    enrollment = DeprecatedEnrollmentDetailInUserEnrollSerializer(read_only=True)
    parameters = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = EnrolledUser
        fields = (
            'id', 'course_id', 'enrollment', 'group_id',
            'survey_id', 'status', 'created', 'modified',
            'parameters',
        )
        read_only_fields = fields

    @extend_schema_field(OpenApiTypes.NONE)
    def get_parameters(self, obj: EnrolledUser) -> None:
        return None


class EnrolledUserDetailLabSerializer(serializers.ModelSerializer):
    group = CourseGroupInlineSerializer()

    class Meta:
        model = EnrolledUser
        fields = (
            'id', 'course_id', 'enrollment_id', 'user_id', 'group',
            'enroll_date', 'completion_date',
            'status', 'created', 'modified',
        )
        read_only_fields = fields


class EnrolledUserUpdateLabSerializer(serializers.ModelSerializer):
    class Meta:
        model = EnrolledUser
        fields = (
            'status',
        )


class UserEnrollCourseInlineSerializer(serializers.ModelSerializer):
    categories = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
    type = serializers.ChoiceField(choices=Course.TypeChoices.choices, source='course_type')

    class Meta:
        model = Course
        fields = (
            'id', 'slug', 'name', 'num_hours', 'format', 'categories', 'type', 'structure', 'is_active', 'is_archive',
        )
        read_only_fields = fields


class EnrolledUserTrackerIssueInlineSerializer(serializers.ModelSerializer):
    class Meta:
        model = EnrolledUserTrackerIssue
        fields = (
            'issue_key', 'issue_status', 'status', 'is_default',
        )
        read_only_fields = fields


class CourseProgressScoreField(serializers.IntegerField):
    def to_representation(self, enrolled_user: EnrolledUser) -> int:
        if not enrolled_user.course_student_id:
            return 0
        progress = next(iter(enrolled_user.course_student.course_progresses.all()), None)
        if not progress:
            return 0
        return progress.score


class CourseStudentProgressScoreField(serializers.IntegerField):
    def to_representation(self, course_student: CourseStudent):
        progress = next(iter(course_student.course_progresses.all()), None)
        if not progress:
            return None
        return progress.score


class CourseStudentInlineSerializer(serializers.ModelSerializer):
    score = CourseStudentProgressScoreField(source='*', allow_null=True)

    class Meta:
        model = CourseStudent
        fields = (
            'id', 'status', 'is_passed', 'score',
        )
        read_only_fields = fields


class UserEnrollListSerializer(serializers.ModelSerializer):
    course = UserEnrollCourseInlineSerializer()
    issues = EnrolledUserTrackerIssueInlineSerializer(many=True)
    status = serializers.ChoiceField(
        choices=list(dict(EnrolledUser.StatusChoices.choices + CourseStudent.StatusChoices.choices).items()),
        source='course_status',
    )
    name = serializers.CharField(source='course_name')
    # TODO убрать score. пока оставил для обратной совместимости
    score = CourseProgressScoreField(source='*', read_only=True)
    student = CourseStudentInlineSerializer(source='course_student', allow_null=True)

    class Meta:
        model = EnrolledUser
        fields = (
            'id', 'course', 'course_id', 'enrollment_id', 'group_id', 'status',
            'name', 'begin_date', 'end_date', 'score', 'student',
            'issues', 'created', 'modified',
        )
        read_only_fields = fields


class UserEnrollDetailSerializer(serializers.ModelSerializer):
    course = UserEnrollCourseInlineSerializer()
    issues = EnrolledUserTrackerIssueInlineSerializer(many=True)
    status = serializers.ChoiceField(
        choices=list(dict(EnrolledUser.StatusChoices.choices + CourseStudent.StatusChoices.choices).items()),
        source='course_status',
    )
    name = serializers.CharField(source='course_name')
    # TODO убрать score. пока оставил для обратной совместимости
    score = CourseProgressScoreField(source='*', read_only=True)
    student = CourseStudentInlineSerializer(source='course_student', allow_null=True)

    class Meta:
        model = EnrolledUser
        fields = (
            'id', 'course', 'course_id', 'enrollment_id', 'group_id', 'status',
            'name', 'begin_date', 'end_date', 'score', 'student',
            'issues', 'created', 'modified',
        )
        read_only_fields = fields
