import hashlib
import time
import traceback
from urllib.parse import urlencode
import uuid
import requests
import logging

from adminportal.tasks import send_whatsapp_message ,check_and_verify_order_status, send_whatsapp_order_message
from adminportal.views import EmailSend, NotificationInit
from orders.delhivery import calculate_cart_weight, get_delhivery_charge, get_delivery_info, get_expected_delivery_time, get_full_address_from_latlng, get_pincode_from_latlng
from django.utils.timezone import localtime
from user_agents import parse
import json
from decimal import ROUND_HALF_UP, Decimal
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.shortcuts import get_object_or_404, redirect, render
from shops.models import ProductionUnit, Shop
from orders.signals.custom_signals import order_confirmed
from products.models import CustomProduct, ProductImage, Products, Wishlist,SalesUnitProductSelection, CustomProductImage
from .models import (
    AdditionalDetails,
    BillEdited,
    Cart,
    CartItem,
    SKU,
    CartItemCustomization,
    CustomCouponSettings,
    CustomOrderTracking,
    Delhivery,
    DeliveryBoys,
    DeliveryMatrix,
    DeliveryOTP,
    DeliverySlot,
    Discount,
    OrderProductCustomization,

    Orders,
    Dropaddress,
    OrderProducts,
    Coupons,
    CustomCoupon,
    Payment,
    Ads,
OrderDelivery,
NotificationStat,
    PaymentModes,
SomeOneElse,
DeliverySettings,
DeliveryDiscount
)
from accounts.models import UserLocation, Address, Referral, Users
from datetime import datetime, timedelta
from django.utils import timezone
from django.db import transaction
from .serializers import CustomOrderCreateSerializer, OrderSerializer, PastOrderListSerializer, AdSerializer,OrderSerializer2, CourierDetailsSerializer, CustomOrderSerializer,OrderBillDetailsSerializer
from products.serializers import CustomProductSerializer
import random, string, googlemaps
import razorpay
from django.conf import settings
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.db.models import Q
from django.http import FileResponse, JsonResponse
import os


from bill_writer.BillWriter import template_writer





from decimal import Decimal
from . import billdesk_utils






# @csrf_exempt
# def check_pincode(request):
#     pincode = request.GET.get('pincode')
    
#     if not pincode:
#         return JsonResponse({'error': 'Pincode required'}, status=400)
    
#     url = f"https://staging-express.delhivery.com/c/api/pin-codes/json/?filter_codes={pincode}"
#     headers = {"Authorization": "Token xxxxxxxxxxxxxxxx"}
    
#     try:
#         response = requests.get(url, headers=headers)
#         data = response.json()
        
#         # Check if serviceable
#         if isinstance(data, list) and len(data) > 0:
#             remark = data[0].get("remark", "")
#             serviceable = remark != "Embargo"
#         else:
#             serviceable = False
        
#         return JsonResponse({
#             'pincode': pincode,
#             'serviceable': serviceable
#         })
        
#     except:
#         return JsonResponse({
#             'pincode': pincode,
#             'serviceable': False
#         })



    



class CartViewMixin:

    # def calculate_dynamic_delivery_fee(self, subtotal, distance_km=0):
    #     settings = DeliverySettings.objects.first()
    #     if not settings:
    #         return Decimal('0.0') 

    #     base_fee = settings.base_fee
    #     base_km = settings.base_km
    #     per_km_fee = settings.per_km_fee

    #     distance_km = Decimal(str(distance_km))  
    #     subtotal = Decimal(str(subtotal))      

    #     if distance_km > base_km:
    #         extra_km = distance_km - base_km
    #         delivery_fee = base_fee + (per_km_fee * extra_km)
    #     else:
    #         delivery_fee = base_fee

    #     # Apply discount on delivery fee based on order value
    #     discounts = DeliveryDiscount.objects.order_by('-min_order_value')
    #     for discount in discounts:
    #         if subtotal >= discount.min_order_value:
    #             discount_percent = Decimal(discount.discount_percent) / Decimal('100.0')
    #             discount_amount = discount_percent * delivery_fee
    #             delivery_fee -= discount_amount
    #             break

    #     return round(delivery_fee, 2)

    def calculate_dynamic_delivery_fee(self, subtotal, distance_km=0):
        settings = DeliverySettings.objects.first()
        if not settings:
            return Decimal('0.0'), "Delivery settings not configured."

        # Convert to Decimal
        distance_km = Decimal(str(distance_km))
        subtotal = Decimal(str(subtotal))

        # Free delivery check
        if (
            settings.free_delivery_max_distance > Decimal('0.0')
            and settings.free_delivery_min_order_value > Decimal('0.0')
            and distance_km <= settings.free_delivery_max_distance
        ):
            if subtotal >= settings.free_delivery_min_order_value:
                return Decimal('0.0'), "Free delivery applied!"
            else:
                remaining = settings.free_delivery_min_order_value - subtotal
                remaining = remaining.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
                return settings.base_fee, f"Add ₹{remaining} more to get free delivery."

        # Standard delivery fee calculation
        base_fee = settings.base_fee
        base_km = settings.base_km
        per_km_fee = settings.per_km_fee

        if distance_km > base_km:
            extra_km = distance_km - base_km
            delivery_fee = base_fee + (per_km_fee * extra_km)
        else:
            delivery_fee = base_fee

        # Apply discount on delivery fee based on order value
        discounts = DeliveryDiscount.objects.order_by('-min_order_value')
        message = ""
        applied_discount = None

        for discount in discounts:
            if subtotal >= discount.min_order_value:
                discount_percent = Decimal(discount.discount_percent) / Decimal('100.0')
                discount_amount = discount_percent * delivery_fee
                delivery_fee -= discount_amount
                applied_discount = discount
                break
        next_discounts = [d for d in discounts if subtotal < d.min_order_value]

        if next_discounts:
            next_discount = next_discounts[-1]  # smallest min_order_value greater than subtotal
            remaining = next_discount.min_order_value - subtotal
            remaining = remaining.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
            message = f"Add ₹{remaining} more to get {next_discount.discount_percent}% off on delivery."
        else:
            # If no higher discount exists, apply the highest discount
            applied_discount = discounts.first()  # The highest discount available
            if applied_discount:
                message = f"{applied_discount.discount_percent}% discount applied on delivery."
            else:
                message = "No delivery discount available."
        return round(delivery_fee, 2), message

    def order_for_someone_else_details(self, cart):
        some_one_details = SomeOneElse.objects.filter(cart = cart).first()
        if some_one_details:
            return Response(
            {
                "status": 1,
                "name": some_one_details.name if some_one_details.name else "",
                "phone_number": some_one_details.phone_number if some_one_details.phone_number else "",
            },
            status=status.HTTP_200_OK,
        )
        else:
            return Response(
                {"status": 0,
                 "name": "",
                  "phone_number": ""
                 },
                status = status.HTTP_404_NOT_FOUND
            )


    def get_cart_items_response(self, cart, message):
        """Helper method to format cart items into a response."""
        cart_items = cart.items.all()
        grouped_items = {}
        subtotal_sum = 0
        gst_charges_sum = 0
        total_savings = 0
        delivery_fee = 0

        for item in cart_items:
            sku = item.sku
            product = sku.product
            sku_id = sku.id

            if sku_id not in grouped_items:
                grouped_items[sku_id] = {
                    "sku_id": sku.id,
                    "same_day_delivery": sku.same_day_delivery,
                    "sku_name": sku.sku_name,
                    "sku_code": sku.sku_code,
                    "sku_unit": sku.sku_unit,
                    "sku_quantity": sku.sku_quantity,
                    "product_name": product.item_name,
                    "product_image": product.images.first().image.url if product.images.exists() else None,
                    "customization_available": sku.customization_available,
                    "customization_items": [],
                    "sku_price": sku.sku_mrp,
                    "offer_price": None,
                    "offer": "0%",
                    "cart_item_id": item.id,
                    "quantity": 0
                }

            # Calculate applicable discount
            applicable_discount = None
            discounts = Discount.objects.filter(
                Q(DiscountOn="Category", ApplicableCategory__in=[product.item_category]) |
                Q(DiscountOn="SubCategory", ApplicableSubCategory__in=[product.item_sub_category]) |
                Q(DiscountOn="Product", ApplicableProduct__in=[product]) |
                Q(DiscountOn="Sku", ApplicableSku__in=[sku])
            )

            for discount in discounts:
                if discount.DiscountOn == 'Category' and product.item_category in discount.ApplicableCategory.all():
                    applicable_discount = discount
                    break
                elif discount.DiscountOn == 'SubCategory' and product.item_sub_category in discount.ApplicableSubCategory.all():
                    applicable_discount = discount
                    break
                elif discount.DiscountOn == 'Product' and product in discount.ApplicableProduct.all():
                    applicable_discount = discount
                    break
                elif discount.DiscountOn == 'Sku' and sku in discount.ApplicableSku.all():
                    applicable_discount = discount
                    break

            # Price Calculation (offer price is based on discount)
            sku_mrp = sku.sku_mrp
            if applicable_discount:
                discount_percentage = applicable_discount.DiscountPercentage
                offer_price = round(float(sku_mrp) * (1 - float(discount_percentage) / 100), 2)  # type: ignore
                offer = f"{discount_percentage}%"
            else:
                offer_price = sku_mrp
                offer = "0%"

            # GST Calculation (GST on the original price, not on the offer price)
            gst_values = {
                "s_gst": product.s_gst or 0,
                "c_gst": product.c_gst or 0,
                "cess": product.cess or 0,
            }
            gst_amount = 0
            for gst_type, gst_percent in gst_values.items():
                gst_amount += round(float(offer_price) * (float(gst_percent) / 100), 2)

            # Calculate Item Data
            grouped_items[sku_id]["offer_price"] = offer_price
            grouped_items[sku_id]["offer"] = offer
            grouped_items[sku_id]["quantity"] += item.quantity
            subtotal_sum += round(float(sku_mrp) * item.quantity, 2)
            gst_charges_sum += float(gst_amount) * item.quantity
            total_savings += round((float(sku_mrp) - float(offer_price)) * item.quantity, 2)

            # Add customization details if applicable
            if sku.customization_available:
                for customization in item.customizations.all():
                    grouped_items[sku_id]["customization_items"].append({
                        "cart_item_id": item.id,
                        "custom_id": customization.id,
                        "custom_note": customization.custom_note,
                        "custom_image": customization.custom_image.url if customization.custom_image else None,
                        "custom_image_id": customization.custom_image_id,
                        "has_customization": customization.has_customization()
                    })

        items_data = list(grouped_items.values())

        # Apply coupon savings if coupon is applied
        coupon_savings = 0
        if cart.coupon:
            if isinstance(cart.coupon, Coupons):
                coupon_obj = Coupons.objects.filter(CouponCode=cart.coupon.CouponCode).first()
                if coupon_obj:
                    coupon_savings = self.calculate_coupon_savings(coupon_obj, subtotal_sum, cart.user)
        elif cart.custom_coupon:
            coupon_code = cart.custom_coupon
            coupon_savings = self.calculate_coupon_savings(coupon_code, subtotal_sum, cart.user)
        else:
            coupon_savings = 0.00

        # delivery_fee, delivery_discount_message = self.calculate_dynamic_delivery_fee(subtotal_sum, distance_km=5)
        # grand_total = round(float(subtotal_sum) + float(gst_charges_sum) - float(total_savings) - float(coupon_savings) + float(delivery_fee), 2)
        distance_km =0 
        delivery_fee_cod_express = 0
        delivery_fee_cod_surface = 0
        delivery_fee_online_express=0
        delivery_fee_online_surface=0
        expected_delivery = {}
        user_location = UserLocation.objects.filter(user=cart.user).order_by('-created_at').first()
        if not user_location:
            return Response(
                {"status": 0, "message": "User location not found."},
                status=400
            )
        shop_uuid = user_location.shop
        long_distance = False
        cart_weight = 0
        if not shop_uuid and cart.user:
            long_distance = True
            pickup_pincode = ProductionUnit.objects.values_list("pin_code", flat=True).first()
            cart_weight = calculate_cart_weight(cart)
            address_pin_code = get_pincode_from_latlng(user_location.latitude, user_location.longitude)
            
            delivery_fee_online_express = get_delhivery_charge(pickup_pincode, address_pin_code ,cart_weight,"Pre-paid","E")
            # delivery_fee_online_nxt = get_delhivery_charge(pickup_pincode, address_pin_code ,cart_weight,"Pre-paid","N")
            delivery_fee_online_surface = get_delhivery_charge(pickup_pincode, address_pin_code ,cart_weight,"Pre-paid","S")

            delivery_fee_cod_express = get_delhivery_charge(pickup_pincode, address_pin_code ,cart_weight,"COD","E")
            # delivery_fee_cod_nxt = get_delhivery_charge(pickup_pincode, address_pin_code ,cart_weight,"COD","N")
            delivery_fee_cod_surface = get_delhivery_charge(pickup_pincode, address_pin_code ,cart_weight,"COD","S")
            delivery_discount_message= ""
            expected_delivery = get_delivery_info(address_pin_code)
        else:
            if cart.user:
                user_location = UserLocation.objects.filter(user=cart.user).order_by('-created_at').first()
                if user_location and user_location.distance is not None:
                    distance_km = user_location.distance
            delivery_fee, delivery_discount_message  = self.calculate_dynamic_delivery_fee(subtotal_sum, distance_km = distance_km)
        subtotal = float(subtotal_sum)
        gst = float(gst_charges_sum)
        savings = float(total_savings) + float(coupon_savings)

        if long_distance:
            delivery_fee = float(delivery_fee_online_surface)
        else:
            delivery_fee = float(delivery_fee)
        grand_total = round(subtotal + gst - savings + delivery_fee, 2)
        savings = float(total_savings) + float(coupon_savings)
        total_without_delivery = subtotal + gst - savings
        price_data = {
            "subtotal": round(subtotal_sum, 2),
            "taxes_and_charges": round(gst_charges_sum, 2),
            "delivery_fee": round(delivery_fee, 2),
            "discount": round(total_savings, 2),
            "total_savings": round(total_savings + coupon_savings, 2),
            "coupon_savings": round(coupon_savings, 2),
            "grand_total": grand_total,
            "coupon_code": cart.coupon.CouponCode if cart.coupon else cart.custom_coupon,
            'total_without_delivery': round(total_without_delivery, 2),
        }
        long_distance_charges={
            "delivery_fee_online_express": delivery_fee_online_express,
            # "delivery_fee_online_nxt": delivery_fee_online_nxt,
            "delivery_fee_online_surface": delivery_fee_online_surface,
            "delivery_fee_cod_express": delivery_fee_cod_express,
            # "delivery_fee_cod_nxt": delivery_fee_cod_nxt,
            "delivery_fee_cod_surface": delivery_fee_cod_surface,
            "expected_tat_surface": expected_delivery.get("tat_surface"),
            "expected_tat_express": expected_delivery.get("tat_express"),
            "cart_weight": cart_weight,
        }
        some_one_details = SomeOneElse.objects.filter(cart = cart).first()
        if some_one_details:
            some_one_order = {
                "name": some_one_details.name if some_one_details.name else "",
                "phone_number": some_one_details.phone_number if some_one_details.phone_number else "",
            }
        else:
            some_one_order = {}
        payment_modes = PaymentModes.objects.filter(status=True).values('mode_name','id')
        return Response(
            {
                "status": 1,
                "message": message,
                "data": items_data,
                "price_data": price_data,
                "some_one_else_order": some_one_order,
                "delivery_discount_message":delivery_discount_message,
                "available_payment_modes": list(payment_modes),
                "long_distance_charges":long_distance_charges,
                "long_distance": long_distance,

                
            },
            status=status.HTTP_200_OK,
        )

    def calculate_coupon_savings(self, coupon, subtotal, user):

        savings = 0.0  

        try:
            if isinstance(coupon, Coupons):
                if coupon.CouponType == "percentage":
                    savings = (coupon.DiscountPercentage or 0) / 100 * subtotal
                    if coupon.MaxDiscountAmountForPercentage:
                        savings = min(savings, coupon.MaxDiscountAmountForPercentage or 0)
                elif coupon.CouponType == "amount":
                    savings = coupon.DiscountAmount or 0.0

            elif isinstance(coupon, str):
                referral = Referral.objects.filter(referral_code=coupon).first()
                if referral and referral.user != user:
                    has_previous_orders = Orders.objects.filter(user_uuid=user).exists()
                    if not has_previous_orders:
                        savings = 100.0
                else:
                    custom_coupon = CustomCoupon.objects.filter(coupon_code=coupon).first()
                    if custom_coupon and custom_coupon.user == user:
                        if custom_coupon.coupon.discount_amount:
                            savings = custom_coupon.coupon.discount_amount
                        else:
                            savings = 0.0
        except Exception as e:
            logging.error(e)
            pass  

        try:
            return round(float(savings), 2)
        except (TypeError, ValueError):
            return 0.0



