from rest_framework import serializers
from apps.product import models as product_models
from rest_framework.exceptions import APIException
from apps.product.web.api.v1.serializers.quota_serializers import QuotaSerializer
from django.db import models
from apps.product.exceptions import (
    QuotaWeightException,
    QuotaClosedException,
    QuotaExpiredTimeException,
    QuotaLimitByOrganizationException
)


class QuotaDistributionSerializer(serializers.ModelSerializer):
    class Meta:
        model = product_models.QuotaDistribution
        fields = '__all__'
        extra_kwargs = {
            'assigner_organization': {
                'required': False
            }
        }

    def validate(self, data):
        """
        @ to validate if distribution weight
        more than quota weight raise exception
        @ if quota is closed raise exception
        @ if quota has organization limit, before distribution
        check assigned organization
        """

        quota = data['quota']
        assigned_organization = data['assigned_organization']
        amount = data['weight']
        instance_id = self.instance.id if self.instance else None

        # check quota expired time
        if not quota.is_in_valid_time():
            raise QuotaExpiredTimeException()

        # check if quota is closed
        if quota.is_closed:
            raise QuotaClosedException()

        # check if assigned organization is in quota limitation
        if quota.has_organization_limit is True and assigned_organization not in quota.limit_by_organizations.all():
            raise QuotaLimitByOrganizationException()

        # total quota distributions weight
        total = product_models.QuotaDistribution.objects.filter(
            quota=quota
        ).exclude(id=instance_id).aggregate(
            total=models.Sum('weight')
        )['total'] or 0
        if total + amount > quota.quota_weight:
            raise QuotaWeightException()

        if self.instance:
            # total warehouse inventory entry
            total_entry = self.instance.inventory_entry.aggregate(
                total=models.Sum('weight')
            )['total'] or 0

            # if inventory entry weight is bigger than distribute weight in edit distribution
            if total_entry > self.instance.weight:
                raise APIException("وزن وارد شده کمتر از وزن ورودی به انبار است", code=403)  # noqa

            # if weight is more than distribution remaining weight
            if self.instance.weight > self.instance.remaining_weight:
                raise APIException("وزن وارد شده بیشتر از وزن باقیمانده است", code=403)  # noqa

        return data

    def to_representation(self, instance):
        """ Custom output of serializer """

        representation = super().to_representation(instance)
        if instance.quota:
            representation['quota'] = QuotaSerializer(instance.quota).data

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

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

        return representation
