from rest_framework import serializers
from api.producers_api.orders.models import Order, OrderItem, OrderPayment, ShippingAddress, Coupon, ShippingMethod
from api.producers_api.accounts.models import User, UserAddress
from producers_products_variants.models.products_vairants import ProductsVariants
from producers_products_variants.serializers.products_variants_serializer import ProductsVariantsSerializer
from api.producers_api.accounts.serializers.user_address import UserAddressSerializer
from django.db import transaction

class OrderItemSerializer(serializers.ModelSerializer):
    product_variant = serializers.PrimaryKeyRelatedField(queryset=ProductsVariants.objects.all())

    class Meta:
        model = OrderItem
        fields = ['product_variant', 'quantity', 'price_each', 'subtotal']
        read_only_fields = ['subtotal']

class OrderPaymentSerializer(serializers.ModelSerializer):
    class Meta:
        model = OrderPayment
        fields = ['payment_method', 'status', 'total_amount', 'paid_at']

class ShippingAddressSerializer(serializers.ModelSerializer):
    class Meta:
        model = ShippingAddress
        fields = [
            'recipient_name', 'company_name', 'appartment_number',
            'street_address', 'city', 'state', 'postal_code',
            'country', 'phone_number', 'email', 'is_check_save_info_faster_checkout'
        ]

