from rest_framework import serializers
from decimal import Decimal
from .models import Product, ProductImage
from apps.business.schemes.models import OpportunityBundle


class ProductImageSerializer(serializers.ModelSerializer):
    image_url = serializers.SerializerMethodField()

    class Meta:
        model = ProductImage
        fields = ['id', 'product', 'image', 'image_url', 'alt_text', 'is_primary', 'sort_order', 'created_at']
        read_only_fields = ['id', 'product', 'image_url', 'created_at']

    def get_image_url(self, obj):
        request = self.context.get('request')
        if obj.image and request:
            return request.build_absolute_uri(obj.image.url)
        return obj.image.url if obj.image else None

class ProductSerializer(serializers.ModelSerializer):
    opportunity_bundle = serializers.PrimaryKeyRelatedField(
        queryset=OpportunityBundle.objects.all(),
        required=False,
        allow_null=True,
    )
    opportunity_bundle_name = serializers.SerializerMethodField()
    opportunity_bundle_amount = serializers.SerializerMethodField()
    images = ProductImageSerializer(many=True, read_only=True)
    primary_image_url = serializers.SerializerMethodField()

    class Meta:
        model = Product
        fields = '__all__'

    def to_internal_value(self, data):
        # Backward-compatible payload support from existing admin UI/client payloads.
        if hasattr(data, 'copy'):
            data = data.copy()
        if isinstance(data, dict) and 'opportunityBundle' in data and 'opportunity_bundle' not in data:
            data['opportunity_bundle'] = data.get('opportunityBundle')
        return super().to_internal_value(data)

    def get_scheme_name(self, obj):
        if obj.opportunity_bundle:
            return obj.opportunity_bundle.name
        return None

    def get_opportunity_bundle_name(self, obj):
        if obj.opportunity_bundle:
            return obj.opportunity_bundle.name
        return None

    def get_opportunity_bundle_amount(self, obj):
        if obj.opportunity_bundle and getattr(obj.opportunity_bundle, 'opportunity_bundle_amount', None) is not None:
            return str(obj.opportunity_bundle.opportunity_bundle_amount)
        return None

    def get_primary_image_url(self, obj):
        primary = obj.images.filter(is_primary=True).first() or obj.images.first()
        if not primary or not primary.image:
            return None
        request = self.context.get('request')
        if request:
            return request.build_absolute_uri(primary.image.url)
        return primary.image.url

    def validate_base_cost(self, value):
        if value <= 0:
            raise serializers.ValidationError("Base cost must be greater than 0.")
        return value

    def validate_gst_percentage(self, value):
        if value < 0:
            raise serializers.ValidationError("GST percentage must be >= 0.")
        return value

    def validate_twm_max_percentage(self, value):
        if value < 0 or value > 100:
            raise serializers.ValidationError("TWM max percentage must be between 0 and 100.")
        return value

    def validate_part_payment_percentage(self, value):
        if value < 1 or value > 99:
            raise serializers.ValidationError("Part payment percentage must be between 1 and 99.")
        return value

    def validate_part_payment_initial_amount(self, value):
        if value is None:
            return value
        try:
            amt = Decimal(str(value))
        except Exception:
            raise serializers.ValidationError("Initial amount must be a valid decimal number.")
        if amt <= Decimal('0'):
            raise serializers.ValidationError("Initial amount must be greater than 0.")
        # If base_cost is present on payload, ensure initial < base_cost
        base_cost = None
        if isinstance(self.initial_data, dict):
            base_cost = self.initial_data.get('base_cost')
        if base_cost is None and self.instance:
            base_cost = getattr(self.instance, 'base_cost', None)
        if base_cost is not None:
            try:
                base = Decimal(str(base_cost))
                if amt >= base:
                    raise serializers.ValidationError("Initial amount must be less than the product total/base cost.")
            except Exception:
                pass
        return value

    def validate_part_payment_cooling_days(self, value):
        if value < 1:
            raise serializers.ValidationError("Cooling days must be at least 1.")
        return value

    def validate(self, data):
        if data.get('is_pooling_enabled') and not data.get('opportunity_bundle'):
            raise serializers.ValidationError({"opportunity_bundle": "Opportunity Bundle is required if pooling is enabled."})

        instance = getattr(self, 'instance', None)

        allow_part = data.get('allow_part_payment')
        if allow_part is None and instance is not None:
            allow_part = instance.allow_part_payment
        allow_part = bool(allow_part)

        opportunity_bundle = data.get('opportunity_bundle')
        if opportunity_bundle is None and instance is not None:
            opportunity_bundle = instance.opportunity_bundle

        conversion_product = data.get('part_payment_conversion_product')
        if conversion_product is None and instance is not None:
            conversion_product = instance.part_payment_conversion_product

        if allow_part:
            if not opportunity_bundle:
                raise serializers.ValidationError({
                    "allow_part_payment": "Part payment can only be enabled for bundle-linked products."
                })
            initial_amt = data.get('part_payment_initial_amount') if isinstance(data, dict) else None
            if not conversion_product and initial_amt is None and not (instance and getattr(instance, 'part_payment_initial_amount', None) is not None):
                raise serializers.ValidationError({
                    "part_payment_conversion_product|part_payment_initial_amount": "Either a conversion product or an initial fixed amount is required when part payment is enabled."
                })
            if instance and conversion_product and str(conversion_product.id) == str(instance.id):
                raise serializers.ValidationError({
                    "part_payment_conversion_product": "Conversion product cannot be the same as this product."
                })

        product_type = data.get('product_type') or (self.instance.product_type if self.instance else '')
        category = data.get('category') or (self.instance.category if self.instance else '')

        if product_type == 'TWM_COINS':
            if category != 'VOUCHER':
                raise serializers.ValidationError({"product_type": "TWM_COINS type is only valid for Voucher category products."})
            if data.get('twm_coin_amount') is None and not (self.instance and self.instance.twm_coin_amount is not None):
                raise serializers.ValidationError({"twm_coin_amount": "Coin amount is required for TWM_COINS products."})
            if 'twm_coin_amount' in data and data['twm_coin_amount'] is not None and data['twm_coin_amount'] <= 0:
                raise serializers.ValidationError({"twm_coin_amount": "Coin amount must be greater than 0."})

        return data
