from typing import Optional

from django.contrib.auth import get_user_model
from django.utils.translation import gettext_lazy as _

from rest_framework import serializers

from ..models import CourseStudent, StudentModuleProgress

User = get_user_model()


class UserInlineLabSerializer(serializers.ModelSerializer):
    full_name = serializers.SerializerMethodField()

    def get_full_name(self, obj) -> str:
        return obj.get_full_name()

    class Meta:
        model = User
        fields = ('username', 'full_name')


class GradeStudentLabSerializer(serializers.ModelSerializer):
    user = UserInlineLabSerializer()

    class Meta:
        model = CourseStudent
        fields = (
            'id', 'status', 'completion_date', 'is_passed', 'created', 'user',
        )
        read_only_fields = fields


class CourseStudentProgressModulesField(serializers.DictField):
    def to_representation(self, course_student: CourseStudent):
        return {str(progress.module_id): progress.score for progress in course_student.module_progresses.all()}


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


class StudentCourseProgressListSerializer(serializers.ModelSerializer):
    student = GradeStudentLabSerializer(source='*')
    modules = CourseStudentProgressModulesField(source='*', child=serializers.IntegerField())
    score = CourseStudentProgressScoreField(source='*')

    class Meta:
        model = CourseStudent
        fields = (
            'student', 'modules', 'score',
        )
        read_only_fields = fields


class StudentModuleProgressExternalSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(source='module_id')
    score_updated_at = serializers.DateTimeField(source='modified', label=_("дата обновления балла"))

    class Meta:
        model = StudentModuleProgress
        fields = ('id', 'score', 'score_updated_at')
        read_only_fields = fields


class CourseStudentProgressScoreExternalField(serializers.IntegerField):
    def to_representation(self, course_student: CourseStudent) -> Optional[int]:
        # Сейчас храним не более 1 записи по прогрессу студента в рамках курса,
        # но запись может быть получена через `.prefetch_related`
        progress = next(iter(course_student.course_progresses.all()), None)
        if not progress:
            return None
        return progress.score


class StudentCourseProgressListExternalSerializer(serializers.ModelSerializer):
    started_at = serializers.DateTimeField(source='created', label=_("дата поступления на курс"))
    is_finished = serializers.BooleanField(source='is_passed', label=_("набран проходной балл"))
    finished_at = serializers.DateTimeField(source='passing_date', label=_("дата прохождения курса"))
    yandex_login = serializers.CharField(source='user.username')
    modules = StudentModuleProgressExternalSerializer(source='module_progresses', many=True)
    score = CourseStudentProgressScoreExternalField(source='*', label=_("баллы"))

    class Meta:
        model = CourseStudent
        fields = (
            'id', 'started_at', 'yandex_login', 'status',
            'is_finished', 'finished_at', 'score', 'modules',
        )
        read_only_fields = fields
