from rest_framework import serializers, status

from apps.core.custom_middlewares.request_middleware import get_current_request
from apps.livestock.web.api.v1.serializers import LiveStockTypeSerializer
from apps.product import models as product_models
from apps.product.exceptions import QuotaException
from apps.product.web.api.v1.serializers import product_serializers
from common.helpers import get_organization_by_user


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

    def validate(self, attrs):
        weight = attrs['quota_weight']
        if self.instance:
            if self.instance.quota_distributed > weight:
                raise QuotaException(
                    "وزن سهمیه نمیتواند کمتر از وزن توزیع شده باشد",  # noqa
                    status.HTTP_403_FORBIDDEN
                )
        return attrs

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

        assigned_orgs = instance.assigned_organizations.all()

        # get request from thread
        request = get_current_request()

        # get organization
        org = get_organization_by_user(request.user)

        # change quota weight by organization received weight
        quota_weight_by_org = instance.quota_amount_by_org(org)
        if quota_weight_by_org:
            # organization quota stat record
            representation['org_quota_stat'] = quota_weight_by_org['id']

            representation['quota_weight'] = quota_weight_by_org['quota_weight']
            representation['quota_distributed'] = quota_weight_by_org['quota_distributed']
            representation['remaining_weight'] = quota_weight_by_org['remaining_weight']
            representation['been_sold'] = quota_weight_by_org['been_sold']
            representation['inventory_received'] = quota_weight_by_org['inventory_received']
            representation['inventory_entry_balance'] = quota_weight_by_org['inventory_entry_balance']
            representation['distributions_number_by_me'] = instance.distributions_assigned.filter(
                assigner_organization=org
            ).count()
            representation['distributions'] = [{
                "id": dist.id,
                "distribution_id": dist.distribution_id,
                "create_date": dist.create_date,
                "modify_date": dist.modify_date,
                "assigner_organization": dist.assigner_organization.name,
                "assigner_organization_id": dist.assigner_organization.id,
                "weight": dist.weight,
            } for dist in instance.distributions_assigned.filter(assigned_organization=org)]

            representation['assigned_to_me'] = True if (
                    org in assigned_orgs or instance.registerer_organization == org
            ) else False

            # list of assigned organizations that received this quota
            representation['assigned_organizations'] = [{
                "name": org.name, "id": org.id
            } for org in assigned_orgs]

        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}

        # quota incentive plan data
        incentive_plan_map = {}
        for assign in instance.incentive_assignments.all():
            plan_id = assign.incentive_plan.id
            if plan_id not in incentive_plan_map:
                incentive_plan_map[plan_id] = {
                    "id": assign.id,
                    "name": assign.incentive_plan.name,
                    "incentive_plan": plan_id,
                    "live_stocks": []
                }

            if assign.livestock_type:
                incentive_plan_map[plan_id]['live_stocks'].append({
                    "id": assign.livestock_type.id,
                    "name": assign.livestock_type.name,
                    "quantity": assign.quantity_kg
                })

        representation['incentive_plan'] = list(incentive_plan_map.values())

        # get quota stat for filtering pricing features (every distribution of this quota has different attributes)
        quota_stat = instance.get_quota_stat(org) if instance.edited_pricing_features else None  # noqa

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

        representation['brokers'] = QuotaBrokerValueSerializer(
            instance.broker_values.filter(org_quota_stat=quota_stat),
            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()
        ]

        # Build a simplified list of pricing items for API output:
        # map `pricing_type_id` to `pricing_type` and keep `name` and `value`
        items = [
            {
                "pricing_type": it["pricing_type_id"],
                "pricing_type_name": it["pricing_type__name"],
                "name": it["name"],
                "value": it["value"],
            }
            for it in instance.pricing_items.values("pricing_type_id", "pricing_type__name", "name", "value")
        ]

        representation["price_calculation_items"] = items

        return representation

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

        fields = [
            "quota_id",
            "quota_code",
            "quota_weight",
            "remaining_weight",
            "quota_distributed",
            "product",
            "sale_type",
            "sale_unit",
            "month_choices",
            "sale_license",
            "group",
            "has_distribution_limit",
            "distribution_mode",
            "has_organization_limit",
            "base_price_factory",
            "base_price_cooperative",
            "final_price",
            "is_closed",
            "closed_at",
            "limit_by_herd_size",
            "pos_sale_type",
            "pre_sale",
            "free_sale",
        ]

        for field in fields:
            setattr(instance, field, validated_data.get(field, getattr(instance, field)))

        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",
            "livestock_type",
            "quantity_kg",
        ]

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

        representation = super().to_representation(instance)
        representation['incentive_plan_name'] = instance.incentive_plan.name
        if instance.livestock_type:
            representation['livestock_type'] = {
                'name': instance.livestock_type.name,
                'id': instance.livestock_type.id
            }

        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 QuotaPriceCalculationPriceItemsSerializer(serializers.ModelSerializer):
    class Meta:
        model = product_models.QuotaPriceCalculationItems
        fields = '__all__'


class QuotaFinalPriceTypeSerializer(serializers.ModelSerializer):
    class Meta:
        model = product_models.QuotaFinalPriceTypes
        fields = '__all__'
