from decimal import Decimal

from django.db import transaction
from rest_framework import serializers

from . import models


class ProductCategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = models.ProductCategory
        fields = (
            "id",
            "name",
            "slug",
            "description",
            "display_order",
            "is_active",
        )


class ProductSerializer(serializers.ModelSerializer):
    category = ProductCategorySerializer(read_only=True)
    category_id = serializers.PrimaryKeyRelatedField(
        source="category",
        queryset=models.ProductCategory.objects.all(),
        required=False,
        allow_null=True,
        write_only=True,
    )

    class Meta:
        model = models.Product
        fields = (
            "id",
            "name",
            "slug",
            "short_description",
            "description",
            "ingredients",
            "allergens",
            "price",
            "inventory_quantity",
            "max_per_order",
            "is_active",
            "is_featured",
            "hero_image",
            "category",
            "category_id",
        )


class DeliveryZoneSerializer(serializers.ModelSerializer):
    is_active = serializers.BooleanField(required=False)

    class Meta:
        model = models.DeliveryZone
        fields = ("id", "label", "postal_code", "is_active")


class DeliveryOverrideCodeSerializer(serializers.ModelSerializer):
    can_use = serializers.SerializerMethodField()

    class Meta:
        model = models.DeliveryOverrideCode
        fields = (
            "id",
            "code",
            "label",
            "message_to_customer",
            "max_uses",
            "usage_count",
            "is_active",
            "can_use",
        )
        read_only_fields = ("usage_count", "can_use")

    def get_can_use(self, obj: models.DeliveryOverrideCode) -> bool:
        return obj.can_use()


class OrderItemSerializer(serializers.ModelSerializer):
    line_subtotal = serializers.DecimalField(
        max_digits=8, decimal_places=2, read_only=True
    )

    class Meta:
        model = models.OrderItem
        fields = (
            "id",
            "product",
            "product_name",
            "product_slug",
            "unit_price",
            "quantity",
            "line_subtotal",
        )
        read_only_fields = ("product_name", "product_slug", "unit_price", "line_subtotal")


class OrderSerializer(serializers.ModelSerializer):
    items = OrderItemSerializer(many=True)
    subtotal_amount = serializers.DecimalField(
        max_digits=8, decimal_places=2, read_only=True
    )
    tax_amount = serializers.DecimalField(max_digits=8, decimal_places=2, read_only=True)
    delivery_fee_amount = serializers.DecimalField(
        max_digits=8, decimal_places=2, read_only=True
    )
    discount_amount = serializers.DecimalField(
        max_digits=8, decimal_places=2, read_only=True
    )
    total_amount = serializers.DecimalField(max_digits=8, decimal_places=2, read_only=True)

    class Meta:
        model = models.Order
        fields = (
            "id",
            "customer_name",
            "customer_email",
            "customer_phone",
            "fulfillment_method",
            "status",
            "scheduled_date",
            "scheduled_time_slot",
            "delivery_address_line1",
            "delivery_address_line2",
            "delivery_city",
            "delivery_state",
            "delivery_postal_code",
            "delivery_override_code",
            "subtotal_amount",
            "tax_amount",
            "delivery_fee_amount",
            "discount_amount",
            "total_amount",
            "notes",
            "items",
            "created_at",
            "updated_at",
        )
        read_only_fields = ("status", "created_at", "updated_at")

    def create(self, validated_data):
        items_data = validated_data.pop("items", [])
        delivery_fee_amount = Decimal(validated_data.pop("delivery_fee_amount", Decimal("0")))
        discount_amount = Decimal(validated_data.pop("discount_amount", Decimal("0")))
        tax_amount = Decimal(validated_data.pop("tax_amount", Decimal("0")))

        if not items_data:
            raise serializers.ValidationError("Order requires at least one item.")

        with transaction.atomic():
            subtotal = Decimal("0")
            order_items = []

            for item_data in items_data:
                product = item_data.get("product")
                if product is None:
                    raise serializers.ValidationError("Each order item must reference a product.")

                quantity = item_data.get("quantity", 1)
                if quantity > product.inventory_quantity:
                    raise serializers.ValidationError(
                        f"Insufficient inventory for {product.name}. Requested {quantity}, "
                        f"available {product.inventory_quantity}."
                    )

                line_subtotal = product.price * quantity
                subtotal += line_subtotal

                order_items.append(
                    {
                        "product": product,
                        "product_name": product.name,
                        "product_slug": product.slug,
                        "unit_price": product.price,
                        "quantity": quantity,
                        "line_subtotal": line_subtotal,
                    }
                )

                product.inventory_quantity -= quantity
                product.save(update_fields=["inventory_quantity"])

            total_amount = subtotal + tax_amount + delivery_fee_amount - discount_amount

            order = models.Order.objects.create(
                subtotal_amount=subtotal,
                tax_amount=tax_amount,
                delivery_fee_amount=delivery_fee_amount,
                discount_amount=discount_amount,
                total_amount=total_amount,
                **validated_data,
            )

            models.OrderItem.objects.bulk_create(
                [models.OrderItem(order=order, **item) for item in order_items]
            )

            return order


class OrderAdminSerializer(serializers.ModelSerializer):
    items = OrderItemSerializer(many=True, read_only=True)
    subtotal_amount = serializers.DecimalField(
        max_digits=8, decimal_places=2, read_only=True
    )
    tax_amount = serializers.DecimalField(max_digits=8, decimal_places=2, read_only=True)
    delivery_fee_amount = serializers.DecimalField(
        max_digits=8, decimal_places=2, read_only=True
    )
    discount_amount = serializers.DecimalField(
        max_digits=8, decimal_places=2, read_only=True
    )
    total_amount = serializers.DecimalField(max_digits=8, decimal_places=2, read_only=True)

    class Meta:
        model = models.Order
        fields = (
            "id",
            "customer_name",
            "customer_email",
            "customer_phone",
            "fulfillment_method",
            "status",
            "scheduled_date",
            "scheduled_time_slot",
            "delivery_address_line1",
            "delivery_address_line2",
            "delivery_city",
            "delivery_state",
            "delivery_postal_code",
            "delivery_override_code",
            "subtotal_amount",
            "tax_amount",
            "delivery_fee_amount",
            "discount_amount",
            "total_amount",
            "notes",
            "items",
            "created_at",
            "updated_at",
        )
        read_only_fields = (
            "subtotal_amount",
            "tax_amount",
            "delivery_fee_amount",
            "discount_amount",
            "total_amount",
            "created_at",
            "updated_at",
        )
