from rest_framework import serializers

from authentication.serializers import OwnerSerializer
from hostadmin.models import Domain
from toolshed.models import Category, Property, Tag


class SlugPathField(serializers.SlugRelatedField):
    def to_internal_value(self, data):
        path = data.split('/') if '/' in data else [data]
        candidates = self.get_queryset().filter(name=path[-1])
        if len(candidates) == 1:
            return candidates.first()
        if len(candidates) == 0:
            raise serializers.ValidationError(
                "No {} with name '{}' found".format(self.queryset.model.__name__, path[-1]))
        if len(candidates) > 1 and len(path) == 1:
            raise serializers.ValidationError("Multiple {}s with name '{}' found, please specify the parent".format(
                self.queryset.model.__name__, path[-1]))
        parent = self.to_internal_value('/'.join(path[:-1]))
        candidates = self.get_queryset().filter(name=path[-1], parent=parent)
        if len(candidates) == 1:
            return candidates.first()
        if len(candidates) == 0:
            raise serializers.ValidationError(
                "No {} with name '{}' found".format(self.queryset.model.__name__, path[-1]))

    def to_representation(self, value):
        source = getattr(value, self.field_name, None)  # should this use self.source?
        prefix = self.to_representation(source) + '/' if source else ''
        return prefix + getattr(value, self.slug_field)


class DomainSerializer(serializers.ModelSerializer):
    owner = OwnerSerializer(read_only=True)

    class Meta:
        model = Domain
        fields = ['name', 'owner', 'open_registration']


class CategorySerializer(serializers.ModelSerializer):
    parent = SlugPathField(slug_field='name', queryset=Category.objects.all(), required=False)

    def validate(self, attrs):
        if 'name' in attrs:
            if '/' in attrs['name']:
                raise serializers.ValidationError("Category name cannot contain '/'")
        return attrs

    def create(self, validated_data):
        try:
            return Category.objects.create(**validated_data)
        except Exception as e:
            raise serializers.ValidationError(e)

    class Meta:
        model = Category
        fields = ['name', 'description', 'parent', 'origin']
        read_only_fields = ['origin']
        ref_name = 'HostAdminCategory'


class PropertySerializer(serializers.ModelSerializer):
    category = SlugPathField(slug_field='name', queryset=Category.objects.all(), required=False)

    def validate(self, attrs):
        if 'name' in attrs:
            if '/' in attrs['name']:
                raise serializers.ValidationError("Property name cannot contain '/'")
        return attrs

    def create(self, validated_data):
        try:
            return Property.objects.create(**validated_data)
        except Exception as e:
            raise serializers.ValidationError(e)

    class Meta:
        model = Property
        fields = ['name', 'description', 'category', 'unit_symbol', 'unit_name', 'unit_name_plural', 'base2_prefix',
                  'dimensions', 'origin']
        read_only_fields = ['origin']
        ref_name = 'HostAdminProperty'


class TagSerializer(serializers.ModelSerializer):
    category = SlugPathField(slug_field='name', queryset=Category.objects.all(), required=False)

    def validate(self, attrs):
        if 'name' in attrs:
            if '/' in attrs['name']:
                raise serializers.ValidationError("Tag name cannot contain '/'")
        return attrs

    def create(self, validated_data):
        try:
            return Tag.objects.create(**validated_data)
        except Exception as e:
            raise serializers.ValidationError(e)

    class Meta:
        model = Tag
        fields = ['name', 'description', 'category', 'origin']
        read_only_fields = ['origin']
        ref_name = 'HostAdminTag'