from rest_framework import serializers

from apps.core.models import SystemConfig
from apps.herd.services.services import get_rancher_statistic_by_herd, rancher_quota_weight
from apps.livestock.web.api.v1.serializers import LiveStockTypeSerializer
from apps.pos_device.services.services import pos_organizations_sharing_information
from apps.product import models as product_models
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.product.web.api.v1.serializers import product_serializers


class QuotaSerializer(serializers.ModelSerializer):
    class Meta:
        model = product_models.Quota
        fields = '__all__'

    def to_representation(self, instance):
        representation = super().to_representation(instance)
        if isinstance(instance, product_models.Quota):
            if instance.sale_unit:
                representation['sale_unit'] = product_serializers.SaleUnitSerializer(
                    instance.sale_unit
                ).data
            representation['product'] = {"product": instance.product.name, "product_id": instance.product.id}
            representation['incentive_plan'] = QuotaIncentiveAssignmentSerializer(
                instance.incentive_assignments.all(),
                many=True
            ).data

            representation['attribute_values'] = product_serializers.AttributeValueSerializer(
                instance.attribute_values.all(),
                many=True
            ).data

            representation['brokers'] = QuotaBrokerValueSerializer(
                instance.broker_values.all(),
                many=True
            ).data

            representation['livestock_allocations'] = QuotaLiveStockAllocationSerializer(
                instance.livestock_allocations.all(),
                many=True
            ).data

            representation['livestock_limitations'] = QuotaLiveStockAgeLimitationSerializer(
                instance.livestock_age_limitations.all(),
                many=True
            ).data

            representation['limit_by_organizations'] = [
                {"name": limit.name, "id": limit.id} for limit in instance.limit_by_organizations.all()
            ]

        return representation

    def update(self, instance, validated_data):
        """ Custom Update """

        instance.quota_id = validated_data.get('quota_id', instance.quota_id)
        instance.quota_code = validated_data.get('quota_code', instance.quota_code)
        instance.quota_weight = validated_data.get('quota_weight', instance.quota_weight)
        instance.remaining_weight = validated_data.get('remaining_weight', instance.remaining_weight)
        instance.quota_distributed = validated_data.get('quota_distributed', instance.quota_distributed)
        instance.product = validated_data.get('product', instance.product)
        instance.sale_type = validated_data.get('sale_type', instance.sale_type)
        instance.sale_unit = validated_data.get('sale_unit', instance.sale_type)
        instance.month_choices = validated_data.get('month_choices', instance.month_choices)
        instance.sale_license = validated_data.get('sale_license', instance.sale_license)
        instance.group = validated_data.get('group', instance.group)
        instance.has_distribution_limit = validated_data.get('has_distribution_limit', instance.has_distribution_limit)
        instance.distribution_mode = validated_data.get('distribution_mode', instance.distribution_mode)
        instance.has_organization_limit = validated_data.get('has_organization_limit', instance.has_organization_limit)
        instance.base_price_factory = validated_data.get('base_price_factory', instance.base_price_factory)
        instance.base_price_cooperative = validated_data.get('base_price_cooperative', instance.base_price_cooperative)
        instance.final_price = validated_data.get('final_price', instance.final_price)
        instance.is_closed = validated_data.get('is_closed', instance.is_closed)
        instance.closed_at = validated_data.get('closed_at', instance.closed_at)
        instance.save()

        # update assigned organization many to many
        if 'assigned_organizations' in validated_data.keys():
            instance.assigned_organizations.clear()
            instance.assigned_organizations.add(
                *(validated_data.get('assigned_organizations', instance.assigned_organizations))
            )

        # update organization limit many to many
        if 'limit_by_organizations' in validated_data.keys():
            instance.limit_by_organizations.clear()
            instance.limit_by_organizations.add(
                *(validated_data.get('limit_by_organizations', instance.limit_by_organizations))
            )
        else:
            instance.limit_by_organizations.clear()

        return instance


class QuotaStatsSerializer(serializers.ModelSerializer):
    class Meta:
        model = product_models.QuotaStats
        fields = '__all__'


class QuotaIncentiveAssignmentSerializer(serializers.ModelSerializer):
    class Meta:
        model = product_models.QuotaIncentiveAssignment
        fields = [
            "id",
            "quota",
            "incentive_plan",
            "heavy_value",
            "light_value",
        ]

    def to_representation(self, instance):
        """ Custom Output for incentive plans """

        representation = super().to_representation(instance)
        representation['incentive_plan_name'] = instance.incentive_plan.name

        return representation

    def update(self, instance, validated_data):
        """ Custom Update """

        instance.quota = validated_data.get('quota', instance.quota)
        instance.incentive_plan = validated_data.get('incentive_plan', instance.incentive_plan)
        instance.heavy_value = validated_data.get('heavy_value', instance.heavy_value)
        instance.light_value = validated_data.get('light_value', instance.light_value)
        instance.save()

        return instance


