# -*- coding: utf-8 -*-
import copy

from collections.abc import Mapping
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext as _
from rest_framework import serializers
from rest_framework.utils.serializer_helpers import ReturnDict


class InternalModelSerializerV2Mixin:
    def get_user(self):
        request = self.context.get('request')
        if request:
            return getattr(request, 'user', None)


class FilterByDataSerializerMixin(object):
    # todo: test me and move to drf-extensions
    """
    class Snippet(models.Model):
        title = models.CharField(max_length=100)


    class SnippetSerializer(FilterByDataSerializerMixin, serializers.ModelSerializer):
        pass


    Snippet.objects.create(id=1, title='hello 1')
    Snippet.objects.create(id=2, title='hello 2')
    Snippet.objects.create(id=3, title='hello 3')

    SnippetSerializer(Snippet.objects.all(), data=[{'id': 1}, {'id': 2}], many=True, filter_by_data=True).data
    [
        {'id': 1, 'title': 'hello 1'},
        {'id': 2, 'title': 'hello 2'},
    ]

    SnippetSerializer(Snippet.objects.all(), data=[1, 2], many=True, filter_by_data=True).data
    [
        {'id': 1, 'title': 'hello 1'},
        {'id': 2, 'title': 'hello 2'},
    ]

    SnippetSerializer(Snippet.objects.exclude(id=1), data=[{'id': 1}, {'id': 2}], many=True, filter_by_data=True).data
    [
        {'id': 2, 'title': 'hello 2'},
    ]

    SnippetSerializer(Snippet.objects.all(), data=[], many=True, filter_by_data=True).data
    []

    """
    def __init__(self, *args, **kwargs):
        self.filter_by_data = kwargs.pop('filter_by_data', False)
        super(FilterByDataSerializerMixin, self).__init__(*args, **kwargs)

    def to_internal_value(self, data):
        if self.filter_by_data:
            return self._field_from_native_filter_by_data(data)
        else:
            return super(FilterByDataSerializerMixin, self).to_internal_value(data)

    def _field_from_native_filter_by_data(self, data):
        if self.read_only:
            return data

        try:
            value = data
        except KeyError:
            if self.default is not None and not self.partial:
                # Note: partial updates shouldn't set defaults
                value = copy.deepcopy(self.default)
            else:
                if self.required:
                    raise ValidationError(self.error_messages['required'])
                return data

        return self.Meta.model.objects.get(pk=value['id'])


class ForeignKeyMixin(object):
    """
    Позволяет создавать связи передавая id в foreignkey serializer
    Пример:
    GET /api/smth/1 -> {'id': 1, related_model: {'id': 1, 'text': 'hello'}}
    POST {'related_model': 2} /api/smth/1 -> {'id': 1, related_model: {'id': 2, 'text': 'smth'}}
    """

    def to_internal_value(self, value):
        model = self.Meta.model
        if isinstance(value, Mapping):
            pk_field_name = self.Meta.model._meta.pk.name
            pk_value = value.get(pk_field_name)
        else:
            pk_value = value

        if pk_value:
            try:
                return model.objects.get(pk=pk_value)
            except model.DoesNotExist:
                raise ValidationError(_('Объекта с таким pk не существует'))
        return super(ForeignKeyMixin, self).to_internal_value(value)


class DictIdSerializer(serializers.ListSerializer):

    @property
    def data(self):
        data = super(DictIdSerializer, self).data
        serialized_data = {
            serialized_object['id']: serialized_object
            for serialized_object in data
        }
        return ReturnDict(serialized_data, serializer=self)
