# -*- coding: utf-8 -*-
from copy import deepcopy
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from django.contrib.auth.models import User
from django.utils import timezone

from core import models


class CoreModelSerializer(serializers.HyperlinkedModelSerializer):
    """
    Provide the child link (used by most core models) and run model clean()
    methods during POST operations.
    """
    child = serializers.PrimaryKeyRelatedField(
        queryset=models.Child.objects.all())

    def validate(self, attrs):
        # Ensure that all instance data is available for partial updates to
        # support clean methods that compare multiple fields.
        if self.partial:
            new_instance = deepcopy(self.instance)
            for attr, value in attrs.items():
                setattr(new_instance, attr, value)
        else:
            new_instance = self.Meta.model(**attrs)
        new_instance.clean()
        return attrs


class CoreModelWithDurationSerializer(CoreModelSerializer):
    """
    Specific serializer base for models with a "start" and "end" field.
    """
    child = serializers.PrimaryKeyRelatedField(
        allow_null=True, allow_empty=True, queryset=models.Child.objects.all(),
        required=False)

    class Meta:
        abstract = True
        extra_kwargs = {
            'start': {'required': False},
            'end': {'required': False},
        }

    def validate(self, attrs):
        # Check for a special "timer" data argument that can be used in place
        # of "start" and "end" fields as well as "child" if it is set on the
        # Timer entry.
        timer = None
        if 'timer' in self.initial_data:
            try:
                timer = models.Timer.objects.get(pk=self.initial_data['timer'])
            except models.Timer.DoesNotExist:
                raise ValidationError({'timer': ['Timer does not exist.']})
            if timer.end:
                end = timer.end
            else:
                end = timezone.now()
            if timer.child:
                attrs['child'] = timer.child

            # Overwrites values provided directly!
            attrs['start'] = timer.start
            attrs['end'] = end

        # The "child", "start", and "end" field should all be set at this
        # point. If one is not, model validation will fail because they are
        # required fields at the model level.
        if not self.partial:
            errors = {}
            for field in ['child', 'start', 'end']:
                if field not in attrs or not attrs[field]:
                    errors[field] = 'This field is required.'
            if len(errors) > 0:
                raise ValidationError(errors)

        attrs = super().validate(attrs)

        # Only actually stop the timer if all validation passed.
        if timer:
            timer.stop(attrs['end'])

        return attrs


class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'username')


class ChildSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = models.Child
        fields = ('id', 'first_name', 'last_name', 'birth_date', 'slug',
                  'picture')
        lookup_field = 'slug'


class DiaperChangeSerializer(CoreModelSerializer):
    class Meta:
        model = models.DiaperChange
        fields = (
                'id',
                'child',
                'time',
                'wet',
                'solid',
                'color',
                'amount',
                'notes'
            )


class FeedingSerializer(CoreModelWithDurationSerializer):
    class Meta(CoreModelWithDurationSerializer.Meta):
        model = models.Feeding
        fields = ('id', 'child', 'start', 'end', 'duration', 'type', 'method',
                  'amount', 'notes')


class NoteSerializer(CoreModelSerializer):
    class Meta:
        model = models.Note
        fields = ('id', 'child', 'note', 'time')


class SleepSerializer(CoreModelWithDurationSerializer):
    class Meta(CoreModelWithDurationSerializer.Meta):
        model = models.Sleep
        fields = ('id', 'child', 'start', 'end', 'duration', 'nap', 'notes')


class TemperatureSerializer(CoreModelSerializer):
    class Meta:
        model = models.Temperature
        fields = ('id', 'child', 'temperature', 'time', 'notes')


class TimerSerializer(CoreModelSerializer):
    child = serializers.PrimaryKeyRelatedField(
        allow_null=True, allow_empty=True, queryset=models.Child.objects.all(),
        required=False)
    user = serializers.PrimaryKeyRelatedField(
        allow_null=True, allow_empty=True, queryset=User.objects.all(),
        required=False)

    class Meta:
        model = models.Timer
        fields = ('id', 'child', 'name', 'start', 'end', 'duration', 'active',
                  'user')

    def validate(self, attrs):
        attrs = super(TimerSerializer, self).validate(attrs)

        # Set user to current user if no value is provided.
        if 'user' not in attrs or attrs['user'] is None:
            attrs['user'] = self.context['request'].user

        return attrs


class TummyTimeSerializer(CoreModelWithDurationSerializer):
    class Meta(CoreModelWithDurationSerializer.Meta):
        model = models.TummyTime
        fields = ('id', 'child', 'start', 'end', 'duration', 'milestone')


class WeightSerializer(CoreModelSerializer):
    class Meta:
        model = models.Weight
        fields = ('id', 'child', 'weight', 'date', 'notes')