from rest_framework import serializers

from apps.authentication.api.v1.serializers import serializer as auth_serializers
from apps.tag import models as tag_models
from apps.tag.exceptions import TagException
from apps.tag.models import TagBatch


class TagSerializer(serializers.ModelSerializer):
    """ Tag Model Serializer """

    class Meta:
        model = tag_models.Tag
        fields = [
            'id',
            'country_code',
            'static_code',
            'ownership_code',
            'species_code',
            'serial',
            'tag_code',
            'organization',
            'status',
        ]
        extra_kwargs = {
            'serial': {
                'required': False
            }
        }

    def validate(self, attrs):
        """
        Some validation on tags serialization
        """
        species_code = attrs.get('species_code', None)
        serial_range = attrs.get('serial_range', None)

        if self.Meta.model.objects.filter(species_code=species_code, serial__in=serial_range).exists():
            raise TagException(f'پلاک با سریال مد نظر از قبل وجود دارد', status_code=403)  # noqa

        return attrs

    def update(self, instance, validated_data):
        """ update tag information """

        instance.country_code = validated_data.get(
            'country_code', instance.country_code
        )
        instance.static_code = validated_data.get(
            'static_code', instance.static_code
        )
        instance.ownership_code = validated_data.get(
            'ownership_code', instance.ownership_code
        )
        instance.species_code = validated_data.get(
            'species_code', instance.species_code
        )
        instance.serial = validated_data.get(
            'serial', instance.serial
        )
        instance.tag_code = validated_data.get(
            'tag_code', instance.tag_code
        )
        if validated_data.get('organization'):
            instance.organization = tag_models.auth_models.Organization.objects.get(
                id=validated_data.get('organization', instance.organization).id
            )
        instance.status = validated_data.get('status', instance.status)
        instance.save()
        return instance

    def to_representation(self, instance):
        """ Customize output of serializer """
        representation = super().to_representation(instance)
        if isinstance(instance, tag_models.Tag):
            if instance.organization:
                representation['organization'] = {
                    'name': instance.organization.name,
                    'id': instance.organization.id
                }
        return representation


class TagAssignmentSerializer(serializers.ModelSerializer):
    """ assigned tag serializer """

    class Meta:
        model = tag_models.TagAssignment
        fields = [
            'id',
            'organization',
            'document',
            'serial',
        ]

    def to_representation(self, instance):
        """ custom output for serializer """
        representation = super().to_representation(instance)
        representation['serial'] = instance.serial
        representation['document'] = instance.document
        representation['organization'] = auth_serializers.OrganizationSerializer(
            instance.organization
        ).data
        representation['allocated_tags'] = AllocatedTagsSerializer(
            instance.assigned_allocated_tags.all(), many=True
        ).data
        return representation


class AllocatedTagsSerializer(serializers.ModelSerializer):
    """ allocated tags serializer """

    class Meta:
        model = tag_models.AllocatedTags
        fields = [
            'id',
            'tag',
            'assignment',
            'status'
        ]

    def to_representation(self, instance):
        """ custom output for serializer """
        representation = super().to_representation(instance)
        representation['tag'] = TagSerializer(instance.tag).data
        representation['status'] = instance.status

        return representation


class TagBatchSerializer(serializers.ModelSerializer):
    class Meta:
        model = TagBatch
        fields = '__all__'

    def to_representation(self, instance):
        representation = super().to_representation(instance)

        representation['organization'] = {
            'id': instance.organization.id,
            'name': instance.organization.name
        }

        representation['tag'] = [{
            'tag_code': tag.tag_code,
            'species_code': tag.species_code,
            'status': tag.status
        } for tag in instance.tag.all()]

        return representation


class TagDistributionSerializer(serializers.ModelSerializer):
    class Meta:
        model = tag_models.TagDistribution
        fields = '__all__'

    def to_representation(self, instance):
        """
        customize output of serializer
        """
        representation = super().to_representation(instance)

        if instance.batch:
            representation['batch'] = {
                'id': instance.batch.id,
                'batch_creator': instance.batch.organization.name,
                'batch_identity': instance.batch.batch_identity
            }

        representation['assigner_org'] = {
            'id': instance.assigner_org.id,
            'name': instance.assigner_org.name
        }

        representation['assigned_org'] = {
            'id': instance.assigned_org.id,
            'name': instance.assigned_org.name
        }

        return representation


class TagDistributionBatchSerializer(serializers.ModelSerializer):
    class Meta:
        model = tag_models.TagDistributionBatch
        fields = '__all__'

    def to_representation(self, instance):
        representation = super().to_representation(instance)

        representation['assigner_org'] = {
            'id': instance.assigner_org.id,
            'name': instance.assigner_org.name,
        }

        representation['assigned_org'] = {
            'id': instance.assigned_org.id,
            'name': instance.assigned_org.name
        }

        representation['distributions'] = [{
            'id': dist.id,
            'dist_identity': dist.identity,
            'species_code': dist.species_code,
            'distributed_number': dist.distributed_number
        } for dist in instance.distributions]

        return representation