class AddOrUpdateCartView(CartViewMixin, APIView):
    def post(self, request):
        # sku_data = request.data.get("skus")
        sku_data_raw = request.data.get("skus")
        try:
            sku_data = json.loads(sku_data_raw) if isinstance(sku_data_raw, str) else sku_data_raw
        except json.JSONDecodeError:
            return Response(
                {"status": 0, "message": "Invalid JSON format for 'skus' field."},
                status=status.HTTP_400_BAD_REQUEST
            )

        coupon_code = request.data.get("coupon_code")  # Get the coupon code from the request
        remove_coupon = request.data.get("remove_coupon", False)
        if not sku_data and not coupon_code and not remove_coupon:
            return Response(
                {"status": 0, "message": "SKU data or coupon code must be provided."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        if request.user.is_authenticated:
            user = request.user
            anonymous_id = None
            location = UserLocation.objects.get(user=user)
            
        else:
            anonymous_id = request.data.get("anonymous_id")
            user = None  # No authenticated user, we're using 
            location = UserLocation.objects.get(anonymous_id=anonymous_id)
        # if not location.shop:
        #     location_message = "We don't deliver to this location yet. Please choose a nearby outlet."  
        #     return Response(
        #         {"status": 0, "location_message": location_message},
        #     )

        # Get or create the cart for the user or anonymous ID
        cart, created = Cart.objects.get_or_create(
            user=user if user else None, anonymous_id=anonymous_id if not user else None
        )
        
        # If a coupon is provided, try to find and apply it
        if coupon_code:
            # First try to match with an actual coupon
            coupon = Coupons.objects.filter(CouponCode=coupon_code, validity_end_date__gte=timezone.now()).first()
            if coupon:
                cart.coupon = coupon  # type: ignore # ForeignKey relation
                cart.save()
                return self.get_cart_items_response(cart, "Coupon added successfully!")
            else:
                # Fallback to check if it's a valid referral code
                referral = Referral.objects.filter(referral_code=coupon_code).first()
                if referral:
                    if referral.user != user:
                        has_previous_orders = Orders.objects.filter(user_uuid=user).exists()
                        if not has_previous_orders:
                            cart.custom_coupon = coupon_code  # Save the referral code as string
                            cart.save()
                            return self.get_cart_items_response(cart, "Referral code applied successfully!")
                        else:
                            return Response(
                                {"status": 0, "message": "Referral code is only valid for first-time users."},
                                status=status.HTTP_400_BAD_REQUEST,
                            )
                    else:
                        return Response(
                            {"status": 0, "message": "You cannot use your own referral code."},
                            status=status.HTTP_400_BAD_REQUEST,
                        )
                else:
                    custom_coupon = CustomCoupon.objects.filter(coupon_code = coupon_code).first()
                    if custom_coupon:
                        if custom_coupon.user != user:
                            return Response(
                                {"status": 0, "message": "Coupon code is only valid for approved users."},
                                status=status.HTTP_400_BAD_REQUEST,
                            )
                        cart.custom_coupon = coupon_code
                        cart.save()
                        return self.get_cart_items_response(cart, "Coupon code applied successfully!")
                    return Response(
                        {"status": 0, "message": "Invalid or expired coupon/referral code."},
                        status=status.HTTP_400_BAD_REQUEST,
                    )
        if remove_coupon:
            cart.coupon = None
            cart.custom_coupon = ""
            cart.save()
            return self.get_cart_items_response(cart, "Coupon removed successfully!")
        

        # Add or update the cart items
        for sku_info in sku_data:
            sku_id = sku_info.get("sku")
            quantity = sku_info.get("quantity", 1)
            customization_data = sku_info.get("customisation", [])
            # custom_note = sku_info.get("custom_note", "").strip() or None
            # custom_image_id = sku_info.get("custom_image_id", "").strip() or None
            # custom_image = request.FILES.get(custom_image_id) if custom_image_id else None


            if not sku_id or quantity <= 0:
                return Response(
                    {
                        "status": 0,
                        "message": "SKU ID and quantity must be provided and greater than zero.",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            sku = get_object_or_404(SKU, id=sku_id)

            cart_item, _ = CartItem.objects.get_or_create(cart=cart, sku=sku)

            total_custom_entries = len(customization_data)
            cart_item.quantity = quantity  # Set explicitly
            cart_item.save()

            existing_custom_ids = []

            for custom in customization_data:
                custom_id = custom.get("custom_id")
                custom_note = custom.get("custom_note")
                custom_image_id = custom.get("custom_image_id")
                custom_image = request.FILES.get(custom_image_id) if custom_image_id else None

                # -----------------------------------------
                # CASE 1: Existing customization
                # -----------------------------------------
                if custom_id:
                    try:
                        customization = CartItemCustomization.objects.get(
                            id=custom_id, cart_item=cart_item
                        )

                        # ---- DELETE CASES ----
                        # If BOTH removed or ANY removed leaving nothing
                        if ((custom_note in ["", None]) and (custom_image_id in ["", None]) and not custom_image):
                            customization.delete()
                            continue

                        # ---- UPDATE CASES ----

                        # update note
                        customization.custom_note = custom_note

                        # update image id
                        customization.custom_image_id = custom_image_id

                        # A new uploaded image (replace existing)
                        if custom_image:
                            customization.custom_image = custom_image

                        # Image removed (custom_image_id = null)
                        if custom_image_id is None:
                            customization.custom_image = None

                        customization.save()
                        existing_custom_ids.append(customization.id)

                    except CartItemCustomization.DoesNotExist:
                        pass

                # -----------------------------------------
                # CASE 2: New customization
                # -----------------------------------------
                else:

                    # Ignore completely empty new data
                    if (custom_note in ["", None]) and not custom_image_id and not custom_image:
                        continue

                    new_custom = CartItemCustomization.objects.create(
                        cart_item=cart_item,
                        custom_note=custom_note,
                        custom_image_id=custom_image_id
                    )

                    if custom_image:
                        new_custom.custom_image = custom_image
                        new_custom.save()

                    existing_custom_ids.append(new_custom.id)


            # -----------------------------------------
            # CASE 3: Remove DB customizations not sent
            # -----------------------------------------
            CartItemCustomization.objects.filter(cart_item=cart_item).exclude(
                id__in=existing_custom_ids).delete()



            # Handle cart item (either create or update)
            # cart_item, created = CartItem.objects.get_or_create(cart=cart, sku=sku)
            # cart_item.quantity = quantity
            # cart_item.save()

        # Now, return the updated cart with the coupon details if applied
        return self.get_cart_items_response(cart, "Cart Updated Successfully!")



class RemoveFromCartView(CartViewMixin, APIView):
    def delete(self, request, cart_item_id):
        cart_item = get_object_or_404(CartItem, id=cart_item_id)
        cart = cart_item.cart

        # Delete the cart item
        cart_item.delete()

        some_one_else = SomeOneElse.objects.filter(cart=cart)
        if some_one_else:
            some_one_else.delete()

        if not cart.items.exists():  # type: ignore
            # Delete the cart if it's empty
            cart.delete()

            return Response(
                {
                    "status": 1,
                    "message": "Cart is now empty.",
                    "data": None,
                },
                status=status.HTTP_200_OK,
            )

        return self.get_cart_items_response(
            cart, "Item removed from cart successfully!"
        )
    
class FlushCartView(CartViewMixin, APIView):
    def post(self, request):
        if request.user.is_authenticated:
            cart = Cart.objects.filter(user=request.user).first()
        else:
            try:
                anonymous_id = request.data.get("anonymous_id")
                cart = Cart.objects.filter(anonymous_id=anonymous_id).first()
            except:
                cart = None
        
        if not cart:
            return Response(
                {"status": 1, "message": "No cart found for this user.", "data": None},
                status=status.HTTP_200_OK,
            )
        some_one_else = SomeOneElse.objects.filter(cart=cart)
        if some_one_else:
            some_one_else.delete()

        cart.items.all().delete()   # type: ignore

        if not cart.items.exists():  # type: ignore
            cart.delete()

        return Response(
            {"status": 1, "message": "Cart flushed successfully.", "data": None},
            status=status.HTTP_200_OK,
        )


class GetCartView(CartViewMixin, APIView):
    def post(self, request):
        if request.user.is_authenticated:

            cart = Cart.objects.filter(user=request.user).first()
        else:
            try:
                anonymous_id = request.data.get("anonymous_id")
                cart = Cart.objects.filter(anonymous_id=anonymous_id).first()
            except:
                cart = None
        if not cart:
            return Response(
                {"status": 1, "message": "No cart found for this user.", "data": None},
                status=status.HTTP_200_OK,
            )

        return self.get_cart_items_response(cart, "Cart retrieved successfully!")
    
def get_available_delivery_slots():
    """Retrieve active and available delivery slots."""
    return DeliverySlot.objects.filter(
        is_available=True,
        status="active",
    ).order_by("start_time")


class DeliverySlotSelectionView(APIView):
    def get(self, request):
        try:
            if not request.user.is_authenticated:
                return Response(
                    {
                        "status": 0,
                        "message": "User is not authenticated.",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            cart = Cart.objects.filter(user=request.user).first()

            if not cart:
                return Response(
                    {
                        "status": 0,
                        "message": "Cart not found.",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            cart_items = CartItem.objects.filter(cart=cart)

            if not cart_items.exists():
                return Response(
                    {
                        "status": 0,
                        "message": "Cart is empty. Please add items to cart before selecting delivery slot.",
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # ✅ Safe same-day check
            allow_same_day = all(
                getattr(item.sku, "same_day_delivery", False)
                for item in cart_items
            )
            same_day_message = None

            if not allow_same_day:
                same_day_message = (
                    "One or more products in your cart are not eligible for same-day delivery. "
                    "Your order will be delivered from tomorrow onwards."
                )

            # ✅ Pickup logic
            user_location = UserLocation.objects.filter(user=request.user).first()
            pickup_available = False
            shop_details = None

            if user_location and user_location.shop:
                pickup_available = True
                shop = user_location.shop
                shop_details = {
                    "shop": "Navya Bakers",
                    "shop_name": shop.unit_name,
                    "shop_phone": shop.contact_no,
                    "shop_location": shop.unit_location,
                    "latitude": shop.latitude,
                    "longitude": shop.longitude,
                }

            # ✅ Slot logic
            available_slots = get_available_delivery_slots()
            slots_data = []
            seen = set()
            current_time = timezone.localtime(timezone.now())

            start_day = 0 if allow_same_day else 1

            for slot in available_slots:
                for day_offset in range(start_day, start_day + 5):
                    future_date = current_time + timedelta(days=day_offset)

                    start_time = timezone.localtime(
                        timezone.make_aware(
                            datetime.combine(future_date.date(), slot.start_time)
                        )
                    )

                    end_time = timezone.localtime(
                        timezone.make_aware(
                            datetime.combine(future_date.date(), slot.end_time)
                        )
                    )

                    # Skip past slots for today
                    if day_offset == 0 and start_time <= current_time:
                        continue

                    key = (slot.id, future_date.date())
                    if key in seen:
                        continue
                    seen.add(key)

                    delivery_slot = (
                        f"{start_time.strftime('%d %b %Y %I:%M %p')} "
                        f"to {end_time.strftime('%I:%M %p')}"
                    )

                    slots_data.append(
                        {
                            "delivery_slot": delivery_slot,
                            "slot_id": slot.id,
                            "date": future_date.strftime("%Y-%m-%d"),
                            "start_time": start_time.isoformat(),
                        }
                    )

            # Sort and limit
            slots_data.sort(key=lambda x: (x["date"], x["start_time"]))
            slots_data = slots_data[:5]

            return Response(
                {
                    "status": 1,
                    "message": "Available delivery slots retrieved successfully!",
                    "data": slots_data,
                    "pickup_available": pickup_available,
                    "shop_details": shop_details,
                    "same_day_message": same_day_message,
                },
                status=status.HTTP_200_OK,
            )

        except Exception as e:
            return Response(
                {
                    "status": 0,
                    "message": "An unexpected error occurred.",
                    "exception": str(e),
                },
                status=status.HTTP_400_BAD_REQUEST,
            )


class AddOrUpdateSomeOneElseOrderDetail(CartViewMixin, APIView):
    def post(self, request):
        name = request.data.get("name", "")
        phone_number = request.data.get("phone_number", "")  # Get the coupon code from the request
        message = request.data.get("message", "")
        cart = Cart.objects.filter(user=request.user).first()
        order_id = request.data.get("order_id", "")

        if not name and not phone_number:
            return Response(
                {"status": 0, "message": "other person details should be given."},
                status=status.HTTP_400_BAD_REQUEST,
            )

        if order_id:
            order = Orders.objects.filter(uuid = order_id).first()
            if order:
                if order.order_type != "Custom Orders":
                    return Response(
                        {"status": 0, "message": "Invalid Order type please check order detail"},
                        status=status.HTTP_400_BAD_REQUEST,
                    )
                try:
                    some_one, created = SomeOneElse.objects.get_or_create(orders=order)
                    some_one.name = name if name else ""
                    some_one.phone_number = phone_number if phone_number else ""
                    some_one.message = message if message else ""
                    some_one.save()
                    return Response({
                        "status": 1,
                        "message": "Some one else data created successfully!",
                        "name": name,
                        "phone_number": phone_number
                    }, status=status.HTTP_201_CREATED)
                except Exception as e:
                    return Response({
                        "status": 0,
                        "message": "Some one else data creation failed",
                        "error": str(e)
                    }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        else:

            if not name and not phone_number and not cart:
                return Response(
                    {"status": 0, "message": "Cart detail and other person details should be given."},
                    status=status.HTTP_400_BAD_REQUEST,
                )
            elif not cart:
                return Response({
                    "status": 0, "message": "Cart couldn't found please check cart number"
                }, status = status.HTTP_404_NOT_FOUND)

            try:
                some_one , created = SomeOneElse.objects.get_or_create(cart=cart)
                some_one.name = name if name else ""
                some_one.phone_number = phone_number if phone_number else ""
                some_one.message = message if message else ""
                some_one.save()
                return Response({
                    "status": 1,
                    "message": "Some one else data created successfully!",
                    "name": name,
                    "phone_number": phone_number
                }, status = status.HTTP_201_CREATED)
            except Exception as e:
                return Response({
                    "status": 0,
                    "message": "Some one else data creation failed",
                    "error": str(e)
                }, status= status.HTTP_500_INTERNAL_SERVER_ERROR)


class GetSomeOneElseOrderDetail(CartViewMixin, APIView):
    def get(self, request):
        cart = Cart.objects.filter(user=request.user).first()
        if cart:
            some_one_data = SomeOneElse.objects.filter(cart = cart).first()
            if some_one_data:
                return Response({
                    "status": 1,
                    "message": "Some one else data retrieved successfully!",
                    "name": some_one_data.name,
                    "phone_number": some_one_data.phone_number
                },status = status.HTTP_200_OK)
            else:
                return Response({
                    "status": 0,
                    "message": "Some one else data not found",

                },status = status.HTTP_204_NO_CONTENT)
        else:
            return Response({
                "status": 0,
                "message": "Cart not found"
            }, status = status.HTTP_404_NOT_FOUND)


class DeleteGetSomeOneElseOrderDetail(CartViewMixin, APIView):
    def post(self, request):
        cart = Cart.objects.filter(user=request.user).first()
        if cart:
            some_one = SomeOneElse.objects.filter(cart=cart)
            some_one_data = some_one.first()
            name = some_one_data.name
            phone_number = some_one_data.phone_number
            if some_one_data:
                some_one.delete()
                return Response({
                    "status": 1,
                    "message": "Some one else data deleted successfully!",
                    "name": name,
                    "phone_number": phone_number
                }, status=status.HTTP_200_OK)
            else:
                return Response({
                    "status": 0,
                    "message": "Some one else data not found",

                }, status=status.HTTP_404_NOT_FOUND)
        else:
            return Response({
                "status": 0,
                "message": "Cart not found"
            }, status=status.HTTP_404_NOT_FOUND)




class CouponsListView(APIView, CartViewMixin):
    """
    View to list all available valid coupons and calculate the savings based on the user's cart.
    """

    def post(self, request):
        try:
            if request.user.is_authenticated:
                cart = Cart.objects.filter(user=request.user).first()
            else:
                try:
                    anonymous_id = request.data.get("anonymous_id")
                    cart = Cart.objects.filter(anonymous_id=anonymous_id).first()
                except:
                    cart = None

            if not cart:
                return Response(
                    {"status": 0, "message": "No cart found for the user."},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Use the CartViewMixin's method to get the cart's price data (including total)
            price_data_response = self.get_cart_items_response(cart, "Cart details")
            
            # Extract the total amount from the price_data
            cart_total = price_data_response.data.get("price_data", {}).get("subtotal", 0) # type: ignore

            # Get the cart items
            cart_items = CartItem.objects.filter(cart=cart)

            # Only fetch valid coupons
            valid_coupons = Coupons.objects.filter(
                validity_end_date__gte=timezone.now()
            )


            applicable_coupons = []

            # Loop through each valid coupon and check if it's applicable to the cart
            for coupon in valid_coupons:

                applicable_items = self.get_applicable_items(coupon, cart_items)
                savings = 0
                is_applicable = False

                if applicable_items:
                    savings = self.calculate_savings(coupon, applicable_items, cart_total)
                    is_applicable = True
                applicable_coupons.append(
                    {
                        "coupon_name": coupon.CouponName,
                        "coupon_code": coupon.CouponCode,
                        "coupon_description": coupon.CouponDescription,
                        "coupon_type": coupon.CouponType,
                        "minimum_bill_amount": coupon.TotalBillAmount,
                        "price": coupon.DiscountAmount if coupon.CouponType == 'amount' else None,
                        "percentage": coupon.DiscountPercentage if coupon.CouponType == 'percentage' else None,
                        "max_discount_amount": coupon.MaxDiscountAmountForPercentage,
                        "icon": coupon.Icon.url if coupon.Icon else None,
                        "terms_and_conditions": coupon.TermsAndConditions,
                        "savings": savings,
                        "applicable": is_applicable,
                    }
                )

            return Response(
                {
                    "status": 1,
                    "message": "Valid coupons retrieved successfully.",
                    "coupons": applicable_coupons,
                },
                status=status.HTTP_200_OK,
            )
        except Exception as e:
            return Response(
                {
                    "status": 0,
                    "message": "An unexpected error occurred.",
                    "Exception": str(e),
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

    def get_applicable_items(self, coupon, cart_items):
        """
        Check if any items in the cart match the applicable categories, subcategories, or SKUs of the coupon.
        """
        applicable_items = []

        # Check if the coupon applies to specific SKUs in the cart
        if coupon.CouponOn == "Sku":
            applicable_items = [
                item for item in cart_items if item.sku in coupon.ApplicableSku.all()
            ]

        # Check if the coupon applies to specific categories or subcategories
        elif coupon.CouponOn == "Category":
            applicable_items = [
                item
                for item in cart_items
                if item.sku.product.item_category in coupon.ApplicableCategory.all()
            ]
        elif coupon.CouponOn == "SubCategory":
            applicable_items = [
                item
                for item in cart_items
                if item.sku.product.item_sub_category
                in coupon.ApplicableSubCategory.all()
            ]
        elif coupon.CouponOn == "Product":
            applicable_items = [
                item
                for item in cart_items
                if item.sku.product in coupon.ApplicableProduct.all()
            ]
        # add for price

        return applicable_items

    def calculate_savings(self, coupon, applicable_items, cart_total):
        """
        Calculate the savings for the user based on the coupon type (DiscountAmount or DiscountPercentage).
        """
        savings = 0

        # Check if the cart total exceeds the MinimumBillAmount
        if cart_total >= coupon.TotalBillAmount:
            if coupon.CouponType == "amount":
                savings = coupon.DiscountAmount
            elif coupon.CouponType == "percentage":
                savings = (coupon.DiscountPercentage / 100) * cart_total

            # Apply the maximum discount amount cap
                if coupon.MaxDiscountAmountForPercentage:
                    savings = min(savings, coupon.MaxDiscountAmountForPercentage)

        savings = round(savings, 2)

        return savings




class VerifyDeliveryOTP(APIView):

    authentication_classes = []
    permission_classes = []

    def post(self, request):

        order_uuid = request.data.get("order_uuid")
        otp = request.data.get("otp")

        order = Orders.objects.filter(uuid=order_uuid).first()

        if not order:
            return Response({"error": "Order not found"})

        delivery_otp = DeliveryOTP.objects.filter(order=order).first()

        if not delivery_otp:
            return Response({"error": "OTP not found"})

        if delivery_otp.otp != otp:
            return Response({"error": "Invalid OTP"})

        if delivery_otp.is_verified:
            return Response({"error": "OTP already used"})

        delivery_otp.is_verified = True
        delivery_otp.save()

        order.order_status = "Delivered"
        order.color_status = "White"
        order.color_status_updation_time = datetime.now()
        order.save()
        # -----------------------------
        # YOUR EXISTING DELIVERED LOGIC
        # -----------------------------

        try:
            shipper_uuid = order.delivery_boy
            shipper = DeliveryBoys.objects.filter(pk=shipper_uuid).first()

            if shipper and shipper.delivery_boy_status == "assigned":
                shipper.delivery_boy_status = "not assigned"
                shipper.save()

            custom_coupon_check = CustomCouponSettings.objects.first()

            if (order.grand_total >= custom_coupon_check.lower_limit_price) and (order.grand_total <= custom_coupon_check.higher_limit_price):

                coupon_code_generation = f"NavyaCoup{str(random.randint(1000,100000000))}"

                custom_coupon = CustomCoupon.objects.create(
                    coupon_code=coupon_code_generation,
                    coupon=custom_coupon_check,
                    user=order.user_uuid
                )

                notification_title = "Eligible for Coupon!"
                notification_description = f"You are eligible for Coupon ({coupon_code_generation})."

                NotificationInit(
                    order.user_uuid.fcm_token,
                    order,
                    notification_title,
                    notification_description,
                    order.user_uuid
                )

                # EmailSend(
                #     notification_title,
                #     notification_description,
                #     [order.user_uuid.email],
                #     False
                # )

        except:
            pass

        return Response({
            "message": "Order Delivered Successfully"
        })




class VerifyPayBillDesk(APIView):
    def post(self, request, *args, **kwargs):
        try:
            order_id = request.data.get("order_id")
            order    = Orders.objects.get(order_ID= order_id)
            payment  = Payment.objects.get(order=order)
            order    = payment.order
            test     = payment.payment_status.lower()

            try:

                if payment.payment_status == 'paid' or payment.payment_status == 'Paid':
                    
                    # temp_name ='order_confirmation_general'
                    # title = "Your Order is Confirmed 🎉"

                    # description = f"""Hi {order.user_uuid.first_name},

                    # Your order {order.order_ID} has been successfully confirmed.
                    # We’ve started processing it and will keep you updated on the next steps.
                    # Thank you for choosing Navya Bakers!"""
                    # NotificationInit(order.user_uuid.fcm_token, order, title, description, order.user_uuid)
                    # EmailSend(title, description, [order.user_uuid.email], False)
                    # if order.user_uuid.opt_in == True:
                    #     send_whatsapp_message.apply_async(args=[order.user_uuid.phone_number, order.order_ID, order.user_uuid.first_name, temp_name], countdown=2 )
                    if order.store_uuid:
                        shop_name = order.store_uuid.unit_name
                        phone_number = order.store_uuid.contact_no
                    else:
                        shop_name = order.pu_uuid.pu_name
                        phone_number = order.pu_uuid.contact_no

                    grand_total = order.grand_total
                    payment_method = order.payment_mode.mode_name

                    delivery_time = "N/A"

                    if order.delivery_slot_time and order.delivery_slot_date:

                        slot = DeliverySlot.objects.filter(
                            start_time=order.delivery_slot_time
                        ).first()

                        if slot:

                            # Convert string to date object if needed
                            if isinstance(order.delivery_slot_date, str):
                                delivery_date_obj = datetime.strptime(
                                    order.delivery_slot_date,
                                    "%Y-%m-%d"
                                )
                            else:
                                delivery_date_obj = order.delivery_slot_date

                            delivery_date = delivery_date_obj.strftime("%d %b %Y")

                            start_time = slot.start_time.strftime("%I:%M %p")
                            end_time = slot.end_time.strftime("%I:%M %p")

                            delivery_time = (
                                f"{delivery_date} | "
                                f"{start_time} - {end_time}"
                            )
                    if order.order_type != "Custom Orders":
                        delivery_mode =order.order_type
                        if delivery_mode == "Local Orders":
                            delivery_mode = "Home Delivery"
                            if order.drop_address:
                                d = order.drop_address
                                drop_address = (
                                    f"{d.name}, {d.house_number_or_name}, {d.street}, "
                                    f"{d.city}, {d.state_or_province} - {d.pin_code}"
                                )
                        else:
                            drop_address = "N/A"
                    else:
                        delivery_mode = CustomOrderTracking.objects.filter(order=order).first().delivery_type
                        if delivery_mode == "Home Delivery":
                            if order.drop_address:
                                d = order.drop_address
                                drop_address = (
                                    f"{d.name}, {d.house_number_or_name}, {d.street}, "
                                    f"{d.city}, {d.state_or_province} - {d.pin_code}"
                                )
                        else:
                            drop_address = "N/A"
                    
                    send_whatsapp_order_message.apply_async(args=[phone_number, shop_name, order.order_ID, order.user_uuid.first_name, order.user_uuid.phone_number, drop_address, grand_total, payment_method, delivery_mode, delivery_time])    
                    if order.order_type != "Custom Orders":
                        user = order.user_uuid 
                        cart = get_object_or_404(Cart, user=user)
                        cart.delete()
                        custom_coupon = cart.custom_coupon

                        if custom_coupon:
                            CustomCoupon.objects.filter(coupon_code=custom_coupon).delete()
                    
                    if order.order_type == "Local Orders" or order.order_type == "Pick Up":
                        order_confirmed.send(
    sender="Order Creation",
    order_id=order.order_ID,
    store_id=order.store_uuid.uuid,
    platform=order.platform,    # read from saved order
    order_type=order.order_type
)
                        return Response(
                            {
                                "status": 1,
                                "message": "Payment Verified Successfully",
                                "order_details": OrderSerializer(order).data,
                            },
                            status=200,
                        )
                    elif order.order_type == "Custom Orders":
                        try: 
                            bill_edit = BillEdited.objects.filter(order=order).first()
                            editted = bill_edit.is_edited if bill_edit else False
                        except Exception as e:
                            logging.error(f"Error occurred while fetching bill edit status: {e}")
                            editted = False
                        return Response(
                        {
                            "status": 1,
                            "message": "Payment Verified Successfully",
                            "order_details": CustomOrderSerializer(
                            order,
                            context={
                                'request': request,
                                'is_edited': editted
                            }
                        ).data,
                        }, status=200,

                        )
                    elif order.order_type == "Long Distance Orders":
                        
                        return Response(
                            {
                                "status": 1,
                                "message": "Payment Verified Successfully",
                                "order_details": OrderSerializer2(order).data,
                            },
                            status=200,
                        )
                    else:
                        return Response(
                            {
                                "status": 1,
                                "message": "Payment Verified Successfully",
                                "order_details": OrderSerializer(order).data,
                            },
                            status=200,
                        )
                else:
                    temp_name ='deliveryfailedcase_general'
                    title = "Payment Failed"
                    description = f"Your payment for  order {order.order_ID} could not be processed at this time. Please try again later."
                    NotificationInit(order.user_uuid.fcm_token, order, title, description, order.user_uuid)
                    EmailSend(title, description, [order.user_uuid.email], False)
                    if order.user_uuid.opt_in == True:
                        send_whatsapp_message.apply_async(args=[order.user_uuid.phone_number, order.order_ID, order.user_uuid.first_name, temp_name], countdown=2 )
                    logging.error(
                    f"Payment Failed  for {order.order_ID}:\n{traceback.format_exc()}"
                )
                    return Response(
                        {
                            "status": 0,
                            "message": "An unexpected error occurred."
                        },
                        status=400,
                    )


            except Exception as e:
                temp_name ='deliveryfailedcase_general'
                title = "Payment Failed"
                description = f"Your payment for  order {order.order_ID} could not be processed at this time. Please try again later."
                NotificationInit(order.user_uuid.fcm_token, order, title, description, order.user_uuid)
                EmailSend(title, description, [order.user_uuid.email], False)
                if order.user_uuid.opt_in == True:
                    send_whatsapp_message.apply_async(args=[order.user_uuid.phone_number, order.order_ID, order.user_uuid.first_name, temp_name], countdown=2 )
                logging.error(
                    f"Payment Verification Failed for {order.order_ID}: {e}\n{traceback.format_exc()}"
                )
                return Response(
                    {"status": 0, "message": "Payment verification failed"},
                    status=400,
                )
        except Exception as e:
            temp_name ='deliveryfailedcase_general'
            title = "Payment Failed"
            description = f"Your payment for  order {order.order_ID} could not be processed at this time. Please try again later."
            NotificationInit(order.user_uuid.fcm_token, order, title, description, order.user_uuid)
            EmailSend(title, description, [order.user_uuid.email], False)
            if order.user_uuid.opt_in == True:
                                send_whatsapp_message.apply_async(args=[order.user_uuid.phone_number, order.order_ID, order.user_uuid.first_name, temp_name], countdown=2 )
            logging.error(
                    f"Payment Verification Failed for {order.order_ID}: {e}\n{traceback.format_exc()}"
                )

            return Response(
                {
                    "status": 0,
                    "message": "An unexpected error occurred.",
                    "exception": str(e),
                },
                status=400,
            )





class PastOrdersListAPIView(APIView):
    def get(self, request, *args, **kwargs):
        user = request.user

        orders = Orders.objects.filter(user_uuid=user).exclude(order_status="New Order").order_by("-created_date")

        serializer = PastOrderListSerializer(orders, many=True).data
        # print(serializer)
        for i in serializer:
            # print(i)
            if i["order_type"] == "Pick Up":
                if i["order_status"] == "Delivered":
                    i["order_status"] = "Order collected"
            if i["address_type"] == "home":
                i["address_type"] = "Home"
            elif i["address_type"] == "work":
                i["address_type"] = "Work"
            elif i["address_type"] == "others":
                i["address_type"] = "Others"
        # print(serializer)
        return Response(
            {
                "status": 1,
                "message": "Past orders fetched successfully",
                "orders": serializer,
            },
            status=status.HTTP_200_OK,
        )

def get_google_maps_link(lat, lng):
    return f"https://www.google.com/maps?q={lat},{lng}"



class PastOrderDetailAPIView(APIView):
    def get(self, request, order_uuid):
        try:
            pickup = False
            delivery_link = None
            order = Orders.objects.get(uuid=order_uuid, user_uuid=request.user)
            
            custom_order = CustomOrderTracking.objects.filter(order_id=order).first()

            if custom_order and custom_order.delivery_type == "Pick Up":
                pickup = True
                lat = order.store_uuid.latitude
                lng = order.store_uuid.longitude
                delivery_link = get_google_maps_link(lat, lng)
            elif order.order_type == "Pick Up":
                pickup = True
                lat = order.store_uuid.latitude
                lng = order.store_uuid.longitude
                delivery_link = get_google_maps_link(lat, lng)
            
            
            if order.order_type == "Local Orders":
                serializer = OrderSerializer(order).data

            elif order.order_type == "Long Distance Orders":
                serializer = OrderSerializer2(order).data
                if serializer.get("order_status") == "Despatched" or serializer.get("order_status") == "Delivered":
                    order_delivery = OrderDelivery.objects.filter(order = order_uuid).first()
                    courier_details = CourierDetailsSerializer(order_delivery).data
                    serializer["courier_details"] = courier_details
            elif order.order_type == "Custom Orders":
                    try:
                        bill_edit = BillEdited.objects.filter(order=order).first()
                        editted = bill_edit.is_edited if bill_edit else False
                    except Exception as e:
                        logging.error(f"Error occurred while fetching bill edit status: {e}")
                        editted = False
                    serializer = CustomOrderSerializer(
                        order,
                        context={
                            'request': request,
                            'is_edited': editted
                        }
                    ).data
            elif order.order_type == "Pick Up":
                serializer = OrderSerializer(order).data
                if serializer["order_status"] == "Delivered":
                        serializer["order_status"] = "Order collected"
            else:
                serializer = OrderSerializer(order).data
            payment_modes = PaymentModes.objects.filter(status=True).values('mode_name','id')
            return Response(
                {
                    "status": 1,
                    "message": "Order details fetched successfully",
                    "order_details": serializer,
                    "available_payment_modes": list(payment_modes),
                    **({"delivery_link": delivery_link} if pickup else {})
                },
                status=status.HTTP_200_OK,
            )
        except Orders.DoesNotExist:
            return Response(
                {
                    "status": 0,
                    "message": "Error while fetching order details",
                    "exc":str(Exception)
                },
                status=status.HTTP_200_OK,
            )






# class AddressChangeView(APIView):
#     def post(self, request):
#         if request.user.is_authenticated:

#             user = request.user
#             address_id = request.data.get("address_id")
#             address = Address.objects.get(id=address_id, user=user)
#             user_location = UserLocation.objects.filter(user=user).first()
#             pin_code = get_pincode_from_latlng(address.latitude, address.longitude)
#             reachble = check_pincode(pin_code)
#             shop = None
#             if user_location.shop: # type: ignore
#                 shop = user_location.shop # type: ignore
#                 new_address_coords = (address.latitude, address.longitude)
#                 shop_location_coords = (shop.latitude, shop.longitude)
#                 # gmaps = googlemaps.Client(key="AIzaSyBqLt_zwm0JnJR8Rm29_Lqrs0I5P0CkcYU")
#                 gmaps = googlemaps.Client(key=settings.GOOGLE_MAPS_API_KEY)
#                 result = gmaps.distance_matrix(origins=new_address_coords, destinations=shop_location_coords, mode="driving") # type: ignore
#                 if result["rows"][0]["elements"][0]["status"] == 'OK':
#                     road_distance = result["rows"][0]["elements"][0]["distance"]["value"]
#                     if road_distance <= shop.delivery_radius * 1000:
#                         return Response(
#                             {
#                             "status": 1,
#                             "message": "Address change applicable.",
#                             "proceed":True,
#                             "reachable": reachble
#                             },
#                         status=200,
#                         )
#                     else:
#                         return Response(
#                             {
#                                 "status": 0,
#                                 "message": "Address change not possible. Address is outside the delivery radius.",
#                                 "proceed": False,
#                                 "reachable": reachble
#                             },
#                             status=200,
#                         )
#                 else:
#                     return Response(
#                         {
#                             "status": 0,
#                             "message": "Address change not possible. Address is outside the delivery radius.",
#                             "proceed":False,
#                             "reachble": reachble
#                         },
#                         status=200,
#                     )
#             else:
#                 return Response(
#                         {
#                             "status": 0,
#                             "message": "No Shop available for this particular area So every products comes from production unit",
#                             "proceed":True,
#                             "reachble": reachble
#                         },
#                         status=200,
#                     )

class AddressChangeView(APIView):
    def post(self, request):
        # -----------------------------
        # AUTH CHECK
        # -----------------------------
        if not request.user.is_authenticated:
            return Response({"status": 0, "message": "Unauthorized"}, status=401)

        user = request.user
        address_id = request.data.get("address_id")

        if not address_id:
            return Response({"status": 0, "message": "Address ID required"}, status=400)

        # -----------------------------
        # GET ADDRESS
        # -----------------------------
        try:
            address = Address.objects.get(id=address_id, user=user)
        except Address.DoesNotExist:
            return Response({"status": 0, "message": "Invalid address"}, status=400)

        if not address.latitude or not address.longitude:
            return Response({"status": 0, "message": "Invalid coordinates"}, status=400)

        new_coords = (float(address.latitude), float(address.longitude))

        # -----------------------------
        # USER LOCATION
        # -----------------------------
        user_location = UserLocation.objects.filter(user=user).first()
        user_latitude = user_location.latitude if user_location else None
        user_longitude = user_location.longitude if user_location else None
        current_shop = user_location.shop if user_location else None

        # -----------------------------
        # GET SHOPS
        # -----------------------------
        shops = Shop.objects.filter(
            latitude__isnull=False,
            longitude__isnull=False,
            status="Open"  # optional but recommended
        )

        if not current_shop:
            return Response({
                "status": 0,
                "message": "No shops available. Delivery from production unit.",
                "proceed": True,
                "nearest_shop": None,
                "long_distance": True,
            })

        # -----------------------------
        # GOOGLE API
        # -----------------------------
        gmaps = googlemaps.Client(key=settings.GOOGLE_MAPS_API_KEY)

        destinations = [(shop.latitude, shop.longitude) for shop in shops]

        try:
            result = gmaps.distance_matrix(
                origins=[new_coords],
                destinations=destinations,
                mode="driving",
            )
        except Exception as e:
            return Response({
                "status": 0,
                "message": f"Google API error: {str(e)}"
            }, status=500)

        elements = result.get("rows", [])[0].get("elements", [])

        distances = []

        # -----------------------------
        # BUILD DISTANCE LIST
        # -----------------------------
        for shop, element in zip(shops, elements):

            if element.get("status") != "OK":
                continue

            distance_km = element["distance"]["value"] / 1000

            distances.append({
                "shop_uuid": str(shop.uuid),  # ✅ UUID
                "shop_name": shop.unit_name,
                "distance_km": round(distance_km, 2),
                "radius": shop.delivery_radius
            })

        if not distances:
            return Response({
                "status": 0,
                "message": "No reachable shops",
                "proceed": False,
                "long_distance": False

            })

        # -----------------------------
        # SORT
        # -----------------------------
        distances.sort(key=lambda x: x["distance_km"])

        nearest = distances[0]

        nearest_shop = shops.get(uuid=nearest["shop_uuid"])
        nearest_distance = nearest["distance_km"]
        nearest_radius = nearest["radius"]

        # -----------------------------
        # SAVE DISTANCE (OPTIONAL 🔥)
        # -----------------------------
        if user_location:
            user_location.distance = nearest_distance
            user_location.shop = nearest_shop
            user_location.save()

        # -----------------------------
        # OUTSIDE RADIUS
        # -----------------------------
        if nearest_radius and nearest_distance > nearest_radius:
            return Response({
                "status": 0,
                "message": "Outside delivery radius",
                "proceed": False,
                "nearest_shop": nearest["shop_name"],
                "distance_km": nearest_distance,
                "long_distance": False
            })
        # -----------------------------
        # SAME SHOP
        # -----------------------------
        if current_shop.uuid == nearest_shop.uuid:
            return Response({
                "status": 1,
                "message": "Same shop - allowed",
                "proceed": True,
                "current_shop": current_shop.unit_name,
                "nearest_shop": nearest["shop_name"],
                "distance_km": nearest_distance,
                "long_distance": False
            })

        # -----------------------------
        # DIFFERENT SHOP
        # -----------------------------
        return Response({
            "status": 0,
            "message": "Nearest shop changed - not allowed",
            "proceed": False,
            "current_shop": current_shop.unit_name if current_shop else None,
            "nearest_shop": nearest["shop_name"],
            "distance_km": nearest_distance,
            "long_distance": False
        })
        


class CustomOrderCheckoutAPIView(APIView):

    def post(self, request, *args, **kwargs):
        try:
            if request.user.is_authenticated:
                user          = request.user
                # Get the cart associated with the user
                order_id      = request.data.get("order_id")

                order = Orders.objects.filter(order_ID= order_id).first()
                delivery_mode_id = request.data.get("delivery_mode")
                grand_total = order.grand_total # to fetch the corresponding grand total of the order using order id
                try:
                    payment_mode = PaymentModes.objects.get(id=delivery_mode_id)
                except PaymentModes.DoesNotExist:
                    return Response({"status": 0, "message": "Invalid payment mode."}, status=400)
                ua_string = request.META.get('HTTP_USER_AGENT', '')
                pf_type = request.data.get("platform", None)
                if pf_type and pf_type == "Flutter Web App":
                    platform_data = "Flutter_web_app"
                elif pf_type and pf_type == "Flutter Mobile App":
                    platform_data = "Android"
                else:
                    user_agent = parse(ua_string)
                    logging.info(f"Platform for the user agent string: {ua_string}")
                    platform = user_agent.os.family
                    logging.info(f"Platform : {platform}")
                    platform_data = "Other"
                    if platform == 'Windows' or platform == "Mac OS X" or platform == 'Linux' or platform == 'Ubuntu':
                        platform_data = "Web"
                    else:
                        platform_data = "Other"

                if order.order_status != "Bill Created":
                    return Response(
                        {
                            "status":0,
                            "message": "Payment not allowed!"
                        }
                    )
                if not order:
                    return Response(
                        {
                            "status": 0,
                            "message": "Order not found!",
                        }
                    )
                with transaction.atomic():
                    order.order_status = "New Order"
                    order.delivery_instruction = request.data.get("delivery_instruction", "")
                    order.cooking_instruction = request.data.get("cooking_instruction", "")
                    order.payment_mode = payment_mode
                    order.platform = platform_data
                    order.save()
                        
                    
                    # some_one_else = SomeOneElse.objects.filter(cart = cart).first()
                    # if some_one_else:
                    #     some_one_else.orders = order
                    #     some_one_else.save()
                    check_and_verify_order_status.apply_async((order.order_ID,), countdown=300)
                    
                    if payment_mode.id == 1:
                        
                        
                        Payment.objects.create(
                            order=order,
                            payment_status="pending",
                            bill_desk_order_id=None,
                            amount=str(grand_total),
                            payment_method_type="COD",
                        )
                        order.order_status = "Confirmed"
                        order.save()
                        order_confirmed.send(
    sender="Order Creation",
    order_id=order.order_ID,
    store_id=order.store_uuid.uuid,
    platform=platform_data,
    order_type="Custom Orders"
)
                        temp_name ='custom_order_confirmation'
                        title = "Your Order is Confirmed 🎉"

                        description = f"""Hi {order.user_uuid.first_name},
                        Your order {order.order_ID} has been successfully confirmed.
                        We’ve started processing it and will keep you updated on the next steps.
                        Thank you for choosing Navya Bakers!"""
                        NotificationInit(order.user_uuid.fcm_token, order, title, description, order.user_uuid)
                        EmailSend(title, description, [order.user_uuid.email], False)
                        if order.user_uuid.opt_in == True:
                            send_whatsapp_message.apply_async(args=[order.user_uuid.phone_number, order.order_ID, order.user_uuid.first_name, temp_name], countdown=2 )
                        if order.store_uuid:
                            shop_name = order.store_uuid.unit_name
                            phone_number = order.store_uuid.contact_no
                        else:
                            shop_name = order.pu_uuid.pu_name
                            phone_number = order.pu_uuid.contact_no

                        grand_total = order.grand_total
                        payment_method = order.payment_mode.mode_name

                        delivery_time = "N/A"

                        if order.delivery_slot_time and order.delivery_slot_date:

                            slot = DeliverySlot.objects.filter(
                                start_time=order.delivery_slot_time
                            ).first()

                            if slot:

                                # Convert string to date object if needed
                                if isinstance(order.delivery_slot_date, str):
                                    delivery_date_obj = datetime.strptime(
                                        order.delivery_slot_date,
                                        "%Y-%m-%d"
                                    )
                                else:
                                    delivery_date_obj = order.delivery_slot_date

                                delivery_date = delivery_date_obj.strftime("%d %b %Y")

                                start_time = slot.start_time.strftime("%I:%M %p")
                                end_time = slot.end_time.strftime("%I:%M %p")

                                delivery_time = (
                                    f"{delivery_date} | "
                                    f"{start_time} - {end_time}"
                                )
                        delivery_mode = CustomOrderTracking.objects.filter(order=order).first().delivery_type
                        if delivery_mode == "Home Delivery":
                            if order.drop_address:
                                d = order.drop_address
                                drop_address = (
                                    f"{d.name}, {d.house_number_or_name}, {d.street}, "
                                    f"{d.city}, {d.state_or_province} - {d.pin_code}"
                                )
                        else:
                            drop_address = "N/A"
                        
                        send_whatsapp_order_message.apply_async(args=[phone_number, shop_name, order.order_ID, order.user_uuid.first_name, order.user_uuid.phone_number, drop_address, grand_total, payment_method, delivery_mode, delivery_time])    

                        try:
                            cart = Cart.objects.get(user=user)
                            logging.info(f"The cart value is {cart}")
                            cart.delete()
                        except Cart.DoesNotExist:
                            logging.info("No cart found for user, skipping cart deletion")
                        try: 
                            bill_edit = BillEdited.objects.filter(order=order).first()
                            editted = bill_edit.is_edited if bill_edit else False
                        except Exception as e:
                            logging.error(f"Error occurred while fetching bill edit status: {e}")
                            editted = False

                        return Response(
                            {
                            "status": 1,
                            "message": "Order placed successfully with COD.",
                            "data": {
                                "order_id":order_id,
                                "amount": grand_total,
                                "payment_mode": payment_mode.id,
                                "order_details": CustomOrderSerializer(
                            order,
                            context={
                                'request': request,
                                'is_edited': editted
                            }
                        ).data,
                            }
                        }, status=201)
                    elif payment_mode.id == 2:                   
                            Payment.objects.create(
                                    order=order,
                                    payment_status="pending",
                                    payment_method_type="Online Payment",
                                    amount=str(grand_total),
                                )
                            

                            # ---- PayU credentials ----
                            payu_key = "oEOB0P"
                            payu_salt = "IJB9iqgsiUw879xSB1XGfqSM3hzDSaO7"

                            # ---- PayU required fields ----
                            txnid = order_id
                            split1= grand_total 
                            amount = f"{Decimal(grand_total):.2f}"
                            productinfo = "Navya Bakers Custom Order"
                            firstname = user.first_name or ""
                            email = user.email or ""

                            
 
                            phone = user.phone_number.replace("+", "").strip()[-10:]
                            auth_header = request.headers.get("Authorization", "")
                            token = None
                            if auth_header.startswith("Token "):
                                token = auth_header.split("Token ")[1].strip()
                            if not token:
                                surl = f"{settings.DOMAIN}orders/payu/return/"
                                furl = f"{settings.DOMAIN}orders/payu/return/"

                            else:

                                surl = f"{settings.DOMAIN}orders/payu/return/?token={token}"
                                furl = f"{settings.DOMAIN}orders/payu/return/?token={token}"

                            # # ---- SPLIT REQUEST (Sub-Merchant Config) ----
                            # split_request = {
                            #     "type": "absolute",
                            #     "splitInfo": {
                            #         "X4Y55z": {  # Sub-merchant key 1
                            #             "aggregatorSubTxnId": f"{txnid}_1",
                            #             "aggregatorSubAmt": f"{amount}",
                            #             "aggregatorCharges": "0.00"
                            #         },
                            #     }
                            # }
                            # split_request_str = json.dumps(split_request, separators=(",", ":"))

                            # # ---- HASH GENERATION (FOR SPLIT PAYMENT) ----
                            # hash_string = (
                            #     f"{payu_key}|{txnid}|{amount}|{productinfo}|"
                            #     f"{firstname}|{email}|||||||||||{payu_salt}|{split_request_str}"
                            # )
                            productinfo = "Navya Bakers Custom Order"

                            split_request = {
                                "type": "absolute",
                                "splitInfo": {
                                    "X4Y55z": {
                                        "aggregatorSubTxnId": f"{txnid}_1",
                                        "aggregatorSubAmt": amount,
                                        "aggregatorCharges": "0.00"
                                    }
                                }
                            }

                            split_request_str = json.dumps(split_request, separators=(",", ":"))

                            hash_string = (
                                f"{payu_key}|{txnid}|{amount}|{productinfo}|"
                                f"{firstname}|{email}|||||||||||{payu_salt}|{split_request_str}"
                            )

                            

                            # ---- HASH GENERATION (FOR SPLIT PAYMENT) ----
                            # hash_string = (
                            #     f"{payu_key}|{txnid}|{amount}|{productinfo}|"
                            #     f"{firstname}|{email}|||||||||||{payu_salt}"
                            # )

                            payu_hash = hashlib.sha512(hash_string.encode("utf-8")).hexdigest()
                            assert len(payu_hash) == 128
                            # ---- Redirect to PayU ----
                            params = {
                                "key": payu_key,
                                "txnid": txnid,
                                "amount": amount,
                                "productinfo": productinfo,
                                "firstname": firstname or "",
                                "email": email or "",
                                "phone": phone,
                                "surl": surl,
                                "furl": furl,
                                "hash": payu_hash,
                                "splitRequest": split_request_str,
                                "hash_string": hash_string,
                            }

                            # Only if absolutely required
                            if platform_data and platform_data.lower() in ["android", "ios"]:
                                params["salt"] = payu_salt  # ⚠️ not recommended

                            return Response({
                                "status": 1,
                                "message": "PayU payment initiated",
                                "payu_url": "https://test.payu.in/_payment",
                                "params": params,
                            }, status=200)
                    else:
                        return Response(
                            {
                                "status": 0,
                                "message": "Invalid payment mode selected.",
                            },
                            status=400,
                        )
            else:
                return Response(
                    {
                        "status": 0,
                        "message": "User not Authenticated",
                    }
                )

        except Exception as e:
            return Response(
                {
                    "status": 0,
                    "message": "An unexpected error occurred.",
                    "exception": str(e),
                },
                status=status.HTTP_400_BAD_REQUEST,
            )



class AdListAPIView(APIView):

    def get(self, request):
        try:
            ads = Ads.objects.all()
            ad_serializer = AdSerializer(ads, many= True)
            return Response(
                {
                    "status": 1,
                    "message": "Ad Listed Successfully",
                    "data": {
                        "ads": ad_serializer.data
                    },
                },
                status=status.HTTP_200_OK,
            )

        except Exception as e:
            return Response(
                {
                    "status": 0,
                    "message": "An unexpected error occurred.",
                    "exception": str(e),
                },
                status=status.HTTP_400_BAD_REQUEST,
            )


class DiscountDetailView(APIView):
    """
    View to retrieve the details of a selected discount and list the associated products.
    """

    def get(self, request, discount_id):
        try:
            if request.user.is_authenticated:
                # User is authenticated, get user location and shop
                user_location = UserLocation.objects.filter(user=request.user).first()
            else:
                # Anonymous user, get the anonymous ID and location
                anonymous_id = request.data.get("anonymous_id")
                user_location = UserLocation.objects.filter(
                    anonymous_id=anonymous_id
                ).first()


            if user_location and user_location.shop:

                # Shop found, apply shop logic
                shop_id = user_location.shop.uuid
                product_selections = SalesUnitProductSelection.objects.filter(
                    sales_unit__uuid=shop_id
                ).select_related("sku")
                sku_status_map = {
                    selection.sku.id: selection.shop_admin_status  # type: ignore
                    for selection in product_selections
                    if selection.sku
                }


            discount = get_object_or_404(Discount, id=discount_id)

            product_info_list = []

            if discount.DiscountOn == 'Category':
                applicable_categories = discount.ApplicableCategory.all()


                products = Products.objects.filter(item_category__in=applicable_categories)


            elif discount.DiscountOn == 'SubCategory':
                applicable_subcategories = discount.ApplicableSubCategory.all()
                products = Products.objects.filter(item_sub_category__in=applicable_subcategories)

            elif discount.DiscountOn == 'Product':
                applicable_products = discount.ApplicableProduct.all()
                products = applicable_products

            elif discount.DiscountOn == 'Sku':
                applicable_skus = discount.ApplicableSku.all()
                products = Products.objects.filter(skus__in=applicable_skus)



            for product in products:
                product_image = ProductImage.objects.filter(product=product).first()
                product_image_url = product_image.image.url if product_image else None

                if user_location and user_location.shop:
                    skus = SKU.objects.filter(
                        product=product, sku_status__in=["Visible", "Out of Stock"]
                    )
                else:
                    skus = SKU.objects.filter(
                        product=product,
                        sku_status__in=["Visible", "Out of Stock"],
                        sku_expiry_duration__gt=30,
                    )

                product_info = {
                    "product_id": product.id,
                    "product_name": product.item_name,
                    "product_type": product.veg_or_non_veg_status,
                    "offer": discount.DiscountPercentage if discount.DiscountPercentage else 0,
                    "price": product.skus.first().sku_mrp if product.skus.exists() else None,
                    "offerprice": (Decimal.from_float(product.skus.first().sku_mrp) * (1 - discount.DiscountPercentage / 100)) if product.skus.exists() else None,
                    "product_img": product_image_url,
                    "sku_name": skus.first().sku_name if skus.exists() else None,
                    "sku_quantity": skus.first().sku_quantity if skus.exists() else None,
                    "sku_unit": skus.first().sku_unit if skus.exists() else None,
                    "skus": [
                        {
                            "sku_name": sku.sku_name,
                             "sku_status": sku_status_map.get(sku.id) if user_location and user_location.shop else sku.sku_status,
                        }
                        for sku in skus
                    ],
                    "wishlist": product.id in [wishlist.product.id for wishlist in Wishlist.objects.filter(user=request.user)] if request.user.is_authenticated else False,
                }

                product_info_list.append(product_info)

            return Response(
                {
                    "status": 1,
                    "message": "Discount details and products retrieved successfully.",
                    "discount_name": discount.DiscountName,
                    "discount_code": discount.DiscountCode,
                    "products": product_info_list,
                },
                status=status.HTTP_200_OK,
            )
        except Exception as e:
            return Response(
                {
                    "status": 0,
                    "message": "An unexpected error occurred.",
                    "Exception": str(e),
                },
                status=status.HTTP_400_BAD_REQUEST,
            )


class DiscountsListView(APIView):
    """
    View to list all discounts with DiscountName and StandardImage.
    """
    def post(self, request):
        try:
            user_location = None
            if request.user.is_authenticated:
                # User is authenticated, get user location and shop
                user_location = UserLocation.objects.filter(user=request.user).first()
            else:
                # Anonymous user, get the anonymous ID and location

                anonymous_id = request.data.get("anonymous_id", "")
                if anonymous_id:
                    user_location = UserLocation.objects.filter(
                        anonymous_id=anonymous_id
                    ).first()
                # logging.info(f"...................{user_location.shop.unit_name}................................")

            order_type = "long_distance"
            if user_location and user_location.shop:
                logging.info("////////////////....User Location Fetched................////////////////////////")
                logging.info(f"///////////////////////////.......Shop Found : {user_location.shop.unit_name}........./////////")

                # Shop found, apply shop logic
                shop_id = user_location.shop
                order_type = "shop"

            try:
                discounts = Discount.objects.all()
            except:
                discounts = []
            discounts_data = []
            if order_type == "shop":
                for discount in discounts:
                    if discount.DiscountOn == "Category":
                        if discount.ApplicableCategory.filter(sales_unit__in = [shop_id]).exists():
                            discounts_data.append( {
                            'id': discount.id,
                            'DiscountName': discount.DiscountName,
                            'WebImage': discount.StandardImage.url if discount.StandardImage else None,
                            'MobileImage': discount.BannerImage.url if discount.BannerImage else None,

                            })
                    elif discount.DiscountOn == "SubCategory":
                        if discount.ApplicableSubCategory.filter(sales_unit__in = [shop_id]).exists():
                            discounts_data.append({
                                'id': discount.id,
                                'DiscountName': discount.DiscountName,
                                'WebImage': discount.StandardImage.url if discount.StandardImage else None,
                                'MobileImage': discount.BannerImage.url if discount.BannerImage else None
                            })
                    elif discount.DiscountOn == "Product":
                        if discount.ApplicableProduct.filter(sales_unit__in = [shop_id]).exists():
                            discounts_data.append({
                                'id': discount.id,
                                'DiscountName': discount.DiscountName,
                                'WebImage': discount.StandardImage.url if discount.StandardImage else None,
                                'MobileImage': discount.BannerImage.url if discount.BannerImage else None
                            })

                    else:
                        if discount.ApplicableSku.filter(sales_unit__in = [shop_id]).exists():
                            discounts_data.append({
                                'id': discount.id,
                                'DiscountName': discount.DiscountName,
                                'WebImage': discount.StandardImage.url if discount.StandardImage else None,
                                'MobileImage': discount.BannerImage.url if discount.BannerImage else None
                            })
            else:

                for discount in discounts:
                    if discount.DiscountOn == "Category":
                        for category in discount.ApplicableCategory.all():

                            if category.long_distance_availability:
                                discounts_data.append( {
                                'id': discount.id,
                                'DiscountName': discount.DiscountName,
                                'WebImage': discount.StandardImage.url if discount.StandardImage else None,
                                'MobileImage': discount.BannerImage.url if discount.BannerImage else None
                                })
                                break
                    elif discount.DiscountOn == "SubCategory":
                        for sub_category in discount.ApplicableSubCategory.all():
                            if sub_category.long_distance_availability:
                                discounts_data.append({
                                    'id': discount.id,
                                    'DiscountName': discount.DiscountName,
                                    'WebImage': discount.StandardImage.url if discount.StandardImage else None,
                                    'MobileImage': discount.BannerImage.url if discount.BannerImage else None
                                })
                                break
                    elif discount.DiscountOn == "Product":
                        for product in discount.ApplicableProduct.all():
                            if product.long_distance_availability:
                                discounts_data.append({
                                    'id': discount.id,
                                    'DiscountName': discount.DiscountName,
                                    'WebImage': discount.StandardImage.url if discount.StandardImage else None,
                                    'MobileImage': discount.BannerImage.url if discount.BannerImage else None
                                })
                                break

                    else:
                        for skus in discount.ApplicableSku.all():
                            if skus.long_distance_availability:
                                discounts_data.append({
                                    'id': discount.id,
                                    'DiscountName': discount.DiscountName,
                                    'WebImage': discount.StandardImage.url if discount.StandardImage else None,
                                    'MobileImage': discount.BannerImage.url if discount.BannerImage else None
                                })
                                break



            return Response(
                {
                    "status": 1,
                    "message": "Discounts retrieved successfully.",
                    "discounts": discounts_data,
                },
                status=status.HTTP_200_OK,
            )

        except Exception as e:
            return Response(
                {
                    "status": 0,
                    "message": "An unexpected error occurred.",
                    "Exception": str(e),
                },
                status=status.HTTP_400_BAD_REQUEST,
            )



class Customorder_placing(APIView):
    def generate_unique_order_id(self):
        """Generate a unique order ID."""
        while True:
            order_id = f"ID{random.randint(100, 999)}{random.choice(string.ascii_uppercase)}{random.choice(string.ascii_uppercase)}"
            if not Orders.objects.filter(order_ID=order_id).exists():
                return order_id

    def post(self, request, id):
        try:
            user = request.user
            opt_in = request.data.get("opt_in", False)

            # Convert "true"/"false" string to real boolean
            if isinstance(opt_in, str):
                opt_in = opt_in.lower() == "true"

            # Save only if value changed
            if user.opt_in != opt_in:
                user.opt_in = opt_in
                user.save(update_fields=["opt_in"])
            custom_product = get_object_or_404(CustomProduct, pk=id)
            description = request.data.get("description")
            message = request.data.get("message")  # This is now optional
            if message is None:
                message = ""
            # store_uuid = request.data.get("store_uuid")
            ua_string = request.META.get('HTTP_USER_AGENT', '')  # Django
            user_agent = parse(ua_string)
            logging.info(f"Platform for the user agent string: {ua_string}")
            platform = user_agent.os.family
            logging.info(f"Platform : {platform}")
            platform_data = "Other"
            if platform == 'Windows' or platform == "Mac OS X" or platform == 'Linux' or platform == 'Ubuntu':
                platform_data = "Web"
            elif platform == "Android":
                platform_data = "Andriod"
            elif platform == "iOS" or ua_string == "Flutter Mobile App / iOS":
                platform_data = "IOS"
            else:
                platform_data = "Other"

            # Make only description required, message is optional
            if not description:
                return Response({"error": "Description field is required!"}, status=status.HTTP_400_BAD_REQUEST)

            
            if not user.is_authenticated:
                return Response({"error": "User is not authenticated"}, status=status.HTTP_401_UNAUTHORIZED)
            # location = UserLocation.objects.filter(user=user)
            location = get_object_or_404(UserLocation, user=user)
            if not location:
                return Response({"error": "Please add your location"}, status=status.HTTP_400_BAD_REQUEST)
            shop = location.shop
            if not shop:
                return Response({"error": "No shops found at your location"}, status=status.HTTP_400_BAD_REQUEST)

            address_id = request.data.get("address_id")
            if not address_id:
                return Response(
                    {"status": 0, "message": "Address ID is required for delivery orders."},
                    status=status.HTTP_400_BAD_REQUEST
                )
            try:
                address = get_object_or_404(Address, id=address_id)
            except Exception as e:
                return Response(
                    {"status": 0, "message": "Failed to fetch address.", "exception": str(e)},
                    status=status.HTTP_400_BAD_REQUEST
                )
            drop_address = Dropaddress.objects.create(
                name=f"{user.first_name} {user.last_name}",
                house_number_or_name=address.flat_no,  # type: ignore
                land_mark=address.landmark,  # type: ignore
                street="street",
                city="city",
                state_or_province="state",
                pin_code=000000,
                latitude=address.latitude,  # type: ignore
                longitude=address.longitude,  # type: ignore
                address_type=address.address_type,  # type: ignore
            )
            
            order_id=self.generate_unique_order_id()
            # Create the order
            new_order = Orders.objects.create(
                order_ID=order_id,
                custom_product=custom_product,
                order_type="Custom Orders",
                user_uuid=user,
                store_uuid=shop,
                description=description,
                message=message,  # This can be None/empty now
                order_status="Enquiry",
                color_status="White",
                platform = platform_data,
                drop_address=drop_address
            )
            order = Orders.objects.get(order_ID=order_id)
            image = request.data.get("image")
            if image:
                CustomOrderTracking.objects.create(order_id=order, custom_image=image)
            else:
                CustomOrderTracking.objects.create(order_id=order)
            return Response(
                {
                    "status": 1,
                    "message": "Custom order created successfully!",
                    "order_details": CustomOrderCreateSerializer(new_order).data,
                },
                status=200,
            )
        except Exception as e:
            return Response({"status": 0,
                            "message": "An unexpected error occurred.",
                            "error": str(e), },
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)



class NotificationListView(CartViewMixin, APIView):
    """
    View to list all notification history.
    """
    def get(self, request):
        try:
            if request.user.is_authenticated:
                try:
                    notification_list = NotificationStat.objects.order_by('-created_date')
                    notification_list = notification_list.filter(sendTo=request.user).all()
                except:
                    notification_list = []
                notification_list_data=[]
                for notification in notification_list:
                    if notification.Sendmsg == "Bill Created":
                        bill_details = OrderBillDetailsSerializer(notification.OrderID)
                        custom_product = CustomProductSerializer(notification.OrderID.custom_product)

                        notification_list_data.append( {
                        'id': notification.id,
                        'Sendmsg': notification.Sendmsg,
                        'Description': notification.Description,
                        'OrderID': notification.OrderID.order_ID,
                        'order_type':notification.OrderID.order_type,
                        'order_uuid':notification.OrderID.uuid,
                        'date': localtime(notification.created_date).strftime("%Y-%m-%d"),
                        'time': localtime(notification.created_date).strftime("%H:%M:%S"),
                        'notification_type' : "Bill Created",
                        'product_details' : custom_product.data,
                        'bill_details': bill_details.data,
                    })
                    else:
                        notification_list_data.append({
                        'id': notification.id,
                        'Sendmsg': notification.Sendmsg,
                        'Description': notification.Description,
                        'OrderID': notification.OrderID.order_ID,
                        'order_type':notification.OrderID.order_type,
                        'order_uuid':notification.OrderID.uuid,
                        'date': localtime(notification.created_date).strftime("%Y-%m-%d"),
                        'time': localtime(notification.created_date).strftime("%H:%M:%S"),
                        'notification_type': "Normal"
                    })
                return Response(
                    {
                        "status": 1,
                        "message": "Notification history retrieved successfully.",
                        "notification_list": notification_list_data,
                    },
                    status=status.HTTP_200_OK,
                )
            else:
                return Response({
                    "status": 0,
                    "message" : "User not Authenticated"
                })
        except Exception as e:
            return Response(
                {
                    "status": 0,
                    "message": "An unexpected error occurred.",
                    "Exception": str(e),
                },
                status=status.HTTP_400_BAD_REQUEST,
            )



class ExcelWriter(APIView):
    """
    View for user login (also used for registration).
    """

    def post(self, request, order_id):
        tempate_path = r"bill_writer/navya_bill_template2new.xlsx"
        try:
            output = template_writer(order_id, tempate_path)
            return Response(
                {"status": 1, "message": "Pdf bill created successfully"},
                status=status.HTTP_200_OK,
            )
        except Exception as e:

            return Response(
                {"status": 0, "message": str(e) },
                status=status.HTTP_400_BAD_REQUEST,
            )


class DownloadBill(APIView):

    def post(self, request, order_id):
        order_id = order_id.strip()
        template_path = r"bill_writer/navya_bill_template2new.xlsx"
        try:
            template_writer(order_id, template_path)
            file_path = os.path.join(r'media/output/pdf', f'{order_id}.pdf')

            if os.path.exists(file_path):
                return FileResponse(open(file_path, 'rb'), as_attachment=True, filename=f'{order_id}.pdf')
            else:
                template_writer(order_id, template_path)
                if os.path.exists(file_path):
                    return FileResponse(open(file_path, 'rb'), as_attachment=True, filename=f'{order_id}.pdf')
            return Response({"status":0, "message": "File Not Found"}, status = status.HTTP_404_NOT_FOUND)

        except Exception as e:
            return Response(
                {"status": 0, "message": str(e) },
                status=status.HTTP_400_BAD_REQUEST,
            )






def delete_all_files(folder_path):
    for filename in os.listdir(folder_path):
        file_path = os.path.join(folder_path, filename)

        # Delete only files
        if os.path.isfile(file_path):
            os.remove(file_path)
            logging.info(f"Deleted: {file_path}")



class DeleteBills(APIView):

    def post(self, request):
        try:
            delete_all_files(r'media/output/pdf')
            delete_all_files(r'media/output/excel')
            return Response({"status":1, "message": "Files Deleted"}, status = status.HTTP_200_OK)

        except Exception as e:
            return Response(
                {"status": 0, "message": str(e) },
                status=status.HTTP_400_BAD_REQUEST,
            )



class BillPaymentAPI(APIView):
    def post(self, request, *args, **kwargs):
        
        transaction_response = request.data.get("transaction_response", None)
        # ------------------------------
        # Detect Platform
        # ------------------------------
        ua_string = request.headers.get("User-Agent", "")
        pf_type  = request.GET.get("platform", None)
        token = request.GET.get("token", None)
        order_id = request.GET.get("order_id", None)
        # PRIORITY 1 → If ?platform= is given → Always HTML Mode
        if pf_type:
            platform_type = "Flutter_web_app"
        else:
            # PRIORITY 2 → Detect via User-Agent
            try:
                user_agent = parse(ua_string)
                platform = user_agent.os.family
                logging.info(f"Detected OS Platform: {platform}")
                if platform in ["Windows", "Mac OS X", "Linux", "Ubuntu"]:
                    platform_type = "Web"
                elif platform == "Android":
                    platform_type = "Android"
                elif platform == "iOS" or ua_string == "Flutter Mobile App / iOS":
                    platform_type = "IOS"
                else:
                    platform_type = "Other"
            except Exception:
                platform_type = "Other"
        logging.info(f"REQUEST HEADERS: {dict(request.headers)}")

        
        # ------------------------------
        # No transaction_response
        # ------------------------------
        if not transaction_response:

            # Mobile App → JSON response
            if platform_type in ["Android", "IOS"]:
                return Response({
                    "status": 0,
                    "message": "No transaction data received."
                }, status=status.HTTP_400_BAD_REQUEST)

            # Web Browser → HTML page
            order = Orders.objects.filter(order_ID= order_id).first()
            payment = Payment.objects.filter(order=order).first()
            

            if pf_type:
                checkout_url = f"{settings.domain2}web?token={token}"
            else:
                checkout_url = f"{settings.domain1}checkout"
            if order.order_type == "Custom Orders":
                order.order_status = "Bill Created"
            payment.payment_status = 'Failed'
            order.save()
            payment.save()

            return render(request, "payment_failure.html", {
                "message": "No transaction data received.",
                "checkout_url": checkout_url
            }, status=400)

        # ------------------------------
        # Decrypt and get order
        # ------------------------------
        data = billdesk_utils.decrypt(
            transaction_response, settings.BILLDESK_ENCRYPTION_KEY
        )

        order_id = data.get("orderid", "")
        order = Orders.objects.get(order_ID=order_id)
        payment = Payment.objects.filter(order=order)

        extract_fields = [
            "bank_ref_no", "bankid", "charge_amount", "currency", "itemcode",
            "payment_category", "payment_method_type", "transaction_error_code",
            "transaction_error_desc", "transaction_error_type", "transactionid",
            "txn_process_type", "surcharge", "amount"
        ]

        # ------------------------------
        # Determine Payment Status
        # ------------------------------
        if data.get("transaction_error_type") == "success":
            payment_status = "Paid"
            template = "payment_success.html"
        else:
            payment_status = "Failed"
            template = "payment_failed2.html"

        # ------------------------------
        # Update payment record
        # ------------------------------
        update_data = {field: data.get(field, "") for field in extract_fields}
        update_data["payment_status"] = payment_status
        payment.update(**update_data)
        checkout_url = f"{settings.domain1}web/"
        if order.platform in ["Flutter_web_app"]:
            checkout_url = f"{settings.domain2}web?token={token}"
        elif order.platform in ["Web" , "Other"]:
            if data.get("transaction_error_type") == "success":
                checkout_url = f"{settings.domain1}order-confirmation"
            else:
                checkout_url = f"{settings.domain1}checkout"
        # ------------------------------
        # If platform = Android or iOS → return JSON
        # ------------------------------
        elif order.platform in ["Android", "IOS"]:
            if payment_status == "Paid":
                return Response({
                    "status": 1,
                    "message": data
                }, status=status.HTTP_200_OK)
            else:
                return Response({
                    "status": 0,
                    "message": "Transaction Failed",
                    "details": data
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # ============================================================
        #   PLATFORM = WEB (or platform query given) → RETURN HTML
        #   Extract token from Authorization header
        # ============================================================

        

        # ------------------------------
        # Render HTML with checkout URL
        # ------------------------------
        return render(request, template, {
            "order_id": order_id,
            "amount": data.get("amount", ""),
            "message": "Payment Successful!" if payment_status == "Paid" else "Payment Failed!",
            "checkout_url": checkout_url,
        })

def calculate_dynamic_delivery_fee(subtotal, distance_km=0):
        settings = DeliverySettings.objects.first()
        if not settings:
            return Decimal('0.0'), "Delivery settings not configured."

        # Convert to Decimal
        distance_km = Decimal(str(distance_km))
        subtotal = Decimal(str(subtotal))

        # Free delivery check
        if (
            settings.free_delivery_max_distance > Decimal('0.0')
            and settings.free_delivery_min_order_value > Decimal('0.0')
            and distance_km <= settings.free_delivery_max_distance
        ):
            if subtotal >= settings.free_delivery_min_order_value:
                return Decimal('0.0'), "Free delivery applied!"
            else:
                remaining = settings.free_delivery_min_order_value - subtotal
                remaining = remaining.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
                return settings.base_fee, f"Add ₹{remaining} more to get free delivery."

        # Standard delivery fee calculation
        base_fee = settings.base_fee
        base_km = settings.base_km
        per_km_fee = settings.per_km_fee

        if distance_km > base_km:
            extra_km = distance_km - base_km
            delivery_fee = base_fee + (per_km_fee * extra_km)
        else:
            delivery_fee = base_fee

        # Apply discount on delivery fee based on order value
        discounts = DeliveryDiscount.objects.order_by('-min_order_value')
        message = ""
        applied_discount = None

        for discount in discounts:
            if subtotal >= discount.min_order_value:
                discount_percent = Decimal(discount.discount_percent) / Decimal('100.0')
                discount_amount = discount_percent * delivery_fee
                delivery_fee -= discount_amount
                applied_discount = discount
                break
        next_discounts = [d for d in discounts if subtotal < d.min_order_value]

        if next_discounts:
            next_discount = next_discounts[-1]  # smallest min_order_value greater than subtotal
            remaining = next_discount.min_order_value - subtotal
            remaining = remaining.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
            message = f"Add ₹{remaining} more to get {next_discount.discount_percent}% off on delivery."
        else:
            # If no higher discount exists, apply the highest discount
            applied_discount = discounts.first()  # The highest discount available
            if applied_discount:
                message = f"{applied_discount.discount_percent}% discount applied on delivery."
            else:
                message = "No delivery discount available."
        return round(delivery_fee, 2)





class CheckoutAPIViewBill(APIView):

    def generate_unique_order_id(self):
        """Generate a unique order ID."""
        while True:
            order_id = f"ID{random.randint(100, 999)}{random.choice(string.ascii_uppercase)}{random.choice(string.ascii_uppercase)}"
            # Ensure order ID is unique by checking if it already exists in the database
            if not Orders.objects.filter(order_ID=order_id).exists():
                return order_id

    def post(self, request, *args, **kwargs):
        try:
            user = request.user
            delivery_mode_id = request.data.get("delivery_mode")
            try:
                payment_mode = PaymentModes.objects.get(id=delivery_mode_id)
            except PaymentModes.DoesNotExist:
                return Response({"status": 0, "message": "Invalid payment mode."}, status=400)

        
            if not user or not user.is_authenticated:
                return Response(
                    {"status": 0, "message": "User not authenticated."},
                    status=status.HTTP_401_UNAUTHORIZED
                )
            ua_string = request.META.get('HTTP_USER_AGENT', '')

            pf_type = request.data.get("platform", None)
            opt_in = request.data.get("opt_in", False)
            additional_info = request.data.get("additional_info", "")
            phone_no = request.data.get("phone_no", "")
           # Convert FormData string → boolean
            if isinstance(opt_in, str):
                opt_in = opt_in.lower() == "true"

            # Update only if changed
            if user.opt_in != opt_in:
                user.opt_in = opt_in
                user.save(update_fields=["opt_in"])

            if pf_type and pf_type == "Flutter Web App":
                platform_data = "Flutter_web_app"
            elif pf_type and pf_type == "Flutter Mobile App":
                platform_data = "Android"
            else:
                user_agent = parse(ua_string)
                logging.info(f"Platform for the user agent string: {ua_string}")
                platform = user_agent.os.family
                logging.info(f"Platform : {platform}")
                platform_data = "Other"
                if platform == 'Windows' or platform == "Mac OS X" or platform == 'Linux' or platform == 'Ubuntu':
                    platform_data = "Web"
                else:
                    platform_data = "Other"
            try:
                cart = get_object_or_404(Cart, user=user)
            except Exception as e:
                return Response(
                    {"status": 0, "message": "Failed to fetch cart.", "exception":traceback.format_exc()},
                    status=status.HTTP_400_BAD_REQUEST
                )
            pickup = request.data.get("pickup", False)
            address = None
            delivery_slot = None
            delivery_slot_date = None
            delivery_slot_time = None
            delivery_instruction = ""
            cooking_instruction = ""
            drop_address = None
            try:
                user_location = get_object_or_404(UserLocation, user=user)
                shop_uuid = user_location.shop
                order_type = "Pick Up" if pickup else "Local Orders"
                if not shop_uuid:
                    order_type = "Long Distance Orders"
                if order_type != "Long Distance Orders":
                    delivery_slot_date = request.data.get("deliver_date")
                    cooking_instruction=request.data.get("cooking_instruction", "")
                    delivery_instruction=request.data.get("delivery_instruction", "")
                    if pickup:
                        delivery_slot_time = request.data.get("pickup_time")
            except Exception as e:
                return Response({"status": 0, "message": "Failed to fetch user location.", "exception": traceback.format_exc()},
                    status=status.HTTP_400_BAD_REQUEST
                )
            # If not a pickup, fetch address and delivery slot details
            if not pickup:
                address_id = request.data.get("address_id")
                if not address_id:
                    return Response(
                        {"status": 0, "message": "Address ID is required for delivery orders."},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                try:
                    address = get_object_or_404(Address, id=address_id)
                except Exception as e:
                    return Response(
                        {"status": 0, "message": "Failed to fetch address.", "exception": traceback.format_exc()},
                        status=status.HTTP_400_BAD_REQUEST
                    )
                pickup_pincode = ProductionUnit.objects.values_list("pin_code", flat=True).first()
                latitude = address.latitude
                longitude = address.longitude
                address_pin_code = get_pincode_from_latlng(latitude, longitude)
                loc_details = get_full_address_from_latlng(latitude, longitude)
                street = loc_details["street"] or "street"
                city = loc_details["city"] or "city"
                state = loc_details["state"] or "state"
                if not address_pin_code:
                    return Response(
                        {
                            "status": 0,
                            "message": "Pincode not available for this address"
                        },
                        status=400
                    )

                drop_address = Dropaddress.objects.create(
                    name=f"{user.first_name} {user.last_name}",
                    house_number_or_name=address.flat_no,
                    land_mark=address.landmark,
                    street=street,
                    city=city,
                    state_or_province=state,
                    pin_code=int(address_pin_code),   # ✅ now safe
                    latitude=address.latitude,
                    longitude=address.longitude,
                    address_type=address.address_type,
                    contact_number=user.phone_number,
                )
            if order_type == "Local Orders":
                delivery_slot_id = request.data.get("delivery_slot")
                delivery_slot = get_object_or_404(DeliverySlot, id=delivery_slot_id)
                delivery_slot_time = delivery_slot.start_time
            # Generate order ID
            try:
                order_id = self.generate_unique_order_id()
            except ValueError as e:
                return Response(
                    {"status": 0, "message": "Failed to generate order ID.", "exception": str(e)},
                    status=status.HTTP_400_BAD_REQUEST
                )
            try:
                cart_mixin = CartViewMixin()
                cart_response = cart_mixin.get_cart_items_response(cart, "Cart data fetched successfully")
                price_data = cart_response.data["price_data"]
                long_distance_charges = cart_response.data["long_distance_charges"]
                subtotal = price_data["subtotal"]
                taxes_and_charges = price_data["taxes_and_charges"]
                discount = price_data["discount"]
                total_savings = price_data["total_savings"]
                coupon_savings = price_data["coupon_savings"]
                grand_total = price_data["grand_total"]
                delivery_fee = price_data["delivery_fee"]
                total_without_delivery = price_data["total_without_delivery"]
                cart_weight = long_distance_charges["cart_weight"]
                cod_surface_delivery_fee = long_distance_charges["delivery_fee_cod_surface"]
                cod_express_delivery_fee = long_distance_charges["delivery_fee_cod_express"]
                online_surface_delivery_fee = long_distance_charges["delivery_fee_online_surface"]
                online_express_delivery_fee = long_distance_charges["delivery_fee_online_express"]
                if  order_type == "Pick Up":
                    grand_total = float(grand_total) - float(delivery_fee)
                    delivery_fee = 0.0
                if order_type == "Long Distance Orders":
                    delivery_mode = request.data.get("longdistance_delivery_mode")
                    if payment_mode.id == 1:
                        if delivery_mode == "S":
                            longdistance_delivery_fee = cod_surface_delivery_fee
                        elif delivery_mode == "E":
                            longdistance_delivery_fee = cod_express_delivery_fee
                    else:
                        if delivery_mode == "S":
                            longdistance_delivery_fee = online_surface_delivery_fee
                        elif delivery_mode == "E":
                            longdistance_delivery_fee = online_express_delivery_fee
                    grand_total = float(total_without_delivery) + float(longdistance_delivery_fee)
                    delivery_fee = longdistance_delivery_fee

            except (KeyError, TypeError) as e:
                return Response(
                    {"status": 0, "message": "Failed to fetch cart price data.", "exception": str(e)},
                    status=status.HTTP_400_BAD_REQUEST
                )

            # Create order and process BillDesk payment
            with transaction.atomic():
                try:
                    # Create order
                    order = Orders.objects.create(
                        order_ID=order_id,
                        order_type=order_type,
                        order_status="New Order",
                        user_uuid=user,
                        drop_address=drop_address if drop_address else None,
                        delivery_instruction=delivery_instruction,
                        cooking_instruction=cooking_instruction,
                        delivery_slot_date=delivery_slot_date,
                        delivery_slot_time=delivery_slot_time,
                        grand_total=round(grand_total, 2),
                        taxes_and_charges=taxes_and_charges,
                        delivery_charges=delivery_fee,
                        sub_total=subtotal,
                        total_savings=total_savings,
                        coupon_savings=coupon_savings,
                        discount=discount,
                        color_status="White",
                        color_status_updation_time=datetime.now(),
                        platform=platform_data,
                        payment_mode=payment_mode

                    )
                    # check_and_verify_order_status.apply_async((order.order_ID,), countdown=300)

                    # Update SomeOneElse if exists
                    try:
                        some_one_else = SomeOneElse.objects.filter(cart=cart).first()
                        if some_one_else:
                            some_one_else.orders = order
                            some_one_else.save()
                    except Exception as e:
                        return Response(
                            {"status": 0, "message": "Failed to update SomeOneElse.", "exception": str(e)},
                            status=status.HTTP_400_BAD_REQUEST
                        )

                    # Assign store or production unit
                    try:
                        if order.order_type in ["Local Orders", "Pick Up"]:
                            order.store_uuid = shop_uuid
                        elif order.order_type == "Long Distance Orders":
                            Delhivery.objects.create(order=order, weight_grams = cart_weight , mode = delivery_mode ,payment_mode =payment_mode.mode_name)
                            pu = ProductionUnit.objects.first()
                            if not pu:
                                raise ValueError("No production unit found for long distance order")
                            order.pu_uuid = pu
                        order.save()
                    except Exception as e:
                        return Response(
                            {"status": 0, "message": "Failed to assign store or production unit.", "exception": str(e)},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                    try:
                        additional_infos = AdditionalDetails.objects.create(order=order)
                        additional_infos.additional_info =  additional_info
                        additional_infos.mobile_number = phone_no
                        additional_infos.save()
                    except Exception as e:
                        return Response(
                            {"status": 0, "message": "Failed to save additional details.", "exception": str(e)},
                            status=status.HTTP_400_BAD_REQUEST
                        )
                    try:
                        for cart_item in cart.items.all():
                            sku = cart_item.sku

                            # If item has customizations
                            if cart_item.customizations.exists():

                                # One OrderProduct per customization
                                for customization in cart_item.customizations.all():

                                    order_product = OrderProducts.objects.create(
                                        product_name=sku.product.item_name,
                                        order=order,
                                        sku=sku,
                                        quantity=1,            # ALWAYS 1 for customized items
                                        price=sku.sku_mrp,    # single item price
                                    )

                                    OrderProductCustomization.objects.create(
                                        order_product=order_product,
                                        custom_note=customization.custom_note,
                                        custom_image=customization.custom_image 
                                            if customization.custom_image else None,
                                        custom_image_id=customization.custom_image_id,
                                    )

                                # CASE: user ordered 2 qty, but only 1 qty has customization
                                customized_count = cart_item.customizations.count()
                                remaining_qty = int(cart_item.quantity) - customized_count

                                if remaining_qty > 0:
                                    # SAVE REMAINING NON-CUSTOMIZED ITEMS AS ONE PRODUCT WITH QTY
                                    OrderProducts.objects.create(
                                        product_name=sku.product.item_name,
                                        order=order,
                                        sku=sku,
                                        quantity=remaining_qty,
                                        price=sku.sku_mrp * remaining_qty,
                                    )

                            else:
                                # Completely non-customized item
                                OrderProducts.objects.create(
                                    product_name=sku.product.item_name,
                                    order=order,
                                    sku=sku,
                                    quantity=cart_item.quantity,
                                    price=sku.sku_mrp * cart_item.quantity,
                                )

                    except Exception as e:
                        return Response(
                            {
                                "status": 0,
                                "message": "Failed to create order products.",
                                "exception": str(e),
                            },
                            status=status.HTTP_400_BAD_REQUEST,
                        )
                    
                    if payment_mode.id == 1:
                        
                        Payment.objects.create(
                            order=order,
                            payment_status="pending",
                            bill_desk_order_id=None,
                            amount=str(grand_total),
                            payment_method_type="COD",
                        )
                        order.order_status = "Confirmed"
                        order.save()
                        if order.order_type != "Long Distance Orders":
                            order_confirmed.send(
    sender="Order Creation",
    order_id=order.order_ID,
    store_id=order.store_uuid.uuid,
    platform=platform_data,
    order_type=order.order_type
)
                        else:
                            order_confirmed.send(
    sender="Order Creation",
    order_id=order.order_ID,
    store_id=order.pu_uuid.uuid,
    platform=platform_data,
    order_type=order.order_type
)

                        temp_name ='order_confirmation_general'
                        title = "Your Order is Confirmed 🎉"

                        description = f"""Hi {order.user_uuid.first_name},
                        Your order {order.order_ID} has been successfully confirmed.
                        We’ve started processing it and will keep you updated on the next steps.
                        Thank you for choosing Navya Bakers!"""
                        NotificationInit(order.user_uuid.fcm_token, order, title, description, order.user_uuid)
                        EmailSend(title, description, [order.user_uuid.email], False)
                        if order.user_uuid.opt_in == True:
                            send_whatsapp_message.apply_async(args=[order.user_uuid.phone_number, order.order_ID, order.user_uuid.first_name, temp_name], countdown=2 )
                        if order.store_uuid:
                            shop_name = order.store_uuid.unit_name
                            phone_number = order.store_uuid.contact_no
                        else:
                            shop_name = order.pu_uuid.pu_name
                            phone_number = order.pu_uuid.contact_no

                        grand_total = order.grand_total
                        payment_method = order.payment_mode.mode_name

                        delivery_time = "N/A"

                        if order.delivery_slot_time and order.delivery_slot_date:

                            slot = DeliverySlot.objects.filter(
                                start_time=order.delivery_slot_time
                            ).first()

                            if slot:

                                # Convert string to date object if needed
                                if isinstance(order.delivery_slot_date, str):
                                    delivery_date_obj = datetime.strptime(
                                        order.delivery_slot_date,
                                        "%Y-%m-%d"
                                    )
                                else:
                                    delivery_date_obj = order.delivery_slot_date

                                delivery_date = delivery_date_obj.strftime("%d %b %Y")

                                start_time = slot.start_time.strftime("%I:%M %p")
                                end_time = slot.end_time.strftime("%I:%M %p")

                                delivery_time = (
                                    f"{delivery_date} | "
                                    f"{start_time} - {end_time}"
                                )
                        delivery_mode =order.order_type
                        if delivery_mode == "Local Orders":
                            delivery_mode = "Home Delivery"
                            if order.drop_address:
                                d = order.drop_address
                                drop_address = (
                                    f"{d.name}, {d.house_number_or_name}, {d.street}, "
                                    f"{d.city}, {d.state_or_province} - {d.pin_code}"
                                )
                        else:
                            drop_address = "N/A"
                        logging.info(f"Scheduling WhatsApp message for order {order.order_ID} to {phone_number} for shop {shop_name} with delivery mode {delivery_mode} and delivery time {delivery_time}")
                        send_whatsapp_order_message.apply_async(args=[phone_number, shop_name, order.order_ID, order.user_uuid.first_name, order.user_uuid.phone_number, drop_address, grand_total, payment_method, delivery_mode, delivery_time], countdown=2 )    
                        try:
                            cart = Cart.objects.get(user=user)
                            logging.info(f"The cart value is {cart}")
                            cart.delete()
                        except Cart.DoesNotExist:
                            logging.info("No cart found for user, skipping cart deletion")
                        if order.order_type != "Long Distance Orders":
                                return Response(
                                    {
                                    "status": 1,
                                    "message": "Order placed successfully with COD.",
                                    "data": {
                                        "order_id": order.order_ID,
                                        "amount": grand_total,
                                        "payment_mode": payment_mode.id,
                                        "order_details": OrderSerializer(order).data,
                                    }
                                }, status=201)
                        else:
                            return Response(
                                {
                                "status": 1,
                                "message": "Order placed successfully with COD.",
                                "data": {
                                    "order_id": order.order_ID,
                                    "amount": grand_total,
                                    "payment_mode": payment_mode.id,
                                    "order_details": OrderSerializer2(order).data,
                                }
                            }, status=201)
                    elif payment_mode.id == 2:
                          
                            Payment.objects.create(
                                order=order,
                                payment_status="pending",
                                payment_method_type="Online Payment",
                                amount=str(grand_total),
                            )
                            

                            # ---- PayU credentials ----
                            payu_key = "oEOB0P"
                            payu_salt = "IJB9iqgsiUw879xSB1XGfqSM3hzDSaO7"

                            # ---- PayU required fields ----
                            txnid = order.order_ID
                            split1= grand_total 
                            amount = f"{Decimal(grand_total):.2f}"
                            productinfo = "Navya Bakers Order "
                            firstname = user.first_name or ""
                            email = user.email or ""

                            
 
                            phone = user.phone_number.replace("+", "").strip()[-10:]
                            auth_header = request.headers.get("Authorization", "")
                            token = None
                            if auth_header.startswith("Token "):
                                token = auth_header.split("Token ")[1].strip()
                            if not token:
                                surl = f"{settings.DOMAIN}orders/payu/return/"
                                furl = f"{settings.DOMAIN}orders/payu/return/"
                            else:
                                surl = f"{settings.DOMAIN}orders/payu/return/?token={token}"
                                furl = f"{settings.DOMAIN}orders/payu/return/?token={token}"

                            # # ---- SPLIT REQUEST (Sub-Merchant Config) ----
                            # split_request = {
                            #     "type": "absolute",
                            #     "splitInfo": {
                            #         "X4Y55z": {  # Sub-merchant key 1
                            #             "aggregatorSubTxnId": f"{txnid}_1",
                            #             "aggregatorSubAmt": f"{amount}",
                            #             "aggregatorCharges": "0.00"
                            #         },
                            #     }
                            # }
                            # split_request_str = json.dumps(split_request, separators=(",", ":"))

                            # # ---- HASH GENERATION (FOR SPLIT PAYMENT) ----
                            # hash_string = (
                            #     f"{payu_key}|{txnid}|{amount}|{productinfo}|"
                            #     f"{firstname}|{email}|||||||||||{payu_salt}|{split_request_str}"
                            # )
                            productinfo = "Navya Bakers Order"

                            split_request = {
                                "type": "absolute",
                                "splitInfo": {
                                    "X4Y55z": {
                                        "aggregatorSubTxnId": f"{txnid}_1",
                                        "aggregatorSubAmt": amount,
                                        "aggregatorCharges": "0.00"
                                    }
                                }
                            }

                            split_request_str = json.dumps(split_request, separators=(",", ":"))

                            hash_string = (
                                f"{payu_key}|{txnid}|{amount}|{productinfo}|"
                                f"{firstname}|{email}|||||||||||{payu_salt}|{split_request_str}"
                            )

                            

                            # ---- HASH GENERATION (FOR SPLIT PAYMENT) ----
                            # hash_string = (
                            #     f"{payu_key}|{txnid}|{amount}|{productinfo}|"
                            #     f"{firstname}|{email}|||||||||||{payu_salt}"
                            # )

                            payu_hash = hashlib.sha512(hash_string.encode("utf-8")).hexdigest()
                            assert len(payu_hash) == 128
                            # ---- Redirect to PayU ----
                            params = {
                                "key": payu_key,
                                "txnid": txnid,
                                "amount": amount,
                                "productinfo": productinfo,
                                "firstname": firstname or "",
                                "email": email or "",
                                "phone": phone,
                                "surl": surl,
                                "furl": furl,
                                "hash": payu_hash,
                                "splitRequest": split_request_str,
                                "hash_string": hash_string,
                            }

                            # Only if absolutely required
                            if platform_data and platform_data.lower() in ["android", "ios"]:
                                params["salt"] = payu_salt  # ⚠️ not recommended

                            return Response({
                                "status": 1,
                                "message": "PayU payment initiated",
                                "payu_url": "https://test.payu.in/_payment",
                                "params": params,
                            }, status=200)
                        
                    else:
                        return Response(
                            {"status": 0, "message": "Invalid payment mode."})

                except Exception as e:
                    return Response(
                        {"status": 0, "message": "Failed to create order.", "exception": str(e)},
                        status=status.HTTP_400_BAD_REQUEST
                    )

        except Exception as e:
            return Response(
                {"status": 0, "message": "An unexpected error occurred.", "exception": str(e)},
                status=status.HTTP_400_BAD_REQUEST
            )
        
from django.utils.decorators import method_decorator

@method_decorator(csrf_exempt, name="dispatch")
class PayUWebhook(APIView):
    authentication_classes = []
    permission_classes = []

    def post(self, request, event):
        event = event.lower().strip()
        if event in ["successful", "success", "sucess"]:
            event = "success"
        elif event in ["failed", "failure"]:
            event = "failed"

        data = request.data
        txnid = data.get("txnid")

        order = Orders.objects.filter(order_ID=txnid).first()
        if not order:
            return Response({"error": "Order not found"}, status=200)

        payment = Payment.objects.filter(order=order).first()
        if not payment:
            return Response({"error": "Payment not found"}, status=200)

        if event == "success":
            payment.payment_status = "Paid"
            order.order_status = "Confirmed"
        elif event == "failed":
            payment.payment_status = "Failed"
            order.order_status = "Payment Failed"
        elif event == "refund":
            payment.payment_status = "Refunded"
        payment.save()
        order.save()

        return Response({"status": "OK"}, status=200)

class PayUPaymentResultAPIView(APIView):
    authentication_classes = []
    permission_classes = []

    def post(self, request, *args, **kwargs):

        data = request.data
        txnid = data.get("txnid")
        payu_status = data.get("status")
        logging.info(f"PayU Return | txnid={txnid} | status={payu_status}")

        order = Orders.objects.filter(order_ID=txnid).first()
        if not order:
            return Response({"error": "Order not found"}, status=404)
        payment = Payment.objects.filter(order=order).first()

        if payment:
            if payu_status == "success":
                payment.payment_status = "Paid"
                order.order_status = "Confirmed"
            else:
                payment.payment_status = "Failed"
                order.order_status = "Payment Failed"

            payment.save()
            order.save()

        token = request.GET.get("token")
        platform_type = order.platform or "Other"

        # Mobile Apps
        if platform_type in ["Android", "IOS"]:
            return Response({
                "status": 1 if payu_status == "success" else 0,
                "order_id": txnid,
                "message": "Payment processed"
            })

        # 🔹 IMPORTANT: Always render HTML for web & flutter web
        return render(request, "payment_processing.html", {
            "order_id": txnid,
            "platform_type": platform_type,
            "token": token
        })
    

# @method_decorator(csrf_exempt, name="dispatch")
# class PayUWebhook(APIView):
#     authentication_classes = []
#     permission_classes = []

#     def post(self, request, event):

#         data = request.data

#         received_hash = data.get("hash")
#         status = data.get("status")

#         txnid = data.get("txnid")
#         amount = data.get("amount")
#         productinfo = data.get("productinfo")
#         firstname = data.get("firstname")
#         email = data.get("email")

#         split_request = data.get("splitRequest") or ""

#         # 🔁 Reverse hash
#         reverse_hash_string = (
#             f"{payu_salt}|{status}|||||||||||{email}|{firstname}|"
#             f"{productinfo}|{amount}|{txnid}|{payu_key}|{split_request}"
#         )

#         generated_hash = hashlib.sha512(reverse_hash_string.encode()).hexdigest()

#         # ❌ Reject if hash mismatch
#         if generated_hash != received_hash:
#             return Response({"error": "Invalid hash"}, status=400)

#         # ✅ Only then update DB
#         order = Orders.objects.filter(order_ID=txnid).first()
#         if not order:
#             return Response({"error": "Order not found"}, status=200)

#         payment = Payment.objects.filter(order=order).first()
#         if not payment:
#             return Response({"error": "Payment not found"}, status=200)

#         if status == "success":
#             payment.payment_status = "Paid"
#             order.order_status = "Confirmed"
#         else:
#             payment.payment_status = "Failed"
#             order.order_status = "Payment Failed"
        

#         payment.save()
#         order.save()

#         return Response({"status": "OK"}, status=200)

# class PayUPaymentResultAPIView(APIView):
#     authentication_classes = []
#     permission_classes = []

#     def post(self, request, *args, **kwargs):

#         data = request.data

#         txnid = data.get("txnid")
#         status = data.get("status")
#         received_hash = data.get("hash")

#         amount = data.get("amount")
#         productinfo = data.get("productinfo")
#         firstname = data.get("firstname")
#         email = data.get("email")
#         split_request = data.get("splitRequest") or ""
        
#         logging.info(f"[PayU RETURN] txnid={txnid} status={status}")

#         order = Orders.objects.filter(order_ID=txnid).first()
#         if not order:
#             return Response({"error": "Order not found"}, status=404)

#         payment = Payment.objects.filter(order=order).first()
#         if not payment:
#             return Response({"error": "Payment not found"}, status=404)

#         # ✅ Get stored splitRequest (DO NOT TRUST PAYU FOR THIS)
        

#         # 🔁 Reverse Hash
#         reverse_hash_string = (
#             f"{payu_salt}|{status}|||||||||||{email}|{firstname}|"
#             f"{productinfo}|{amount}|{txnid}|{payu_key}|{split_request}"
#         )

#         generated_hash = hashlib.sha512(
#             reverse_hash_string.encode("utf-8")
#         ).hexdigest()

#         # ❌ Reject if invalid
#         if generated_hash != received_hash:
#             logging.error(f"[HASH MISMATCH] txnid={txnid}")
#             return Response({"error": "Invalid hash"}, status=400)

#         # ✅ Update DB (optional - webhook is primary)
#         if status == "success":
#             payment.payment_status = "Paid"
#             order.order_status = "Confirmed"
#         else:
#             payment.payment_status = "Failed"
#             order.order_status = "Payment Failed"

#         payment.save()
#         order.save()

#         token = request.GET.get("token")
#         platform_type = order.platform or "Other"

#         # Mobile
#         if platform_type in ["Android", "IOS"]:
#             return Response({
#                 "status": 1 if status == "success" else 0,
#                 "order_id": txnid,
#                 "message": "Payment processed"
#             })

#         # Web
#         return render(request, "payment_processing.html", {
#             "order_id": txnid,
#             "platform_type": platform_type,
#             "token": token
#         })
    
class OrderPaymentStatusAPIView(APIView):
    authentication_classes = []
    permission_classes = []
    def get(self, request, order_id):
        order = Orders.objects.filter(order_ID=order_id).first()
        if not order:
            return Response({"error": "Order not found"}, status=404)
        payment = Payment.objects.filter(order=order).first()
        if not payment:
            return Response({"payment_status": "Pending"})
        return Response({
            "order_id": order_id,
            "payment_status": payment.payment_status
        })



PAYU_VERIFY_URL = "https://test.payu.in/merchant/postservice?form=2"

payu_key = "oEOB0P"
payu_salt = "IJB9iqgsiUw879xSB1XGfqSM3hzDSaO7"
class VerifyPayUPaymentAPIView(APIView):
    """
    Verify PayU payment and update DB immediately.
    """

    def post(self, request):
        txnid = request.data.get("order_id")

        if not txnid:
            return Response(
                {"status": 0, "message": "txnid is required"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        try:
            order = Orders.objects.get(order_ID=txnid)
            payment = Payment.objects.get(order=order)
        except Orders.DoesNotExist:
            return Response(
                {"status": 0, "message": "Order not found"},
                status=status.HTTP_404_NOT_FOUND,
            )
        except Payment.DoesNotExist:
            return Response(
                {"status": 0, "message": "Payment record not found"},
                status=status.HTTP_404_NOT_FOUND,
            )

        # ------------------------------
        # IDEMPOTENCY
        # ------------------------------
        if payment.payment_status == "paid":
            return Response(
                {
                    "status": 1,
                    "message": "Payment already successful",
                    "order_status": order.order_status,
                },
                status=status.HTTP_200_OK,
            )

        try:
            # ------------------------------
            # PAYU VERIFY CALL
            # ------------------------------
            hash_string = (
                f"{payu_key}|verify_payment|{txnid}|{payu_salt}"
            )
            hash_value = hashlib.sha512(hash_string.encode()).hexdigest()

            payload = {
                "key": payu_key,
                "command": "verify_payment",
                "var1": txnid,
                "hash": hash_value,
            }

            response = requests.post(
                PAYU_VERIFY_URL,
                data=payload,
                timeout=15
            )
            response.raise_for_status()

            data = response.json()
            logging.info(f"[PayU VERIFY] txnid={txnid} response={data}")

            tx_data = data.get("transaction_details", {}).get(txnid)

            # ------------------------------
            # PAYMENT NOT INITIATED
            # ------------------------------
            if not tx_data:
                return Response(
                    {
                        "status": 0,
                        "payment_status": "pending",
                        "order_status": order.order_status,
                        "message": "Payment not initiated or abandoned",
                        "can_retry": True,
                    },
                    status=status.HTTP_200_OK,
                )

            payu_status = tx_data.get("status")  # success / failure
            unmapped = (tx_data.get("unmappedstatus") or "").lower()
            cancel_msg = tx_data.get("field9") or "Payment cancelled by user"

            # ------------------------------
            # USER CANCELLED
            # ------------------------------
            if payu_status == "failure" and unmapped == "usercancelled":
                with transaction.atomic():
                    payment.payment_status = "failed"
                    payment.auth_status = "userCancelled"
                    payment.transaction_error_desc = cancel_msg
                    payment.transaction_error_code = tx_data.get("error_code")
                    payment.save(update_fields=[
                        "payment_status",
                        "auth_status",
                        "transaction_error_desc",
                        "transaction_error_code",
                    ])

                    order.order_status = "Cancelled"
                    order.message = cancel_msg
                    order.save(update_fields=[
                        "order_status",
                        "message",
                    ])

                return Response(
                    {
                        "status": 1,
                        "payment_status": "failed",
                        "order_status": "Cancelled",
                        "failure_reason": "USER_CANCELLED",
                        "message": "Payment cancelled by user",
                        "can_retry": True,
                    },
                    status=status.HTTP_200_OK,
                )

            # ------------------------------
            # PAYMENT SUCCESS
            # ------------------------------
            if payu_status == "success":
                with transaction.atomic():
                    payment.payment_status = "paid"
                    payment.transactionid = tx_data.get("mihpayid")
                    payment.bank_ref_no = tx_data.get("bank_ref_num")
                    payment.amount = tx_data.get("amt")
                    payment.save(update_fields=[
                        "payment_status",
                        "transactionid",
                        "bank_ref_no",
                        "amount",
                    ])

                    order.order_status = "Confirmed"
                    order.save(update_fields=["order_status"])

                return Response(
                    {
                        "status": 1,
                        "payment_status": "paid",
                        "order_status": "Confirmed",
                        "message": "Payment successful",
                    },
                    status=status.HTTP_200_OK,
                )

            # ------------------------------
            # OTHER FAILURE (BANK / TECH)
            # ------------------------------
            with transaction.atomic():
                payment.payment_status = "failed"
                payment.transaction_error_desc = tx_data.get("error_Message")
                payment.transaction_error_code = tx_data.get("error_code")
                payment.save(update_fields=[
                    "payment_status",
                    "transaction_error_desc",
                    "transaction_error_code",
                ])

                order.order_status = "Failed"
                order.save(update_fields=["order_status"])

            return Response(
                {
                    "status": 1,
                    "payment_status": "failed",
                    "order_status": "Failed",
                    "message": "Payment failed",
                    "can_retry": True,
                },
                status=status.HTTP_200_OK,
            )

        except Exception as e:
            logging.exception("[PayU VERIFY] Unexpected error")
            return Response(
                {
                    "status": 0,
                    "message": "Failed to verify PayU payment",
                    "error": str(e),
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR,
            )


def delivery_confirm_page(request, order_uuid):

    order = Orders.objects.filter(uuid=order_uuid).first()


    # Prevent confirming delivery again
    if order.order_status == "Delivered":
        return render(request, "delivery_error.html", {
            "error": "Order already delivered"
        })

    user = order.user_uuid

    # Customer name
    customer_name = ""
    if user:
        customer_name = f"{user.first_name} {user.last_name or ''}".strip()

    # Fetch customer address
    address = ""
    customer_address = Address.objects.filter(user=user).first()

    if customer_address:
        address = f"{customer_address.flat_no}, {customer_address.landmark or ''}"

    context = {
        "order_uuid": order.uuid,
        "order_id": order.order_ID,
        "customer_name": customer_name,
        "address": address,
    }

    return render(request, "delivery_confirm.html", context)


def delivery_success(request):
    return render(request, "delivery_success.html")

def delivery_failed(request):
    return render(request, "delivery_failed.html")


# import json
# from django.http import JsonResponse
# from django.views.decorators.csrf import csrf_exempt
# from django.utils import timezone

# @csrf_exempt
# def delhivery_webhook(request):
#     if request.method == "POST":
#         try:
#             data = json.loads(request.body)

#             waybill = data.get("waybill")
#             status = data.get("status")
#             if not waybill:
#                 return JsonResponse({"status": 0, "message": "Missing waybill"}, status=400)
            
#             delhivery_obj = Delhivery.objects.filter(awb_number=waybill).first()
#             if not delhivery_obj:
#                 return JsonResponse({"status": 0, "message": "Shipment not found"}, status=404)

#             if status:
#                 delhivery_obj.status = status
#                 if status == "Delivered" and not delhivery_obj.delivered_date:
#                     delhivery_obj.delivered_date = timezone.now()
#                 delhivery_obj.save()

#             if status == "Delivered":
#                 order = delhivery_obj.order
#                 if order.order_status != "Delivered":
#                     order.order_status = "Delivered"
#                     order.order_delivered_time = timezone.now()
#                     order.save(update_fields=["order_status", "order_delivered_time"])
#             return JsonResponse({"status": 1, "message": "Webhook processed"})
#         except Exception as e:
#             return JsonResponse({"status": 0, "message": "Error"}, status=500)
#     return JsonResponse({"error": "Invalid request"}, status=400)



# from rest_framework.decorators import api_view
# from rest_framework.response import Response
# from rest_framework import status
# import requests
# import logging

# from rest_framework.decorators import api_view
# from rest_framework.response import Response
# from rest_framework import status
# import requests
# import logging
# import traceback

# @api_view(["POST"])
# def get_delhivery_charge(request):

#     try:

#         mode = request.data.get("mode")
#         pickup_pin = request.data.get("pickup_pin")
#         drop_pin = request.data.get("drop_pin")
#         cart_weight = request.data.get("cart_weight")
#         pt = request.data.get("pt")

#         # -------------------------
#         # Validation
#         # -------------------------
#         if not all([mode, pickup_pin, drop_pin, cart_weight, pt]):

#             logging.error(
#                 f"Missing required fields | "
#                 f"mode={mode}, pickup_pin={pickup_pin}, "
#                 f"drop_pin={drop_pin}, cart_weight={cart_weight}, pt={pt}"
#             )

#             return Response(
#                 {
#                     "success": False,
#                     "message": "Missing required fields"
#                 },
#                 status=status.HTTP_400_BAD_REQUEST
#             )

#         url = "https://staging-express.delhivery.com/api/kinko/v1/invoice/charges/.json"

#         params = {
#             "md": mode,
#             "ss": "Delivered",
#             "d_pin": str(drop_pin),
#             "o_pin": str(pickup_pin),
#             "cgm": int(cart_weight),
#             "pt": pt
#         }

#         logging.info(f"Delhivery Request Params: {params}")

#         response = requests.get(
#             url,
#             params=params,
#             headers={
#                 "Authorization": f"Token {settings.DELHIVERY_API_KEY}"
#             },
#             timeout=(3, 5)
#         )

#         logging.info(
#             f"Delhivery Charge API | URL: {response.url} | "
#             f"Status: {response.status_code} | "
#             f"Response: {response.text}"
#         )

#         # -------------------------
#         # Handle non-200 response
#         # -------------------------
#         if response.status_code != 200:

#             logging.error(
#                 f"Delhivery API HTTP Error | "
#                 f"Status={response.status_code} | "
#                 f"Response={response.text}"
#             )

#             return Response(
#                 {
#                     "success": False,
#                     "message": "Delhivery API failed",
#                     "status_code": response.status_code,
#                     "response": response.text
#                 },
#                 status=status.HTTP_400_BAD_REQUEST
#             )

#         data = response.json()

#         logging.info(f"Parsed Delhivery Response: {data}")

#         total_amount = 0

#         # -------------------------
#         # Handle list response
#         # -------------------------
#         if isinstance(data, list):

#             logging.info("Delhivery response type: LIST")

#             if len(data) > 0:
#                 total_amount = float(data[0].get("total_amount", 0))

#         # -------------------------
#         # Handle dict response
#         # -------------------------
#         elif isinstance(data, dict):

#             logging.info("Delhivery response type: DICT")

#             if data.get("error"):

#                 logging.error(
#                     f"Delhivery API Business Error | "
#                     f"Response={data}"
#                 )

#                 return Response(
#                     {
#                         "success": False,
#                         "message": data.get("rmk", "Delhivery API error"),
#                         "data": data
#                     },
#                     status=status.HTTP_400_BAD_REQUEST
#                 )

#             total_amount = float(data.get("total_amount", 0))

#         logging.info(f"Calculated delivery charge: {total_amount}")

#         return Response(
#             {
#                 "success": True,
#                 "delivery_charge": total_amount,
#                 "drop_pin": drop_pin,
#                 "pickup_pin": pickup_pin,
#                 "cart_weight": cart_weight,
#                 "mode": mode,
#                 "data": data
#             },
#             status=status.HTTP_200_OK
#         )

#     except requests.exceptions.RequestException as e:

#         stack_trace = traceback.format_exc()

#         logging.error(
#             f"Delhivery Request Exception\n"
#             f"Error: {str(e)}\n"
#             f"Stack Trace:\n{stack_trace}"
#         )

#         return Response(
#             {
#                 "success": False,
#                 "message": "Delhivery API request failed",
#                 "error": str(e),
#                 "stack_trace": stack_trace
#             },
#             status=status.HTTP_500_INTERNAL_SERVER_ERROR
#         )

#     except Exception as e:

#         stack_trace = traceback.format_exc()

#         logging.error(
#             f"Unexpected Exception\n"
#             f"Error: {str(e)}\n"
#             f"Stack Trace:\n{stack_trace}"
#         )

#         return Response(
#             {
#                 "success": False,
#                 "message": "Something went wrong",
#                 "error": str(e),
#                 "stack_trace": stack_trace
#             },
#             status=status.HTTP_500_INTERNAL_SERVER_ERROR
#         )