"""This module holds the apiv2 serializers of the ``trainings`` app."""

from rest_framework import serializers

from mtp.apps.accounts.models import MTPUser
from mtp.apps.accounts.apiv2.serializers import MTPUserSerializer
from mtp.apps.common.utils import get_current_timestamp

from ..constants import TRAINING_SESSION_USER_TIMEOUT
from ..models import Training, TrainingActivity, TrainingSession


class TrainingSerializer(serializers.ModelSerializer):
    """Serializer for the ``Training`` model."""

    business_unit = serializers.SerializerMethodField()
    job_profile = serializers.SerializerMethodField()
    original_id = serializers.PrimaryKeyRelatedField(source='original_version', read_only=True)
    tags = serializers.SerializerMethodField()
    header_image = serializers.SerializerMethodField()

    class Meta:
        model = Training
        fields = (
            'business_unit',
            'description',
            'external_id',
            'id',
            'is_assessing',
            'job_profile',
            'name',
            'original_id',
            'tags',
            'header_image',
        )

    def get_business_unit(self, obj):
        """Return the name of the business unit

        Returns
        -------
        str or None
            The name of the business unit, or None if no business unit

        """

        return obj.business_unit.name if obj.business_unit else None

    def get_job_profile(self, obj):
        """Return the name of the job profile

        Returns
        -------
        str or None
            The name of the job profile, or None if no job profile

        """

        return obj.job_profile.name if obj.job_profile else None

    def get_header_image(self, obj):
        """Return the url of the ``header_image`` field.

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

        Returns
        -------
        str
            The url of the ``header_image`` field.

        """
        return obj.get_header_image().url

    @staticmethod
    def get_tags(instance):
        """Get training tags.

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

        return [instance.get_version_state_display()]


class BaseActivitySerializer(serializers.ModelSerializer):
    """Base serializer for the ``TrainingActivity`` model"""

    class Meta:
        model = TrainingActivity
        fields = (
            'id',
            'name',
            'description',
            'session',
            'training',
            'activity_type',
            'sort_order',
        )
        read_only_fields = (
            'activity_type',
            '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 = []


class TrainingActivitySerializer(BaseActivitySerializer):
    """Serializer for the ``TrainingActivity`` models related to the ``Training`` model

    This serializer make the field ``session`` to read_only and the field ``training`` to required.

    """

    session = serializers.PrimaryKeyRelatedField(read_only=True)
    training = serializers.PrimaryKeyRelatedField(
        required=True,
        queryset=Training.objects.non_deleted()
    )

    class Meta:
        model = TrainingActivity
        fields = BaseActivitySerializer.Meta.fields
        read_only_fields = BaseActivitySerializer.Meta.read_only_fields
        validators = BaseActivitySerializer.Meta.validators


class SessionActivitySerializer(BaseActivitySerializer):
    """Serializer for the ``TrainingActivity`` models related to the ``TrainingSession`` model

    This serializer make the field ``session`` to required and the field ``training`` to read_only.

    """

    session = serializers.PrimaryKeyRelatedField(
        required=True,
        queryset=TrainingSession.objects.non_deleted()
    )
    training = serializers.PrimaryKeyRelatedField(read_only=True)

    class Meta:
        model = TrainingActivity
        fields = BaseActivitySerializer.Meta.fields
        read_only_fields = BaseActivitySerializer.Meta.read_only_fields
        validators = BaseActivitySerializer.Meta.validators


class TrainingSessionSerializer(serializers.ModelSerializer):
    """Serializer for the ``TrainingSession`` model."""

    trainer = MTPUserSerializer(read_only=True)
    trainer_id = serializers.PrimaryKeyRelatedField(
        source='trainer',
        queryset=MTPUser.objects.non_deleted(),
        write_only=True,
        required=False,
    )
    training = TrainingSerializer(read_only=True)
    training_id = serializers.PrimaryKeyRelatedField(
        source='training',
        queryset=Training.objects.non_deleted(),
        write_only=True,
    )

    class Meta:
        model = TrainingSession
        fields = (
            'end_date',
            'id',
            'is_live',
            'permissions',
            'start_date',
            'state',
            'token',
            'trainer',
            'trainer_id',
            'training',
            'training_id',
            'users',
        )
        read_only_fields = (
            'id',
            'token',
            'users',
        )


class TokenSerializer(serializers.ModelSerializer):
    """Serializer for the token of ``TrainingSession`` model."""

    class Meta:
        model = TrainingSession
        fields = (
            'id',
        )


class SessionUserStatusSerializer(serializers.Serializer):
    """Serializer for the user status in a training session"""

    user_id = serializers.UUIDField()
    online = serializers.SerializerMethodField()

    def get_online(self, instance):
        """Status of the user regarding the session

        A user is considered "online" if the last ping for this user is from less than
        15 seconds ago.

        Returns
        -------
        bool
            True if the user is considered as "online",
            False otherwise.

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

        See Also
        --------
        ``mtp.apps.trainings.apiv2.views.SessionUsersStatusView`` to see the content of
        the ``instance`` provided to this serializer.

        """

        duration = (get_current_timestamp() - instance['timestamp']) / 100000
        return duration < TRAINING_SESSION_USER_TIMEOUT
