from apps.utils.serializers import CustomModelSerializer
from rest_framework import serializers
from .models import Questioncat, Question, Paper, PaperQuestion, Exam, ExamRecord, AnswerDetail, Train
from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE
from django.db import transaction
from apps.utils.snowflake import idWorker

class QuestioncatSerializer(CustomModelSerializer):
    class Meta:
        model = Questioncat
        fields = '__all__'

class QuestionSerializer(CustomModelSerializer):
    questioncat_name = serializers.CharField(source="questioncat.name", read_only=True)
    class Meta:
        model = Question
        fields = '__all__'

class PaperListSerializer(CustomModelSerializer):
    class Meta:
        model = Paper
        exclude = ["questions"]

class PaperPatchSerializer(CustomModelSerializer):
    class Meta:
        model = Paper
        fields = ["name"]

class PaperQuestionSerializer(CustomModelSerializer):
    question_name = serializers.CharField(source="question.name", read_only=True)
    question_type = serializers.CharField(source="question.type", read_only=True)
    class Meta:
        model = PaperQuestion
        fields = '__all__'
        read_only_fields = EXCLUDE_FIELDS_BASE + ["paper"]

class PaperSerializer(CustomModelSerializer):
    detail = PaperQuestionSerializer(many=True)
    class Meta:
        model = Paper
        exclude = ["questions"]
        read_only_fields = EXCLUDE_FIELDS
    
    def create(self, validated_data):
        detail = validated_data.pop("detail", [])
        with transaction.atomic():
            question_ids = [item["question"] for item in detail]
            if len(question_ids) != len(set(question_ids)):
                raise serializers.ValidationError("存在重复的题目")
            paper = Paper.objects.create(**validated_data)
            qs = [PaperQuestion(id=idWorker.get_id(), paper=paper, question=item["question"], total_score=item["total_score"], sort=item["sort"]) for item in detail]
            PaperQuestion.objects.bulk_create(qs)
        return paper
    
    def update(self, instance, validated_data):
        detail = validated_data.pop("detail", [])
        with transaction.atomic():
            paper = super().update(instance, validated_data)
            # 删除未有的数据
            question_ids = [item["question"] for item in detail]
            if len(question_ids) != len(set(question_ids)):
                raise serializers.ValidationError("存在重复的题目")
            PaperQuestion.objects.filter(paper=paper).exclude(question__id__in=question_ids).delete()
            # 更新新数据
            for item in detail:
                PaperQuestion.objects.update_or_create(
                    paper=instance,
                    question=item["question"],
                    defaults={
                        "total_score": item["total_score"],
                        "sort": item["sort"]
                    }
                )
        return paper
    
    def to_representation(self, instance):
        ret = super().to_representation(instance)
        ret['detail'] = sorted(ret['detail'], key=lambda x: (x['sort'], x['create_time']))
        return ret

class ExamSerializer(CustomModelSerializer):
    create_by_name = serializers.CharField(source='create_by.name', read_only=True)
    paper_name = serializers.CharField(source='paper.name', read_only=True)
    paper_total_score = serializers.IntegerField(source='paper.total_score', read_only=True)
    paper_pass_score = serializers.IntegerField(source='paper.pass_score', read_only=True)
    paper_limit = serializers.IntegerField(source='paper.limit', read_only=True)
    paper = serializers.PrimaryKeyRelatedField(queryset=Paper.objects.all(), label='有考试记录,编辑时忽略')
    class Meta:
        model = Exam
        fields = "__all__"
        read_only_fields = EXCLUDE_FIELDS
    
    def update(self, instance, validated_data):
        if ExamRecord.objects.filter(exam=instance).exists():
            validated_data.pop("paper", None)
        return super().update(instance, validated_data)

class ExamDetailSerializer(CustomModelSerializer):
    paper_ = PaperSerializer(source='paper')

    class Meta:
        model = Exam
        fields = "__all__"
        read_only_fields = EXCLUDE_FIELDS



class AnswerDetailOutSerializer(CustomModelSerializer):
    name = serializers.ReadOnlyField(source='question.name')
    options = serializers.ReadOnlyField(source='question.options')
    type = serializers.ReadOnlyField(source='question.type')
    img = serializers.ReadOnlyField(source='question.img')
    questioncat_name = serializers.ReadOnlyField(
        source='question.questioncat.name')
    level = serializers.ReadOnlyField(source='question.level')

    class Meta:
        model = AnswerDetail
        fields = ['id', 'question', 'name', 'options', 'type', 'level',
                  'total_score', 'questioncat_name', 'img', 'user_answer', 'score', 'is_right']


class AnswerDetailSerializer(AnswerDetailOutSerializer):
    right = serializers.ReadOnlyField(source='question.right')
    class Meta:
        model = AnswerDetail
        fields = ['id', 'question', 'name', 'options', 'type', 'level', 'right',
                  'total_score', 'questioncat_name', 'img', 'user_answer', 'score', 'is_right']

class AnswerDetailUpdateSerializer(serializers.Serializer):
    id = serializers.CharField(label='下发ID')
    user_answer = serializers.JSONField(label='作答')

class ExamRecordInitSerizlier(CustomModelSerializer):
    detail = serializers.SerializerMethodField()

    class Meta:
        model = ExamRecord
        fields = ["id", "detail"]
    
    def get_detail(self, obj):
        objs = AnswerDetail.objects.select_related('question').filter(
            examrecord=obj).order_by('id')
        return AnswerDetailOutSerializer(instance=objs, many=True).data


class TookSerializerMixin:
    took_format = serializers.SerializerMethodField()

    def get_took_format(self, obj):
        m, s = divmod(obj.took, 60)
        h, m = divmod(m, 60)
        return "%02d:%02d:%02d" % (h, m, s) 

class ExamRecordSerializer(CustomModelSerializer, TookSerializerMixin):
    create_by_name = serializers.CharField(source='create_by.name', read_only=True)
    exam_open_time = serializers.DateTimeField(source='exam.open_time', read_only=True)
    exam_close_time = serializers.DateTimeField(source='exam.close_time', read_only=True)
    total_score = serializers.IntegerField(source='exam.paper.total_score', read_only=True)
    pass_score = serializers.IntegerField(source='exam.paper.pass_score', read_only=True)
    exam_name = serializers.CharField(source='exam.name', read_only=True)
    paper_name = serializers.CharField(source='exam.paper.name', read_only=True)
    
    class Meta:
        model = ExamRecord 
        exclude = ["questions"]


class ExamRecordDetailSerializer(ExamRecordSerializer, TookSerializerMixin):
    detail = serializers.SerializerMethodField()
    
    class Meta:
        model = ExamRecord
        fields = "__all__"

    def get_detail(self, obj):
        objs = AnswerDetail.objects.select_related('question').filter(
            examrecord=obj).order_by('id')
        return AnswerDetailSerializer(instance=objs, many=True).data

class ExamRecordSubmitSerializer(serializers.ModelSerializer):
    detail = AnswerDetailUpdateSerializer(many=True)

    class Meta:
        model = ExamRecord
        fields = ['detail']

class TrainingSerializer(CustomModelSerializer):

    class Meta:
        model = Train
        fields = "__all__"
