""" This module holds the serializers of the ``brainstormers`` app. """

from django.shortcuts import get_object_or_404

from rest_framework import serializers
from rest_framework.exceptions import ParseError

from mtp.apps.brainstormers.constants import BRAINSTORMER_TYPE_CHOICES
from mtp.apps.brainstormers.models import (
    Brainstormer,
    BrainstormerProposition,
    BrainstormerPropositionGroup,
    BrainstormerTemplate
)

from mtp.apps.likes.api.serializers import LikeableSerializer


class BrainstormerTemplateSerializer(serializers.ModelSerializer):
    """
    Serializer for ``brainstormers.BrainstormerTemplate`` objects.
    """

    class Meta:
        model = BrainstormerTemplate
        fields = (
            'id',
            'name',
            'description',
            'activity_type',
            'sort_order',
            'session',
            'training',
        )


class BrainstormerPropositionSimpleSerializer(LikeableSerializer, serializers.ModelSerializer):
    """Serializer for ``brainstormers.BrainstormerProposition`` model.

    This serializer is "simple": it does not include the nested relationships.

    """
    modified = serializers.DateTimeField(
        read_only=True
    )
    created = serializers.DateTimeField(
        read_only=True
    )

    class Meta(LikeableSerializer.Meta):
        model = BrainstormerProposition
        fields = (
            'id',
            'text',
            'user',
            'created',
            'modified',
        ) + LikeableSerializer.Meta.fields


class BrainstormerPropositionGroupSimpleSerializer(serializers.ModelSerializer):
    """Serializer for ``brainstormers.BrainstormerPropositionGroup`` model.

    This serializer is "simple": it does not include the nested relationships.

    """

    order = serializers.IntegerField(source='sort_order', required=False)  # For iOS compatibility

    class Meta:
        model = BrainstormerPropositionGroup
        fields = ('id', 'name', 'color', 'order',)


class BrainstormerPropositionSerializer(LikeableSerializer, serializers.ModelSerializer):
    """Serializer for ``brainstormers.BrainstormerProposition`` objects."""

    modified = serializers.DateTimeField(
        read_only=True
    )
    created = serializers.DateTimeField(
        read_only=True
    )
    groups = serializers.PrimaryKeyRelatedField(
        many=True,
        queryset=BrainstormerPropositionGroup.objects.filter(is_deleted=False),
        required=False
    )

    class Meta(LikeableSerializer.Meta):
        model = BrainstormerProposition
        fields = (
            'id',
            'text',
            'groups',
            'user',
            'created',
            'modified'
        ) + LikeableSerializer.Meta.fields

    def create(self, validated_data):
        """Create a new propositions adding groups if needed.

        For the parameters, see ``rest_framework.serializers.ModelSerializer``
        """
        brainstormer_pk = self.context['view'].kwargs['parent_lookup_brainstormer']
        brainstormer = get_object_or_404(Brainstormer, pk=brainstormer_pk)
        validated_data.update({"brainstormer": brainstormer})

        groups = validated_data.pop('groups', [])
        proposition = BrainstormerProposition.objects.create(**validated_data)
        if groups:
            proposition.groups.add(*groups)
        return proposition


class BrainstormerPropositionGroupSerializer(serializers.ModelSerializer):
    """
    Serializer for ``brainstormers.BrainstormerPropositionGroup`` objects.

    """

    brainstormer = serializers.PrimaryKeyRelatedField(read_only=True)
    order = serializers.IntegerField(source='sort_order', required=False)  # For iOS compatibility
    x = serializers.DecimalField(  # pylint: disable=invalid-name
        max_digits=6,
        decimal_places=2,
        source='coord_x',  # For iOS compatibility
        required=False
    )
    y = serializers.DecimalField(  # pylint: disable=invalid-name
        max_digits=6,
        decimal_places=2,
        source='coord_y',  # For iOS compatibility
        required=False
    )

    class Meta:
        model = BrainstormerPropositionGroup
        fields = ('id', 'name', 'brainstormer', 'color',
                  'x', 'y', 'order')

    def create(self, validated_data):
        brainstormer_id = self.context.get('view').kwargs.get('parent_lookup_brainstormer')

        try:
            brainstormer = Brainstormer.objects.get(id=brainstormer_id)
        except Brainstormer.DoesNotExist:
            raise ParseError("brainstormer_id incorrect : object does not exist")

        return BrainstormerPropositionGroup.objects.create(
            brainstormer=brainstormer, **validated_data
        )


class BrainstormerSerializer(serializers.ModelSerializer):
    """Serializer for ``brainstormers.Brainstormer`` objects."""

    activity_type = serializers.SerializerMethodField()
    training = serializers.SerializerMethodField()
    proposals = BrainstormerPropositionSerializer(
        source="get_propositions", many=True, read_only=True)
    proposal_groups = BrainstormerPropositionGroupSerializer(
        source="groups", many=True, read_only=True
    )

    class Meta:
        model = Brainstormer
        fields = (
            'id',
            'name',
            'description',
            'activity_type',
            'sort_order',
            'session',
            'training',
            'brainstormer_type',
            'anonymous',
            'proposals',
            'proposal_groups',
        )

    @staticmethod
    def get_training(instance):  # pylint: disable=unused-argument
        """For compatibility with the ``TrainingActivitySerializer``

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

        """

        return None

    @staticmethod
    def get_activity_type(instance):
        """Return the activity type

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

        """

        return BRAINSTORMER_TYPE_CHOICES.for_value(
            instance.brainstormer_type
        ).constant.lower()
