"""This module holds serializers for ``photostories`` app."""

from rest_framework import serializers
from rest_framework.exceptions import ParseError

from mtp.apps.trainings.apiv2.serializers import TrainingActivitySerializer
from mtp.apps.trainings.models import Training, TrainingSession

from ..models import Photo, Photostory, Strip


class PhotoSerializer(serializers.ModelSerializer):
    """Serializer for ``Photo`` model."""

    strip = serializers.PrimaryKeyRelatedField(
        queryset=Strip.objects.non_deleted(),
        required=False,
    )

    class Meta:
        model = Photo
        fields = (
            'id',
            'image',
            'sort_order',
            'strip',
            'created',
            'modified',
        )
        read_only_fields = ('created', 'modified')

    @property
    def strip_id(self):
        """Return the strip id contained within the url.

        Notes
        -----
        This method exists to make easier testing with mock.

        Returns
        -------
        str

        """

        return self.context.get('view').kwargs.get('parent_lookup_strip')

    def create(self, validated_data):
        """Allow to autofill the strip with the url parameters.

        Parameters
        ----------
        For the parameters, see the ``serializers.ModelSerializer`` class.

        Returns
        -------
        Photo
            The created photo.

        """

        try:
            strip = validated_data.pop('strip')
        except KeyError:
            try:
                strip = Strip.objects.get(id=self.strip_id)
            except Strip.DoesNotExist:
                raise ParseError('The strip id in the url is wrong.')

        return Photo.objects.create(strip=strip, **validated_data)


class StripSerializer(serializers.ModelSerializer):
    """Serializer for ``Strip`` model."""

    photos = PhotoSerializer(many=True, read_only=True)
    photostory = serializers.PrimaryKeyRelatedField(
        queryset=Photostory.objects.non_deleted(),
        required=False,
    )
    session = serializers.PrimaryKeyRelatedField(
        queryset=TrainingSession.objects.non_deleted(),
        required=False,
    )

    class Meta:
        model = Strip
        fields = (
            'id',
            'name',
            'owner',
            'photostory',
            'session',
            'state',
            'photos',
        )
        read_only_fields = (
            'owner',
        )

    @property
    def photostory_id(self):
        """Return the photostory id contained within the url.

        Notes
        -----
        This method exists to make easier testing with mock.

        Returns
        -------
        str

        """

        return self.context.get('view').kwargs.get('parent_lookup_photostory')

    def create(self, validated_data):
        """Allow to autofill the photostory and/or the session with the url parameters.

        Parameters
        ----------
        For the parameters, see the ``serializers.ModelSerializer`` class.

        Returns
        -------
        Strip
            The created strip.

        """

        try:
            photostory = validated_data.pop('photostory')
        except KeyError:
            try:
                photostory = Photostory.objects.get(id=self.photostory_id)
            except Photostory.DoesNotExist:
                raise ParseError('The photostory id in url is wrong.')

        try:
            session = validated_data.pop('session')
        except KeyError:
            session = photostory.session
            if not session:
                raise ParseError('The `session` parameter is missing')

        return Strip.objects.create(photostory=photostory, session=session, **validated_data)


class PhotostorySerializer(TrainingActivitySerializer):
    """Serializer for ``Photostory`` model."""

    training = serializers.PrimaryKeyRelatedField(
        queryset=Training.objects.non_deleted(),
        required=False,
    )
    session = serializers.PrimaryKeyRelatedField(
        queryset=TrainingSession.objects.non_deleted(),
        required=False,
    )

    class Meta:
        model = Photostory
        fields = TrainingActivitySerializer.Meta.fields
        read_only_fields = (
            'sort_order',
        )
        # By default, DRF, even if `sort_order` is add in 'read_only_fields`,
        # will add this validator :
        # ```python
        # UniqueTogetherValidator(
        #     queryset=TrainingActivity.objects.all(),
        #     fields=('sort_order', 'training')
        # )
        # ```
        # But if we don't add `sort_order` in the serializer definition, the validator is not added.
        # So, as it is read only, and there is only this validator, we erase validators list.
        # http://www.django-rest-framework.org/api-guide/validators/#optional-fields
        validators = []
