"""This module contains the apiv2 related serializers for the ``questionnaires`` app"""

from rest_framework import serializers

from mtp.apps.trainings.apiv2.serializers import TrainingActivitySerializer

from ..models import (
    Answer,
    Choice,
    ChoicesAnswer,
    ChoicesQuestion,
    ImageChoicesQuestion,
    LivePolling,
    LiveQuiz,
    OpenAnswer,
    OpenQuestion,
    Polling,
    Quiz,
)


class BaseQuestionnaireSerializer(TrainingActivitySerializer):
    """Base serializer for the ``Questionnaire`` subclasses"""

    questions = serializers.SerializerMethodField()

    class Meta:
        fields = TrainingActivitySerializer.Meta.fields + (
            'questions',
        )

    def get_questions(self, instance):
        """Get the questions for the current questionnaire

        For the parameters, see ``rest_framework.serializers.ModelSerializer``

        Notes
        -----
        We prepopulated the ``all()`` queryset using the ``prefetch_related`` method
        with the ``non_deleted()`` in the view.

        """

        return [
            question.serializer_class(question).data
            for question in instance.questions.all()
        ]


class QuestionnaireWithScoreSerializer(BaseQuestionnaireSerializer):
    """Serializer defining the fields for the questionnaires with scores"""

    class Meta:
        fields = BaseQuestionnaireSerializer.Meta.fields + (
            'is_score_displayed',
        )


class QuizSerializer(QuestionnaireWithScoreSerializer):
    """Serializer for the ``Quiz`` model"""

    class Meta:
        model = Quiz
        fields = QuestionnaireWithScoreSerializer.Meta.fields + (
            'is_questions_order_random',
            'are_questions_mandatory',
        )


class LiveQuizSerializer(QuestionnaireWithScoreSerializer):
    """Serializer for the ``LiveQuiz`` model"""

    class Meta:
        model = LiveQuiz
        fields = QuestionnaireWithScoreSerializer.Meta.fields


class PollingSerializer(BaseQuestionnaireSerializer):
    """Serializer for the ``Polling`` model"""

    class Meta:
        model = Polling
        fields = BaseQuestionnaireSerializer.Meta.fields + (
            'are_questions_mandatory',
        )


class LivePollingSerializer(BaseQuestionnaireSerializer):
    """Serializer for the ``LivePolling`` model"""

    class Meta:
        model = LivePolling
        fields = BaseQuestionnaireSerializer.Meta.fields


class BaseQuestionSerializer(serializers.ModelSerializer):
    """Base serializer for the ``Question`` subclasses"""

    class Meta:
        fields = (
            'id',
            'label',
            'points',
            'sort_order',
            'question_type',
        )


class OpenQuestionSerializer(BaseQuestionSerializer):
    """Serializer for the ``OpenQuestion`` model"""

    class Meta:
        model = OpenQuestion
        fields = BaseQuestionSerializer.Meta.fields


class ChoiceSerializer(serializers.ModelSerializer):
    """Serializer for the ``Choice`` model"""

    class Meta:
        model = Choice
        fields = (
            'id',
            'label',
            'is_valid',
            'sort_order',
        )


class ChoicesQuestionSerializer(BaseQuestionSerializer):
    """Serializer for the ``ChoicesQuestion`` model"""

    choices = serializers.SerializerMethodField()

    class Meta:
        model = ChoicesQuestion
        fields = BaseQuestionSerializer.Meta.fields + (
            'is_multiple_choices',
            'choices',
        )

    def get_choices(self, instance):
        """Filter the non-deleted choices for this question

        Parameters
        ----------
        For the parameters, see ``rest_framework.ModelSerializer``.

        Returns
        -------
        list(dict)
            A list of the serialized choices of this question

        """

        return ChoiceSerializer(
            instance.choices.non_deleted(),
            many=True,
            read_only=True,
        ).data


class ImageChoicesQuestionSerializer(ChoicesQuestionSerializer):
    """Serializer for the ``ImageQuestion`` model"""

    class Meta:
        model = ImageChoicesQuestion
        fields = ChoicesQuestionSerializer.Meta.fields + (
            'image',
        )


class BaseAnswerSerializer(serializers.ModelSerializer):
    """Base serializer for the ``Answer`` subclasses"""

    question_type = serializers.SerializerMethodField()

    class Meta:
        fields = (
            'id',
            'user',
            'session',
            'question',
            'question_type',
        )

        # As it is only one validator for the unique_together constraints,
        # and we don't want to enforce it here, since we handle it in the
        # "create" method below, remove all the validators
        validators = []

    @staticmethod
    def get_question_type(instance):
        """Return the question_type

        Parameters
        ----------
        For the parameters, see ``rest_framework.ModelSerializer``.

        Returns
        -------
        str

        """

        return instance.question.question_type

    def create(self, validated_data):
        """Create or update the answer of the user for the current question

        For the parameters, see ``rest_framework.ModelSerializer.create``.

        """

        question = validated_data.pop('question')

        return question.create_or_update_user_answer(**validated_data)


class ChoicesAnswerSerializer(BaseAnswerSerializer):
    """Serializer for the ``ChoiceAnswer`` model"""

    choices = serializers.PrimaryKeyRelatedField(
        many=True,
        queryset=Choice.objects.non_deleted(),
        allow_empty=True
    )

    class Meta:
        model = ChoicesAnswer
        fields = BaseAnswerSerializer.Meta.fields + (
            'choices',
        )
        validators = BaseAnswerSerializer.Meta.validators


class OpenAnswerSerializer(BaseAnswerSerializer):
    """Serializer for the ``OpenAnswer`` model"""

    class Meta:
        model = OpenAnswer
        fields = BaseAnswerSerializer.Meta.fields + (
            'content',
        )
        validators = BaseAnswerSerializer.Meta.validators


class ReadAnswerSerializer(serializers.ModelSerializer):
    """Serializer for the ``Answer`` model

    This serializer is used only for "read" api endpoints.

    """

    class Meta:
        model = Answer

    def to_representation(self, instance):
        """Initialize the appropriate serializer accordingly to the ``Answer`` subclass

        For the parameters, see ``rest_framework.serializers.ModelSerializer``

        """

        return instance.serializer_class(
            instance,
            context=self.context
        ).to_representation(instance)