class OrderSerializer(serializers.ModelSerializer):
    items = OrderItemSerializer(many=True)
    payments = OrderPaymentSerializer()
    shipping_address = ShippingAddressSerializer()
    customer = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
    coupon = serializers.SlugRelatedField(slug_field='code', queryset=Coupon.objects.all(), allow_null=True, required=False)
    shipping_method = serializers.SlugRelatedField(slug_field='name', queryset=ShippingMethod.objects.all(), allow_null=True, required=False)

    class Meta:
        model = Order
        fields = [
            'id', 'customer', 'status', 'coupon', 'total_price',
            'discount_amount', 'final_total', 'shipping_method',
            'shipping_cost', 'tracking_number', 'items', 'payments', 'shipping_address'
        ]
        read_only_fields = ['id', 'discount_amount', 'final_total', 'tracking_number','customer','total_price', 'shipping_cost']

    def create(self, validated_data):
        request = self.context.get('request')
        if request and hasattr(request, 'user'):
            customer = request.user
        else:
            raise serializers.ValidationError("Authentication required to create order.")
        items_data = validated_data.pop('items')
        payments_data = validated_data.pop('payments')
        shipping_address_data = validated_data.pop('shipping_address')

        # Check product variant quantities before creating the order
        for item_data in items_data:
            product_variant_id = item_data.get('product_variant').id if isinstance(item_data.get('product_variant'), ProductsVariants) else item_data.get('product_variant')
            quantity_ordered = item_data.get('quantity')

            try:
                product_variant = ProductsVariants.objects.get(id=product_variant_id)
            except ProductsVariants.DoesNotExist:
                raise serializers.ValidationError(f"Product variant with ID {product_variant_id} does not exist.")

            if product_variant.quantity < quantity_ordered:
                raise serializers.ValidationError(f"Not enough stock for product variant {product_variant.id}. Available: {product_variant.quantity}, Ordered: {quantity_ordered}")

        # Recalculate total_price based on order items
        calculated_total_price = sum(item_data['quantity'] * item_data['price_each'] for item_data in items_data)
        validated_data['total_price'] = calculated_total_price

        coupon = validated_data.get('coupon')
        shipping_method = validated_data.get('shipping_method')

        # Calculate shipping_cost based on the selected shipping method
        calculated_shipping_cost = shipping_method.cost if shipping_method else 0
        validated_data['shipping_cost'] = calculated_shipping_cost

        discount_amount = 0
        if coupon:
            if coupon.discount_type == Coupon.PERCENTAGE:
                discount_amount = calculated_total_price * (coupon.discount_value / 100)
            elif coupon.discount_type == Coupon.FIXED:
                discount_amount = coupon.discount_value

        final_total = calculated_total_price + calculated_shipping_cost - discount_amount

        validated_data['discount_amount'] = discount_amount
        validated_data['final_total'] = final_total

        with transaction.atomic():
            #order = Order.objects.create(**validated_data)
            order = Order.objects.create(
                customer=customer,
                coupon=validated_data.get('coupon'),
                total_price=validated_data.get('total_price'),
                discount_amount=validated_data.get('discount_amount'),
                final_total=validated_data.get('final_total'),
                shipping_method=validated_data.get('shipping_method'),
                shipping_cost=validated_data.get('shipping_cost'),
                tracking_number=validated_data.get('tracking_number')
            )
            for item_data in items_data:
                # Use price_each from item_data as per current model design
                quantity = item_data.get('quantity')
                price_each = item_data.get('price_each')
                subtotal = quantity * price_each # Subtotal is calculated on backend

                # Ensure product_variant is an instance before creating OrderItem
                product_variant_id_for_creation = item_data.get('product_variant').id if isinstance(item_data.get('product_variant'), ProductsVariants) else item_data.get('product_variant')
                product_variant_instance = ProductsVariants.objects.get(id=product_variant_id_for_creation)

                OrderItem.objects.create(
                    order=order,
                    product_variant=product_variant_instance,
                    quantity=quantity,
                    price_each=price_each,
                    subtotal=subtotal
                )

                # Subtract ordered quantity from product variant stock
                product_variant_id_for_creation = item_data.get('product_variant').id if isinstance(item_data.get('product_variant'), ProductsVariants) else item_data.get('product_variant')
                product_variant = ProductsVariants.objects.get(id=product_variant_id_for_creation)
                product_variant.quantity -= quantity
                product_variant.save()

            OrderPayment.objects.create(order=order, **payments_data)
            shipping_address_instance = ShippingAddress.objects.create(order=order, **shipping_address_data)

            if shipping_address_data.get('is_check_save_info_faster_checkout'):
                user = validated_data.get('customer')
                user_address_data = {
                    'company_name': shipping_address_data.get('company_name'),
                    'street_address': shipping_address_data.get('street_address'),
                    'appartment_number': shipping_address_data.get('appartment_number'),
                    'city': shipping_address_data.get('city'),
                    'state': shipping_address_data.get('state'),
                    'postal_code': shipping_address_data.get('postal_code'),
                    'country': shipping_address_data.get('country'),
                    'phone_number': shipping_address_data.get('phone_number'),
                    'email': shipping_address_data.get('email'),
                }
                
                # Update or create UserAddress for the customer
                UserAddress.objects.update_or_create(
                    user=user,
                    defaults=user_address_data
                )

        return order

    def update(self, instance, validated_data):
        items_data = validated_data.pop('items', [])
        payments_data = validated_data.pop('payments', None)
        shipping_address_data = validated_data.pop('shipping_address', None)

        # Update simple fields
        instance.status = validated_data.get('status', instance.status)
        instance.tracking_number = validated_data.get('tracking_number', instance.tracking_number)
        
        # Recalculate total_price and shipping_cost based on backend data
        # First, handle OrderItems updates to get the latest item prices/quantities
        current_order_items = {item.product_variant.id: item for item in instance.items.all()}
        updated_items_for_total_calc = []
        for item_data in items_data:
            product_variant_id = item_data.get('product_variant').id if isinstance(item_data.get('product_variant'), ProductsVariants) else item_data.get('product_variant')
            quantity_ordered = item_data.get('quantity')
            price_each = item_data.get('price_each') # Still relying on frontend price_each as per model design

            if product_variant_id in current_order_items:
                # Update existing item for calculation
                order_item = current_order_items[product_variant_id]
                order_item.quantity = quantity_ordered
                order_item.price_each = price_each
                updated_items_for_total_calc.append(order_item)
            else:
                # New item for calculation
                updated_items_for_total_calc.append({'quantity': quantity_ordered, 'price_each': price_each})

        # Calculate total_price based on updated/new items
        instance.total_price = sum(item.quantity * item.price_each if isinstance(item, OrderItem) else item['quantity'] * item['price_each'] for item in updated_items_for_total_calc)

        # Calculate shipping_cost based on the selected shipping method
        if 'shipping_method' in validated_data:
            instance.shipping_method = validated_data['shipping_method']
        instance.shipping_cost = instance.shipping_method.cost if instance.shipping_method else 0

        # Handle coupon and shipping method updates
        # The SlugRelatedField already handles the lookup and validation.
        if 'coupon' in validated_data:
            instance.coupon = validated_data['coupon']
        
        if 'shipping_method' in validated_data:
            instance.shipping_method = validated_data['shipping_method']

        # Recalculate discount and final total using the backend-derived total_price and shipping_cost
        discount_amount = 0
        if instance.coupon:
            if instance.coupon.discount_type == Coupon.PERCENTAGE:
                discount_amount = instance.total_price * (instance.coupon.discount_value / 100)
            elif instance.coupon.discount_type == Coupon.FIXED:
                discount_amount = instance.coupon.discount_value
        instance.discount_amount = discount_amount
        instance.final_total = instance.total_price + instance.shipping_cost - discount_amount

        instance.save()

        # Update or create nested ShippingAddress
        if shipping_address_data:
            shipping_address_instance, created = ShippingAddress.objects.update_or_create(
                order=instance,
                defaults=shipping_address_data
            )
            if shipping_address_data.get('is_check_save_info_faster_checkout'):
                user = instance.customer
                user_address_data = {
                    'company_name': shipping_address_data.get('company_name'),
                    'street_address': shipping_address_data.get('street_address'),
                    'appartment_number': shipping_address_data.get('appartment_number'),
                    'city': shipping_address_data.get('city'),
                    'state': shipping_address_data.get('state'),
                    'postal_code': shipping_address_data.get('postal_code'),
                    'country': shipping_address_data.get('country'),
                    'phone_number': shipping_address_data.get('phone_number'),
                    'email': shipping_address_data.get('email'),
                }
                UserAddress.objects.update_or_create(
                    user=user,
                    defaults=user_address_data
                )

        # Update or create nested OrderPayment
        if payments_data:
            OrderPayment.objects.update_or_create(
                order=instance,
                defaults=payments_data
            )

        # Handle OrderItems updates
        current_order_items = {item.product_variant.id: item for item in instance.items.all()}
        for item_data in items_data:
            product_variant_id = item_data.get('product_variant').id if isinstance(item_data.get('product_variant'), ProductsVariants) else item_data.get('product_variant')
            quantity_ordered = item_data.get('quantity')
            price_each = item_data.get('price_each')

            try:
                product_variant = ProductsVariants.objects.get(id=product_variant_id)
            except ProductsVariants.DoesNotExist:
                raise serializers.ValidationError(f"Product variant with ID {product_variant_id} does not exist.")

            if product_variant_id in current_order_items:
                # Update existing item
                order_item = current_order_items[product_variant_id]
                old_quantity = order_item.quantity
                
                if product_variant.quantity + old_quantity < quantity_ordered:
                    raise serializers.ValidationError(f"Not enough stock for product variant {product_variant.id}. Available: {product_variant.quantity + old_quantity}, Ordered: {quantity_ordered}")
                
                product_variant.quantity += (old_quantity - quantity_ordered) # Adjust stock
                order_item.quantity = quantity_ordered
                order_item.price_each = price_each
                order_item.subtotal = quantity_ordered * price_each
                order_item.save()
                product_variant.save()
                del current_order_items[product_variant_id] # Mark as processed
            else:
                # Create new item
                if product_variant.quantity < quantity_ordered:
                    raise serializers.ValidationError(f"Not enough stock for product variant {product_variant.id}. Available: {product_variant.quantity}, Ordered: {quantity_ordered}")
                
                OrderItem.objects.create(
                    order=instance,
                    product_variant=product_variant,
                    quantity=quantity_ordered,
                    price_each=price_each,
                    subtotal=quantity_ordered * price_each
                )
                product_variant.quantity -= quantity_ordered
                product_variant.save()

        # Remove items not in the updated list
        for product_variant_id, order_item in current_order_items.items():
            product_variant = ProductsVariants.objects.get(id=product_variant_id)
            product_variant.quantity += order_item.quantity # Return stock
            product_variant.save()
            order_item.delete()

        return instance