class QuotaBrokerValueSerializer(serializers.ModelSerializer):  # noqa
    class Meta:
        model = product_models.QuotaBrokerValue
        fields = [
            "id",
            "quota",
            "org_quota_stat",
            "broker",
            "value",
        ]

    def to_representation(self, instance):
        """ Custom Output of broker values """

        representation = super().to_representation(instance)
        representation['broker_name'] = instance.broker.name

        return representation

    def update(self, instance, validated_data):
        """ Custom Update """

        instance.quota = validated_data.get('quota', instance.quota)
        instance.broker = validated_data.get('broker', instance.broker)
        instance.value = validated_data.get('value', instance.value)
        instance.save()

        return instance


class QuotaLiveStockAllocationSerializer(serializers.ModelSerializer):
    class Meta:
        model = product_models.QuotaLivestockAllocation
        fields = [
            "id",
            "quota",
            "livestock_group",
            "livestock_type",
            "livestock_subtype",
            "quantity_kg",
        ]
        extra_kwargs = {
            'livestock_group': {
                'required': False
            },
            'livestock_type': {
                'required': False
            },
            'livestock_subtype': {
                'required': False
            }
        }

    def to_representation(self, instance):
        """ custom output for live stock type """

        representation = super().to_representation(instance)
        if isinstance(instance, product_models.QuotaLivestockAllocation):
            representation['livestock_type'] = LiveStockTypeSerializer(instance.livestock_type).data

        return representation

    def update(self, instance, validated_data):
        """ Custom Update """

        instance.quota = validated_data.get('quota', instance.quota)
        instance.livestock_group = validated_data.get('livestock_group', instance.livestock_group)
        instance.livestock_type = validated_data.get('livestock_type', instance.livestock_type)
        instance.livestock_subtype = validated_data.get('livestock_subtype', instance.livestock_subtype)
        instance.save()

        return instance


class QuotaLiveStockAgeLimitationSerializer(serializers.ModelSerializer):
    class Meta:
        model = product_models.QuotaLiveStockAgeLimitation
        fields = [
            "id",
            "quota",
            "livestock_type",
            "livestock_subtype",
            "age_month",
        ]

    def to_representation(self, instance):
        """ custom output for livestock type """

        representation = super().to_representation(instance)
        if isinstance(instance, product_models.QuotaLiveStockAgeLimitation):
            representation['livestock_type'] = LiveStockTypeSerializer(
                instance.livestock_type
            ).data

        return representation

    def update(self, instance, validated_data):
        """ Custom Update """

        instance.quota = validated_data.get('quota', instance.quota)
        instance.livestock_type = validated_data.get('livestock_type', instance.livestock_type)
        instance.livestock_subtype = validated_data.get('livestock_subtype', instance.livestock_subtype)
        instance.age_month = validated_data.get('age_month', instance.age_month)
        instance.save()

        return instance


class OrganizationQuotaStatsSerializer(serializers.ModelSerializer):
    class Meta:
        model = product_models.OrganizationQuotaStats
        fields = [
            'id',
            'create_date',
            'modify_date',
            'creator_info',
            'modifier_info',
        ]

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

        representation = super().to_representation(instance)

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

        representation['weight'] = instance.total_amount
        representation['remaining_weight'] = instance.remaining_amount
        representation['distributed'] = instance.total_distributed
        representation['warehouse_entry'] = instance.inventory_received
        representation['warehouse_balance'] = instance.inventory_entry_balance
        representation['been_sold'] = instance.sold_amount
        representation['pre_sale_balance'] = instance.quota.pre_sale_balance
        representation['free_sale_balance'] = instance.quota.free_sale_balance

        representation['free_sale'] = instance.quota.free_sale
        representation['pre_sale'] = instance.quota.pre_sale

        last_distribution = (
            instance.distributions
            .order_by('-create_date')
            .first()
        )

        representation['distribution'] = last_distribution.id if last_distribution else None

        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=device,
            quota=instance.quota,
            quota_stat=instance,
            owner_org=organization
        )

        # get organization bank account that set to a device
        bank_account_device_links = organization.bank_account_device_links.filter(device=device)

        representation['pricing'] = {  # noqa
            'main_account_sheba': "IR" + organization.bank_information.first().sheba
            if not bank_account_device_links.exists() else bank_account_device_links.first().bank_account.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_statistic_by_herd(rancher)
            representation['rancher_statistics'] = livestock_counts_list

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

        return representation
