from apps.product.services.services import quota_live_stock_allocation_info, quota_incentive_plans_info, \
    quota_attribute_value, quota_pricing_items_by_type
from apps.herd.services.services import get_rancher_statistics, rancher_quota_weight
from apps.pos_device.services.services import pos_organizations_sharing_information
from rest_framework.exceptions import APIException
from apps.product import models as product_models
from apps.core.models import SystemConfig
from rest_framework import serializers
from apps.product.exceptions import (
    QuotaWeightException,
    QuotaClosedException,
    QuotaExpiredTimeException,
    QuotaLimitByOrganizationException
)
from django.db import models


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)

        organization = self.context['organization']
        rancher = self.context['rancher']
        device = self.context['device']

        if instance.quota:
            representation['quota'] = {
                'quota_identity': instance.quota.quota_id,
                'quota_weight': instance.quota.quota_weight,
                'pos_sale_type': instance.quota.pos_sale_type,
                'quota_livestock_allocations': quota_live_stock_allocation_info(
                    instance.quota
                ),
                'quota_incentive_plans': quota_incentive_plans_info(instance.quota, rancher),
                'quota_sale_license': instance.quota.sale_license,
                'has_sale_license': instance.quota.is_in_valid_time(),
            }

        sale_limitation = SystemConfig.get(
            "IGNORE_ALL_RANCHER_PURCHASE_LIMITS",
            quota_identity=instance.quota.quota_id
        )
        representation['product'] = {
            'image': instance.quota.product.img,
            'name': instance.quota.product.name,
            'id': instance.quota.product.id,
            'free_sale_for_all': sale_limitation if sale_limitation else False,
            'free_sale_for_this_rancher': rancher.ignore_purchase_limit
        }

        sharing_list = pos_organizations_sharing_information(
                device,
                instance.quota,
                distribution=instance,
                owner_org=organization
            )

        representation['pricing'] = {  # noqa
            'main_account_sheba': organization.bank_information.first().sheba,
            'pricing_attributes': quota_attribute_value(instance.quota),
            'sharing': sharing_list,
            'base_prices': quota_pricing_items_by_type(instance.quota, sharing=sharing_list)
        }

        if 'rancher' in self.context.keys():
            # rancher herd & live stock statistics
            livestock_counts_list, livestock_counts_dict = get_rancher_statistics(rancher)
            representation['rancher_statistics'] = livestock_counts_list

            # rancher live stock statistics by quota distributions
            representation['rancher_quota_weight_statistics'] = rancher_quota_weight(
                rancher, distribution=instance
            )

        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
