from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from django.db.models import Q, Count

from orders.models import *
from .models import (
    CustomProduct,
    CustomProductImage,
    CustomProductVideo,
    DynamicFiltering,
    ProductCategory,
    ProductReview,
    SalesUnitProductSelection,
    Products,
    SKU,
    ProductImage,
    SpecialList,
    Tags,
    Wishlist,
)
from .serializers import ProductCategorySerializer  # Create this serializer
import googlemaps
from shops.models import Shop
from accounts.models import UserLocation
from django.shortcuts import get_object_or_404
from django.db.models import Q


class CategoryListView(APIView):
    """
    View for listing product categories.
    """

    def get(self, request):
        categories = ProductCategory.objects.all()
        serializer = ProductCategorySerializer(categories, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)


class ProductListView(APIView):
    def post(self, request):
        category_code = request.data.get("category_code")
        tag_ids = request.data.get("tag_ids", [])
        dynamic_filter_ids = request.data.get("dynamic_filter_ids", [])

        try:
            if request.user.is_authenticated:
                user_location = UserLocation.objects.filter(user=request.user).first()
                wishlist_items = Wishlist.objects.filter(user=request.user).values_list('product', flat=True)
            else:
                anonymous_id = request.data.get("anonymous_id")
                user_location = UserLocation.objects.filter(
                    anonymous_id=anonymous_id
                ).first()

            results = []

            if user_location and user_location.shop:
                # Shop found; use 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
                }

                if category_code:
                    products = Products.objects.filter(
                        item_category__category_code=category_code
                    )
                else:
                    products = Products.objects.all()

            else:
                # If no user location (shop), apply expiry date logic
                if category_code:
                    products = Products.objects.filter(
                        item_category__category_code=category_code,
                        skus__sku_expiry_duration__gt=30,
                    ).distinct()
                else:
                    products = Products.objects.filter(
                        skus__sku_expiry_duration__gt=30
                    ).distinct()

            products = products.filter(
                skus__sku_status__in=["Visible", "Out of Stock"]
            ).distinct()

            tags_list = Tags.objects.filter(products__in=products).distinct()
            dynamic_filters_list = DynamicFiltering.objects.filter(
                products__in=products
            ).distinct()

            if tag_ids:
                tags = Tags.objects.filter(id__in=tag_ids)
                products = products.filter(tags__in=tags).distinct()
            if dynamic_filter_ids:
                dynamic_filters = DynamicFiltering.objects.filter(
                    id__in=dynamic_filter_ids
                )
                products = products.filter(
                    dynamicfiltering__in=dynamic_filters
                ).distinct()

            subcategory_dict = {}

            # Fetch applicable discounts for shop-based products
            discounts = (
                Discount.objects.filter(
                    Q(
                        DiscountOn="Category",
                        ApplicableCategory__in=products.values_list(
                            "item_category", flat=True
                        ),
                    )
                )
                | Discount.objects.filter(
                    Q(
                        DiscountOn="SubCategory",
                        ApplicableSubCategory__in=products.values_list(
                            "item_sub_category", flat=True
                        ),
                    )
                )
                | Discount.objects.filter(
                    Q(DiscountOn="Product", ApplicableProduct__in=products)
                )
                | Discount.objects.filter(
                    Q(
                        DiscountOn="Sku",
                        ApplicableSku__in=SKU.objects.filter(product__in=products),
                    )
                )
            )

            for product in products:
                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,
                    )
                if skus.exists():
                    # Get one product image (if available)
                    product_images = ProductImage.objects.filter(product=product)
                    product_image_url = product_images.first().image.url if product_images.exists() else None  # type: ignore

                    first_sku = (
                        skus.filter(sku_status="Visible").first()
                        or skus.filter(sku_status="Out of Stock").first()
                    )
                    if first_sku:
                        sku_mrp = first_sku.sku_mrp
                        price = f"{sku_mrp:.2f}"
                        sku_name = first_sku.sku_name
                        sku_quantity = first_sku.sku_quantity
                        sku_unit = first_sku.sku_unit

                    # Check if any discount applies
                    applicable_discount = None
                    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 any(
                            sku in discount.ApplicableSku.all() for sku in skus
                        ):
                            applicable_discount = discount
                            break

                    # If discount is found, calculate the offer price
                    if applicable_discount:
                        discount_percentage = applicable_discount.DiscountPercentage
                        offerprice = f"{float(price) * (1 - float(discount_percentage / 100)):.2f}"  # type: ignore
                        offer = f"{discount_percentage}%"
                    else:
                        offerprice = price
                        offer = "0%"

                    subcategory_name = product.item_sub_category.sub_category_name
                    product_info = {
                        "product_id": product.id,  # type: ignore
                        "product_name": product.item_name,
                        "product_type": product.veg_or_non_veg_status,
                        "offer": offer,
                        "price": price,
                        "offerprice": offerprice,
                        "product_img": product_image_url,
                        "sku_name": sku_name,
                        "sku_quantity": sku_quantity,
                        "sku_unit": sku_unit,
                        "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,  # type: ignore
                            }
                            for sku in skus
                        ],
                        "wishlist": product.id in wishlist_items if request.user.is_authenticated else False, # type: ignore

                    }

                    if subcategory_name not in subcategory_dict:
                        subcategory_dict[subcategory_name] = {"subcategory_image": product.item_sub_category.standard_image.url if product.item_sub_category.standard_image else None, "products" :[]}
                    subcategory_dict[subcategory_name].get("products", []).append(product_info)

            results = [
                {
                    "subcategory_name": subcat,
                    "subcategory_image": products.get("subcategory_image", ""),
                    "products": products.get("products", [])
                }
                for subcat, products in subcategory_dict.items()

            ]


            return Response(
                {
                    "status": 1,
                    "message": "Products retrieved successfully!",
                    "data": results,
                    "filters": {
                        "tags": [{"id": tag.id, "name": tag.tag_name} for tag in tags_list],  # type: ignore
                        "dynamic_filters": [{"id": filter.id, "name": filter.filter_name} for filter in dynamic_filters_list],  # type: ignore
                    },
                },
                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 ProductSearchView(APIView):
    def post(self, request):
        search_term = request.data.get("search_term")
        tag_ids = request.data.get("tag_ids", [])
        dynamic_filter_ids = request.data.get("dynamic_filter_ids", [])

        try:
            if request.user.is_authenticated:
                # User is authenticated, get user location and shop
                user_location = UserLocation.objects.filter(user=request.user).first()
                wishlist_items = Wishlist.objects.filter(user=request.user).values_list('product', flat=True)
            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()

            results = []

            # Base filtering of products by search term
            products = Products.objects.filter(
                Q(item_name__icontains=search_term)
                | Q(skus__sku_name__icontains=search_term)
                | Q(item_category__category_code__icontains=search_term)
                | Q(item_sub_category__sub_category_name__icontains=search_term)
            ).distinct()

            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
                }
            else:
                products = products.filter(skus__sku_expiry_duration__gt=30).distinct()
            products = products.filter(
                skus__sku_status__in=["Visible", "Out of Stock"]
            ).distinct()
            tags_list = Tags.objects.filter(products__in=products).distinct()
            dynamic_filters_list = DynamicFiltering.objects.filter(
                products__in=products
            ).distinct()

            if tag_ids:
                tags = Tags.objects.filter(id__in=tag_ids)
                products = products.filter(tags__in=tags).distinct()
            if dynamic_filter_ids:
                dynamic_filters = DynamicFiltering.objects.filter(
                    id__in=dynamic_filter_ids
                )
                products = products.filter(
                    dynamicfiltering__in=dynamic_filters
                ).distinct()
            discounts = (
                Discount.objects.filter(
                    Q(
                        DiscountOn="Category",
                        ApplicableCategory__in=products.values_list(
                            "item_category", flat=True
                        ),
                    )
                )
                | Discount.objects.filter(
                    Q(
                        DiscountOn="SubCategory",
                        ApplicableSubCategory__in=products.values_list(
                            "item_sub_category", flat=True
                        ),
                    )
                )
                | Discount.objects.filter(
                    Q(DiscountOn="Product", ApplicableProduct__in=products)
                )
                | Discount.objects.filter(
                    Q(
                        DiscountOn="Sku",
                        ApplicableSku__in=SKU.objects.filter(product__in=products),
                    )
                )
            )

            # Group products by subcategory
            subcategory_dict = {}

            for product in products:
                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,
                    )
                if skus.exists():
                    product_images = ProductImage.objects.filter(product=product)
                    product_image_url = product_images.first().image.url if product_images.exists() else None  # type: ignore

                    first_sku = (
                        skus.filter(sku_status="Visible").first()
                        or skus.filter(sku_status="Out of Stock").first()
                    )
                    if first_sku:
                        sku_mrp = first_sku.sku_mrp
                        price = f"{sku_mrp:.2f}"
                        sku_name = first_sku.sku_name
                        sku_quantity = first_sku.sku_quantity
                        sku_unit = first_sku.sku_unit

                    # Check if any discount applies
                    applicable_discount = None
                    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 any(
                            sku in discount.ApplicableSku.all() for sku in skus
                        ):
                            applicable_discount = discount
                            break

                    # If discount is found, calculate the offer price
                    if applicable_discount:
                        discount_percentage = applicable_discount.DiscountPercentage
                        offerprice = f"{float(price) * (1 - float(discount_percentage / 100)):.2f}"  # type: ignore
                        offer = f"{discount_percentage}%"
                    else:
                        offerprice = price
                        offer = "0%"

                    subcategory_name = product.item_sub_category.sub_category_name
                    product_info = {
                        "product_id": product.id,  # type: ignore
                        "product_name": product.item_name,
                        "product_type": product.veg_or_non_veg_status,
                        "offer": offer,
                        "price": price,
                        "offerprice": offerprice,
                        "product_img": product_image_url,
                        "sku_name": sku_name,
                        "sku_quantity": sku_quantity,
                        "sku_unit": sku_unit,
                        "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,  # type: ignore
                            }
                            for sku in skus
                        ],
                        "wishlist": product.id in wishlist_items if request.user.is_authenticated else False, # type: ignore
                    }

                    if subcategory_name not in subcategory_dict:
                        subcategory_dict[subcategory_name] = []
                    subcategory_dict[subcategory_name].append(product_info)

            results = [
                {"subcategory_name": subcat, "products": products}
                for subcat, products in subcategory_dict.items()
            ]

            return Response(
                {
                    "status": 1,
                    "message": "Products retrieved successfully!",
                    "data": results,
                    "filters": {
                        "tags": [{"id": tag.id, "name": tag.tag_name} for tag in tags_list],  # type: ignore
                        "dynamic_filters": [{"id": filter.id, "name": filter.filter_name} for filter in dynamic_filters_list],  # type: ignore
                    },
                },
                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 ProductDetailView(APIView):
    def post(self, request, product_id):
        try:
            # Fetch the product by ID
            product = Products.objects.get(id=product_id)


            reviews = (
                product.reviews.all()  # type: ignore
            )  
            review_data = [
                {
                    "user": review.user.uuid,
                    "review_id": review.id,
                    "username": f"{review.user.first_name} {review.user.last_name}",
                    "rating": review.rating,
                    "review_heading": review.review_heading,
                    "review_text": review.review_text,
                    "created_at": review.created_at,
                }
                for review in reviews
            ]
            tags_list = Tags.objects.filter(products=product).distinct()

            # Check if user is authenticated
            if request.user.is_authenticated:
                user_location = UserLocation.objects.filter(user=request.user).first()
                wishlist_items = Wishlist.objects.filter(user=request.user).values_list('product', flat=True)
                wishlist_status = product.id in wishlist_items # type: ignore
            else:
                wishlist_status = False
                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 logic: product details based on the shop
                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
                }

                # Fetch the product's SKUs
                skus = SKU.objects.filter(
                    product=product, sku_status__in=["Visible", "Out of Stock"]
                )
                if skus.exists():
                    product_images = ProductImage.objects.filter(product=product)
                    product_image_urls = (
                        [image.image.url for image in product_images]
                        if product_images.exists()
                        else []
                    )


                    product_info = {
                        "user_id": (
                            request.user.uuid if request.user.is_authenticated else "NA"
                        ),
                        "product_id": product.id,  # type: ignore
                        "product_name": product.item_name,
                        "product_type": product.veg_or_non_veg_status,
                        "product_category":product.item_category.category_name,
                        "product_subcategory": product.item_sub_category.sub_category_name,
                        "product_category_code": product.item_category.category_code,
                        "reviews": review_data,  # Reviews included in the response
                        "item_code": product.item_code,
                        "item_description": product.item_description,
                        "images": product_image_urls,
                        "tags": [{"id": tag.id, "name": tag.tag_name} for tag in tags_list], # type: ignore
                        "wishlist": wishlist_status,
                        "skus": [],
                    }



                    # Loop through the SKUs to get the price and apply discounts
                    for sku in skus:
                        sku_mrp = sku.sku_mrp
                        sku_name = sku.sku_name
                        sku_quantity = sku.sku_quantity
                        sku_unit = sku.sku_unit

                        # Check if any discount applies at the SKU level
                        applicable_discount = None
                        discounts = (
                            Discount.objects.filter(
                                Q(
                                    DiscountOn="Category",
                                    ApplicableCategory__in=[product.item_category],
                                )
                            )
                            | Discount.objects.filter(
                                Q(
                                    DiscountOn="SubCategory",
                                    ApplicableSubCategory__in=[
                                        product.item_sub_category
                                    ],
                                )
                            )
                            | Discount.objects.filter(
                                Q(DiscountOn="Product", ApplicableProduct__in=[product])
                            )
                            | Discount.objects.filter(
                                Q(
                                    DiscountOn="Sku", ApplicableSku__in=[sku]
                                )  # Discount applied on 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 any(
                                sku in discount.ApplicableSku.all() for sku in skus
                            ):
                                applicable_discount = discount
                                break

                        # Calculate the offer price
                        if applicable_discount:
                            discount_percentage = applicable_discount.DiscountPercentage
                            offer_price = f"{float(sku_mrp) * (1 - float(discount_percentage / 100)):.2f}"  # type: ignore
                            offer = f"{discount_percentage}%"
                        else:
                            offer_price = f"{sku_mrp:.2f}"
                            offer = "0%"

                        product_info["skus"].append(
                            {
                                "sku_id": sku.id,
                                "sku_code": sku.sku_code,
                                "sku_mrp": f"{sku_mrp:.2f}",
                                "offer_price": offer_price,
                                "sku_quantity": sku_quantity,
                                "sku_unit": sku_unit,
                                "sku_expiry_duration": sku.sku_expiry_duration,
                                "sku_bulk_qty_limit": sku.sku_bulk_qty_limit,
                                "offer": offer,
                                "sku_status": sku_status_map.get(sku.id, "Disabled")
                            }
                            )
                    return Response(
                        {
                            "status": 1,
                            "message": "Product details retrieved successfully!",
                            "data": product_info,
                        },
                        status=status.HTTP_200_OK,
                    )
                else:
                    product_images = ProductImage.objects.filter(product=product)
                    product_image_urls = (
                        [image.image.url for image in product_images]
                        if product_images.exists()
                        else []
                    )


                    product_info = {
                        "user_id": (
                            request.user.uuid if request.user.is_authenticated else "NA"
                        ),
                        "product_id": product.id,  # type: ignore
                        "product_name": product.item_name,
                        "product_type": product.veg_or_non_veg_status,
                        "product_category":product.item_category.category_name,
                        "product_subcategory": product.item_sub_category.sub_category_name,
                        "product_category_code": product.item_category.category_code,
                        "reviews": review_data,  # Reviews included in the response
                        "item_code": product.item_code,
                        "item_description": product.item_description,
                        "images": product_image_urls,
                        "tags": [{"id": tag.id, "name": tag.tag_name} for tag in tags_list], # type: ignore
                        "wishlist": wishlist_status,
                        "skus": [],
                    }
                    return Response(
                        {
                            "status":0,
                            "message": "No sku Detials retrieved!",
                            "data": product_info,
                        },
                        status =  status.HTTP_404_NOT_FOUND,

                    )

            # Non-shop logic: products that may have expiry > 30 days
            else:
                skus = SKU.objects.filter(
                    product=product,
                    sku_status__in=["Visible", "Out of Stock"],
                    sku_expiry_duration__gt=30,
                )
                if skus.exists():
                    product_images = ProductImage.objects.filter(product=product)
                    product_image_urls = (
                        [image.image.url for image in product_images]
                        if product_images.exists()
                        else []
                    )



                    product_info = {
                        "user_id": (
                            request.user.uuid if request.user.is_authenticated else "NA"
                        ),
                        "product_id": product.id,  # type: ignore
                        "product_name": product.item_name,
                        "product_type": product.veg_or_non_veg_status,
                        "product_category":product.item_category.category_name,
                        "product_subcategory": product.item_sub_category.sub_category_name,
                        "product_category_code": product.item_category.category_code,
                        "reviews": review_data,  # Reviews included in the response
                        "item_code": product.item_code,
                        "item_description": product.item_description,
                        "images": product_image_urls,
                        "tags": [{"id": tag.id, "name": tag.tag_name} for tag in tags_list], # type: ignore
                        "wishlist": wishlist_status,
                        "skus": [],
                    }

                    for sku in skus:
                        sku_mrp = sku.sku_mrp
                        sku_name = sku.sku_name
                        sku_quantity = sku.sku_quantity
                        sku_unit = sku.sku_unit

                        # Check if any discount applies at the SKU level
                        applicable_discount = None
                        discounts = (
                            Discount.objects.filter(
                                Q(
                                    DiscountOn="Category",
                                    ApplicableCategory__in=[product.item_category],
                                )
                            )
                            | Discount.objects.filter(
                                Q(
                                    DiscountOn="SubCategory",
                                    ApplicableSubCategory__in=[
                                        product.item_sub_category
                                    ],
                                )
                            )
                            | Discount.objects.filter(
                                Q(DiscountOn="Product", ApplicableProduct__in=[product])
                            )
                            | Discount.objects.filter(
                                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 any(
                                sku in discount.ApplicableSku.all() for sku in skus
                            ):
                                applicable_discount = discount
                                break

                        if applicable_discount:
                            discount_percentage = applicable_discount.DiscountPercentage
                            offer_price = f"{float(sku_mrp) * (1 - float(discount_percentage / 100)):.2f}"  # type: ignore
                            offer = f"{discount_percentage}%"
                        else:
                            offer_price = f"{sku_mrp:.2f}"
                            offer = "0%"

                        product_info["skus"].append(
                            {
                                "sku_id": sku.id,  # type: ignore
                                "sku_name": sku_name,
                                "sku_code": sku.sku_code,
                                "sku_mrp": f"{sku_mrp:.2f}",
                                "offer_price": offer_price,
                                "sku_quantity": sku_quantity,
                                "sku_unit": sku_unit,
                                "sku_expiry_duration": sku.sku_expiry_duration,
                                "sku_bulk_qty_limit": sku.sku_bulk_qty_limit,
                                "offer": offer,
                                "sku_status": sku.sku_status,
                            }
                        )

                    return Response(
                        {
                            "status": 1,
                            "message": "Product details retrieved successfully!",
                            "data": product_info,
                        },
                        status=status.HTTP_200_OK,
                    )
                else:

                    product_images = ProductImage.objects.filter(product=product)
                    product_image_urls = (
                        [image.image.url for image in product_images]
                        if product_images.exists()
                        else []
                    )



                    product_info = {
                        "user_id": (
                            request.user.uuid if request.user.is_authenticated else "NA"
                        ),
                        "product_id": product.id,  # type: ignore
                        "product_name": product.item_name,
                        "product_type": product.veg_or_non_veg_status,
                        "product_category":product.item_category.category_name,
                        "product_subcategory": product.item_sub_category.sub_category_name,
                        "product_category_code": product.item_category.category_code,
                        "reviews": review_data,  # Reviews included in the response
                        "item_code": product.item_code,
                        "item_description": product.item_description,
                        "images": product_image_urls,
                        "tags": [{"id": tag.id, "name": tag.tag_name} for tag in tags_list], # type: ignore
                        "wishlist": wishlist_status,
                        "skus": [],
                    }
                    return Response(
                        {
                            "status": 0,
                            "message": "SKU  details not retrieved successfully!",
                            "data": product_info,
                        },
                        status=status.HTTP_404_NOT_FOUND,
                    )

        except Products.DoesNotExist:
            return Response(
                {
                    "status": 0,
                    "message": "Product not found.",
                },
                status=status.HTTP_404_NOT_FOUND,
            )

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


class SpecialListProductView(APIView):
    def get(self, request):
        try:
            # Fetch all SpecialLists and their associated products
            special_lists = SpecialList.objects.all()

            # Prepare the result to return
            results = []

            if request.user.is_authenticated:
                user_location = UserLocation.objects.filter(user=request.user).first()
                wishlist_items = Wishlist.objects.filter(user=request.user).values_list('product', flat=True)
            else:
                anonymous_id = request.data.get("anonymous_id")
                user_location = UserLocation.objects.filter(
                    anonymous_id=anonymous_id
                ).first()

            category_ids = set()
            subcategory_ids = set()

            for special_list in special_lists:
                # Loop through each product in the special list
                for product in special_list.products.all():
                    # Directly access the category ID and add to the set (no duplicates will be stored)
                    category_ids.add(product.item_category.uuid)

                    # Directly access the subcategory ID and add to the set (no duplicates will be stored)
                    subcategory_ids.add(product.item_sub_category.uuid)

            # Now fetch applicable discounts based on these category and subcategory IDs
            discounts = (
                Discount.objects.filter(
                    Q(DiscountOn="Category", ApplicableCategory__in=category_ids)
                )
                | Discount.objects.filter(
                    Q(
                        DiscountOn="SubCategory",
                        ApplicableSubCategory__in=subcategory_ids,
                    )
                )
                | Discount.objects.filter(
                    Q(DiscountOn="Product", ApplicableProduct__in=special_list.products.all())  # type: ignore
                )
                | Discount.objects.filter(
                    Q(DiscountOn="Sku", ApplicableSku__in=SKU.objects.filter(product__in=special_list.products.all()))  # type: ignore
                )
            )

            # Handle the case where the user has a location and shop
            if user_location and user_location.shop:
                # Shop found; use 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
                }

                # Iterate through each special list
                for special_list in special_lists:
                    special_list_data = {
                        "special_name": special_list.special_name,
                        "icon": special_list.icon.url if special_list.icon else None,
                        "banner_image": (
                            special_list.banner_image.url
                            if special_list.banner_image
                            else None
                        ),
                        "products": [],
                    }

                    # Iterate through each product in the SpecialList
                    for product in special_list.products.all():
                        # Get SKUs
                        skus = SKU.objects.filter(
                            product=product, sku_status__in=["Visible", "Out of Stock"]
                        )

                        # Get product image
                        product_images = ProductImage.objects.filter(product=product)
                        product_image_url = product_images.first().image.url if product_images.exists() else None  # type: ignore

                        # Get the first visible SKU or out of stock SKU
                        first_sku = (
                            skus.filter(sku_status="Visible").first()
                            or skus.filter(sku_status="Out of Stock").first()
                        )

                        if first_sku:
                            sku_mrp = first_sku.sku_mrp
                            price = f"{sku_mrp:.2f}" if sku_mrp is not None else "N/A"
                            sku_name = first_sku.sku_name
                            sku_quantity = first_sku.sku_quantity
                            sku_unit = first_sku.sku_unit

                            # Check if any discount applies
                            applicable_discount = None
                            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 any(
                                    sku in discount.ApplicableSku.all() for sku in skus
                                ):
                                    applicable_discount = discount
                                    break

                            # Calculate the offer price if discount is found
                            if applicable_discount:
                                discount_percentage = (
                                    applicable_discount.DiscountPercentage
                                )
                                offerprice = f"{float(price) * (1 - float(discount_percentage / 100)):.2f}"  # type: ignore
                                offer = f"{discount_percentage}%"
                            else:
                                offerprice = price
                                offer = "0%"

                            # Group products by subcategory
                            product_info = {
                                "product_id": product.id,  # type: ignore
                                "product_name": product.item_name,
                                "product_type": product.veg_or_non_veg_status,
                                "offer": offer,
                                "price": price,
                                "offerprice": offerprice,
                                "product_img": product_image_url,
                                "sku_name": sku_name,
                                "sku_quantity": sku_quantity,
                                "sku_unit": sku_unit,
                                "skus": [
                                    {"sku_name": sku.sku_name, "sku_status": sku_status_map.get(sku.id, "Unknown")}  # type: ignore
                                    for sku in skus
                                ],
                                "wishlist": product.id in wishlist_items if request.user.is_authenticated else False, # type: ignore
                            }

                            special_list_data["products"].append(product_info)

                    # Append the special list with products to the results
                    results.append(special_list_data)

            # If no shop is found, use expiry date logic and apply discounts
            else:
                for special_list in special_lists:
                    special_list_data = {
                        "special_name": special_list.special_name,
                        "icon": special_list.icon.url if special_list.icon else None,
                        "banner_image": (
                            special_list.banner_image.url
                            if special_list.banner_image
                            else None
                        ),
                        "products": [],
                    }

                    # Iterate through each product in the SpecialList
                    for product in special_list.products.all():
                        # Get SKUs with expiry logic
                        skus = SKU.objects.filter(
                            product=product,
                            sku_status__in=["Visible", "Out of Stock"],
                            sku_expiry_duration__gt=30,
                        )

                        # Get product image
                        product_images = ProductImage.objects.filter(product=product)
                        product_image_url = product_images.first().image.url if product_images.exists() else None  # type: ignore

                        # Get the first visible SKU or out of stock SKU
                        first_sku = (
                            skus.filter(sku_status="Visible").first()
                            or skus.filter(sku_status="Out of Stock").first()
                        )

                        if first_sku:
                            sku_mrp = first_sku.sku_mrp
                            price = f"{sku_mrp:.2f}" if sku_mrp is not None else "N/A"
                            sku_name = first_sku.sku_name
                            sku_quantity = first_sku.sku_quantity
                            sku_unit = first_sku.sku_unit

                            # Check if any discount applies
                            applicable_discount = None
                            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 any(
                                    sku in discount.ApplicableSku.all() for sku in skus
                                ):
                                    applicable_discount = discount
                                    break

                            # Calculate the offer price if discount is found
                            if applicable_discount:
                                discount_percentage = (
                                    applicable_discount.DiscountPercentage
                                )
                                offerprice = f"{float(price) * (1 - float(discount_percentage / 100)):.2f}"  # type: ignore
                                offer = f"{discount_percentage}%"
                            else:
                                offerprice = price
                                offer = "0%"

                            # Group products by subcategory
                            subcategory_name = (
                                product.item_sub_category.sub_category_name
                            )
                            product_info = {
                                "product_id": product.id,  # type: ignore
                                "product_name": product.item_name,
                                "product_type": product.veg_or_non_veg_status,
                                "offer": offer,
                                "price": price,
                                "offerprice": offerprice,
                                "product_img": product_image_url,
                                "sku_name": sku_name,
                                "sku_quantity": sku_quantity,
                                "sku_unit": sku_unit,
                                "skus": [
                                    {
                                        "sku_name": sku.sku_name,
                                        "sku_status": sku.sku_status,
                                    }
                                    for sku in skus
                                ],
                                "wishlist": product.id in wishlist_items if request.user.is_authenticated else False, # type: ignore
                            }

                            special_list_data["products"].append(product_info)

                    # Append the special list with products to the results
                    results.append(special_list_data)

            return Response(
                {
                    "status": 1,
                    "message": "Special lists and products retrieved successfully!",
                    "data": results,
                },
                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 CustomProductListView(APIView):
    def post(self, request):
        try:
            # Fetch all custom products
            custom_products = CustomProduct.objects.all()

            # Prepare response data for each custom product
            custom_product_list = []

            for product in custom_products:
                # Fetch one image for the product
                product_image = CustomProductImage.objects.filter(
                    custom_product=product
                ).first()
                product_image_url = product_image.image.url if product_image else None

                # Create a product info dictionary
                product_info = {
                    "product_id": product.id,  # type: ignore
                    "product_name": product.item_name,
                    "product_code": product.item_code,
                    "product_description": product.item_description,
                    "veg_or_non_veg_status": product.veg_or_non_veg_status,
                    "min_size": product.min_size,
                    "max_size": product.max_size,
                    "size_unit": product.size_unit,
                    "availability": product.availability,  # human-readable availability status
                    "product_img": product_image_url,
                }

                # Add to the custom product list
                custom_product_list.append(product_info)

            # Return the response with the list of products
            return Response(
                {
                    "status": 1,
                    "message": "Custom products retrieved successfully!",
                    "data": custom_product_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 CustomProductDetailView(APIView):
    def get(self, request, product_id):
        try:
            # Fetch the custom product by the given product_id
            custom_product = CustomProduct.objects.filter(id=product_id).first()

            if not custom_product:
                return Response(
                    {
                        "status": 0,
                        "message": "Custom product not found.",
                    },
                    status=status.HTTP_404_NOT_FOUND,
                )

            # Get all images related to this custom product
            images = CustomProductImage.objects.filter(custom_product=custom_product)

            # Get all videos related to this custom product
            videos = CustomProductVideo.objects.filter(custom_product=custom_product)

            # Prepare the response data
            product_data = {
                "product_id": custom_product.id,  # type: ignore
                "product_name": custom_product.item_name,
                "product_code": custom_product.item_code,
                "description": custom_product.item_description,
                "veg_or_non_veg_status": custom_product.veg_or_non_veg_status,
                "min_size": custom_product.min_size,
                "max_size": custom_product.max_size,
                "size_unit": custom_product.size_unit,
                "availability": custom_product.availability,
                "created_date": custom_product.created_date,
                "updated_date": custom_product.updated_date,
                "images": [
                    {"image_url": image.image.url, "created_date": image.created_date}
                    for image in images
                ],
                "videos": [
                    {"video_url": video.video.url, "created_date": video.created_date}
                    for video in videos
                ],
            }

            return Response(
                {
                    "status": 1,
                    "message": "Custom product details retrieved successfully!",
                    "data": product_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 DeleteReviewView(APIView):
    def delete(self, request, review_id):
        try:
            # Ensure the user is authenticated
            if not request.user.is_authenticated:
                return Response(
                    {"status": 0, "message": "User not authenticated."},
                    status=status.HTTP_401_UNAUTHORIZED,
                )

            review = ProductReview.objects.get(id=review_id)

            # Check if the authenticated user is the one who created the review
            if review.user != request.user:
                return Response(
                    {"status": 0, "message": "You can only delete your own reviews."},
                    status=status.HTTP_403_FORBIDDEN,
                )

            # Delete the review
            review.delete()

            return Response(
                {"status": 1, "message": "Review deleted successfully!"},
                status=status.HTTP_200_OK,
            )

        except ProductReview.DoesNotExist:
            return Response(
                {"status": 0, "message": "Review not found."},
                status=status.HTTP_404_NOT_FOUND,
            )

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


class EditReviewView(APIView):
    def put(self, request, review_id):
        try:
            # Ensure the user is authenticated
            if not request.user.is_authenticated:
                return Response(
                    {"status": 0, "message": "User not authenticated."},
                    status=status.HTTP_401_UNAUTHORIZED,
                )

            review = ProductReview.objects.get(id=review_id)

            # Check if the authenticated user is the one who created the review
            if review.user != request.user:
                return Response(
                    {"status": 0, "message": "You can only edit your own reviews."},
                    status=status.HTTP_403_FORBIDDEN,
                )

            rating = request.data.get("rating", review.rating)
            review_heading = request.data.get("review_heading", review.review_heading)
            review_text = request.data.get("review_text", review.review_text)

            # Validate inputs
            if not rating or not review_heading or not review_text:
                return Response(
                    {"status": 0, "message": "Missing required fields."},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Update review fields
            review.rating = rating
            review.review_heading = review_heading
            review.review_text = review_text
            review.save()

            return Response(
                {
                    "status": 1,
                    "message": "Review updated successfully!",
                    "data": {
                        "user": review.user.uuid,
                        "rating": rating,
                        "review_heading": review_heading,
                        "review_text": review_text,
                        "created_at": review.created_at,
                    },
                },
                status=status.HTTP_200_OK,
            )

        except ProductReview.DoesNotExist:
            return Response(
                {"status": 0, "message": "Review not found."},
                status=status.HTTP_404_NOT_FOUND,
            )

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


class AddReviewView(APIView):
    def post(self, request, product_id):
        try:
            product = Products.objects.get(id=product_id)

            # Ensure the user is authenticated
            if not request.user.is_authenticated:
                return Response(
                    {"status": 0, "message": "User not authenticated."},
                    status=status.HTTP_401_UNAUTHORIZED,
                )

            user = request.user
            rating = request.data.get("rating")
            review_heading = request.data.get("review_heading")
            review_text = request.data.get("review_text")

            # Validate inputs
            if not rating or not review_heading or not review_text:
                return Response(
                    {"status": 0, "message": "Missing required fields."},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            # Add review to the product
            review = ProductReview(
                product=product,
                user=user,
                rating=rating,
                review_heading=review_heading,
                review_text=review_text,
            )
            review.save()

            return Response(
                {
                    "status": 1,
                    "message": "Review added successfully!",
                    "data": {
                        "user": user.uuid,
                        "rating": rating,
                        "review_heading": review_heading,
                        "review_text": review_text,
                        "created_at": review.created_at,
                    },
                },
                status=status.HTTP_201_CREATED,
            )

        except Products.DoesNotExist:
            return Response(
                {"status": 0, "message": "Product not found."},
                status=status.HTTP_404_NOT_FOUND,
            )

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


class AddToWishlistView(APIView):
    def post(self, request, product_id):
        try:
            product = Products.objects.get(id=product_id)

            if not request.user.is_authenticated:
                return Response(
                    {"status": 0, "message": "User not authenticated."},
                    status=status.HTTP_401_UNAUTHORIZED,
                )

            user = request.user

            wishlist_item = Wishlist(user=user, product=product)
            wishlist_item.save()

            return Response(
                {"status": 1, "message": "Product added to wishlist successfully!"},
                status=status.HTTP_201_CREATED,
            )

        except Products.DoesNotExist:
            return Response(
                {"status": 0, "message": "Product not found."},
                status=status.HTTP_404_NOT_FOUND,
            )

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


class RemoveFromWishlistView(APIView):
    def post(self, request, product_id):
        try:
            product = Products.objects.get(id=product_id)

            if not request.user.is_authenticated:
                return Response(
                    {"status": 0, "message": "User not authenticated."},
                    status=status.HTTP_401_UNAUTHORIZED,
                )

            user = request.user

            wishlist_item = Wishlist.objects.filter(user=user, product=product).first()
            
            wishlist_item.delete() # type: ignore

            return Response(
                {"status": 1, "message": "Product removed from wishlist successfully!"},
                status=status.HTTP_200_OK,
            )

        except Products.DoesNotExist:
            return Response(
                {"status": 0, "message": "Product not found."},
                status=status.HTTP_404_NOT_FOUND,
            )

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

class WishlistListView(APIView):
    def post(self, request):
        try:
            anonymous_id = request.data.get("anonymous_id")
            user = request.user
            # check whether user authenticated or not
            # if authenticated we fetch the user location
            #other wise anonymous user location
            if request.user.is_authenticated:
                user_location = UserLocation.objects.filter(user=request.user).first()
            else:
                user_location = UserLocation.objects.filter(
                    anonymous_id=anonymous_id
                ).first()

            # select all wish list items

            wishlist_items = Wishlist.objects.filter(user=user).select_related('product')



            # no wish list
            if not wishlist_items.exists():
                return Response(
                    {"status": 0, "message": "No products in wishlist."},
                    status=status.HTTP_200_OK,
                )

            results = []


            # iterating on each wish list item
            # fetch the skus associated with it
            # return the response
            for wishlist_item in wishlist_items:

                product = wishlist_item.product
                product_available = False
                skus = []

                # if shop available and sku is available
                # return the details
                if user_location and user_location.shop:
                    shop_id = user_location.shop.uuid
                    skus_sales = SalesUnitProductSelection.objects.filter(
                        sales_unit__uuid=shop_id, sku__product__id = product.id, sku__sku_status__in=["Visible", "Out of Stock"],
                        shop_admin_status = "Visible"
                    ).distinct()

                    for i in skus_sales:
                        skus.append(i.sku)
                    # sku available
                    if skus:
                        product_available = True
                    else:
                    # sku not available
                        product_available = False



                else:
                    # if shop not available

                    # product received from pu
                    skus_sales = SalesUnitProductSelection.objects.filter(sku__sku_expiry_duration__gt=30, sku__product__id=product.id,sku__sku_status__in=["Visible", "Out of Stock"]).distinct()
                    for i in skus_sales:
                        skus.append(i.sku)

                    if skus:
                        # product available not from near shop
                        product_available = True
                    else:
                        #product is not in the shop and couldn't order from pu since expiry date is not valid
                        # product details fetched and marked it as not available
                        product_available = False
                        sku_inactive = SalesUnitProductSelection.objects.filter(sku__product__id=product.id,sku__sku_status__in=["Visible", "Out of Stock"]).distinct()
                        for j in sku_inactive:
                            skus.append(j.sku)

                # fetch the product images

                product_images = ProductImage.objects.filter(product=product)
                product_image_url = product_images.first().image.url if product_images.exists() else None # type: ignore



                if product_available:

                    # fetch the sku details
                    first_sku = skus[0]
                    sku_mrp = first_sku.sku_mrp
                    price = f"{sku_mrp:.2f}"
                    sku_name = first_sku.sku_name
                    sku_quantity = first_sku.sku_quantity
                    sku_unit = first_sku.sku_unit


                    # discount details
                    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.objects.filter(product=product))
                    )

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

                    if applicable_discount:
                        discount_percentage = applicable_discount.DiscountPercentage
                        offerprice = f"{float(price) * (1 - float(discount_percentage / 100)):.2f}"  # type: ignore
                        offer = f"{discount_percentage}%"
                    else:
                        offerprice = price
                        offer = "0%"

                    product_info = {
                        "product_id": product.id,  # type: ignore
                        "product_name": product.item_name,
                        "product_type": product.veg_or_non_veg_status,
                        "offer": offer,
                        "price": price,
                        "offerprice": offerprice,
                        "product_img": product_image_url,
                        "sku_name": sku_name,
                        "sku_quantity": sku_quantity,
                        "sku_unit": sku_unit,
                        "skus": [
                            {
                                "sku_name": sku.sku_name,
                                "sku_status": sku.sku_status,
                            }
                            for sku in skus
                        ],
                        "product_available": product_available
                    }
                    results.append(product_info)
                else:
                    # sku present but not available for ordering
                    if skus:
                        first_sku = skus[0]
                        sku_mrp = first_sku.sku_mrp
                        price = f"{sku_mrp:.2f}"
                        sku_name = first_sku.sku_name
                        sku_quantity = first_sku.sku_quantity
                        sku_unit = first_sku.sku_unit

                        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.objects.filter(product=product))
                        )

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

                        if applicable_discount:
                            discount_percentage = applicable_discount.DiscountPercentage
                            offerprice = f"{float(price) * (1 - float(discount_percentage / 100)):.2f}"  # type: ignore
                            offer = f"{discount_percentage}%"
                        else:
                            offerprice = price
                            offer = "0%"

                        product_info = {
                            "product_id": product.id,  # type: ignore
                            "product_name": product.item_name,
                            "product_type": product.veg_or_non_veg_status,
                            "offer": offer,
                            "price": price,
                            "offerprice": offerprice,
                            "product_img": product_image_url,
                            "sku_name": sku_name,
                            "sku_quantity": sku_quantity,
                            "sku_unit": sku_unit,
                            "skus": [
                                {
                                    "sku_name": sku.sku_name,
                                    "sku_status": sku.sku_status,
                                }
                                for sku in skus
                            ],
                            "product_available": product_available
                        }
                        results.append(product_info)




            return Response(
                {
                    "status": 1,
                    "message": "Wishlist retrieved successfully!",
                    "data": results,
                },
                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 AlsoBoughtView(APIView):
    """
    View to list all discounts with DiscountName and StandardImage.
    """

    def post(self, request, *args, **kwargs):
        product = request.data.get("product_id")
        tag_ids = request.data.get("tag_ids", [])
        dynamic_filter_ids = request.data.get("dynamic_filter_ids", [])
        anonymous_id = request.data.get("anonymous_id")

        try:
            if request.user.is_authenticated:
                user_location = UserLocation.objects.filter(user=request.user).first()
                wishlist_items = Wishlist.objects.filter(user=request.user).values_list('product', flat=True)
            else:
                user_location = UserLocation.objects.filter(
                    anonymous_id=anonymous_id
                ).first()

            results = []

            product_id = []
            if product:

                order_product_list = OrderProducts.objects.filter(sku__product_id=product)

                order_list = []

                for orders in order_product_list:
                    order_list.append(orders.order.uuid)

                # remove duplicates

                order_list = list(set(order_list))

                orders = Orders.objects.filter(uuid__in=order_list)

                order_numbers = []

                for order in orders:
                    order_numbers.append(order.uuid)


                # fectch related order products

                orders_common = OrderProducts.objects.filter(order__in=order_numbers).exclude(sku__product_id=product)

                # count the sku
                common_products = (orders_common
                                   .values('sku')
                                   .annotate(count=Count('sku'))
                                   ).order_by('-count')


                sku_product_list = []
                for sku_product in common_products:
                    sku_product_list.append(sku_product["sku"])


                for i in sku_product_list:
                    product_sku = SKU.objects.filter(id=i).first()
                    if product_sku.product.id not in product_id:
                        product_id.append(product_sku.product.id)  # get product of sku which are common on orders like in cart

                    if len(product_id) == 10:           # only fetch 5 items
                        break



            else:
                #fetch the cart related products from here

                # fetch cart with user
                if request.user.is_authenticated:
                    user = request.user
                    try:
                        cart = get_object_or_404(Cart, user=user)
                    except:
                        return Response({"status": 0, "message": f"Cart not found for user : {user.first_name}"})

                else:
                    if not anonymous_id:
                        return Response(
                            {"status": 0, "message": "Anonymous ID is required."},
                            status=400,
                        )
                    try:
                        cart = get_object_or_404(Cart, anonymous_id = anonymous_id)
                    except:
                        return Response({"status":0, "message": f"Cart not found for anonymous_id : {anonymous_id}"})


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

                #  get sku id
                sku_list = []
                product_id_list = []
                for item in cart_items:
                    sku = item.sku
                    sku_list.append(sku)
                    product_id_sku = sku.product.id
                    if product_id_sku not in product_id_list:
                        product_id_list .append(product_id_sku)


                # remove sku duplicates

                sku_list = list(set(sku_list))

                order_product_list = OrderProducts.objects.filter(sku__in=sku_list)

                order_list = []

                for orders in order_product_list:
                    order_list.append(orders.order.uuid)

                # remove duplicates

                order_list = list(set(order_list))

                orders = Orders.objects.filter(uuid__in=order_list)

                order_numbers = []

                for order in orders:
                    order_numbers.append(order.uuid)


                # fectch related order products

                orders_common = OrderProducts.objects.filter(order__in=order_numbers).exclude(sku__in=sku_list).exclude(sku__product_id__in=product_id_list)

                # count the sku
                common_products = (orders_common
                                   .values('sku')
                                   .annotate(count=Count('sku'))
                                   ).order_by('-count')


                sku_product_list = []
                for sku_product in common_products:
                    sku_product_list.append(sku_product["sku"])


                for i in sku_product_list:
                    product_sku = SKU.objects.filter(id=i).first()
                    if product_sku.product.id not in product_id:
                        product_id.append(product_sku.product.id)  # get product of sku which are common on orders like in cart

                    if len(product_id) == 10:           # only fetch 5 items
                        break





            if user_location and user_location.shop:
                # Shop found; use 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
                }
                products = Products.objects.filter(id__in = product_id).all()

            else:
                products = Products.objects.filter(skus__sku_expiry_duration__gt=30, id__in = product_id).distinct()

            products = products.filter(skus__sku_status__in=["Visible", "Out of Stock"]).distinct()[:5]
            tags_list = Tags.objects.filter(products__in=products).distinct()
            dynamic_filters_list = DynamicFiltering.objects.filter(
                products__in=products
            ).distinct()

            if tag_ids:
                tags = Tags.objects.filter(id__in=tag_ids)
                products = products.filter(tags__in=tags).distinct()
            if dynamic_filter_ids:
                dynamic_filters = DynamicFiltering.objects.filter(
                    id__in=dynamic_filter_ids
                )
                products = products.filter(
                    dynamicfiltering__in=dynamic_filters
                ).distinct()


                # Fetch applicable discounts for shop-based products

            discounts = (
                    Discount.objects.filter(
                        Q(
                            DiscountOn="Category",
                            ApplicableCategory__in=products.values_list(
                                "item_category", flat=True
                            ),
                        )
                    )
                    | Discount.objects.filter(
                Q(
                    DiscountOn="SubCategory",
                    ApplicableSubCategory__in=products.values_list(
                        "item_sub_category", flat=True
                    ),
                )
            )
                    | Discount.objects.filter(
                Q(DiscountOn="Product", ApplicableProduct__in=products)
            )
                    | Discount.objects.filter(
                Q(
                    DiscountOn="Sku",
                    ApplicableSku__in=SKU.objects.filter(product__in=products),
                )
            )
            )

            product_list = []
            for product in products:
                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,
                    )
                if skus.exists():
                    # Get one product image (if available)
                    product_images = ProductImage.objects.filter(product=product)
                    product_image_url = product_images.first().image.url if product_images.exists() else None  # type: ignore

                    first_sku = (
                            skus.filter(sku_status="Visible").first()
                            or skus.filter(sku_status="Out of Stock").first()
                    )
                    if first_sku:
                        sku_mrp = first_sku.sku_mrp
                        price = f"{sku_mrp:.2f}"
                        sku_name = first_sku.sku_name
                        sku_quantity = first_sku.sku_quantity
                        sku_unit = first_sku.sku_unit

                    # Check if any discount applies
                    applicable_discount = None
                    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 any(
                                sku in discount.ApplicableSku.all() for sku in skus
                        ):
                            applicable_discount = discount
                            break

                    # If discount is found, calculate the offer price
                    if applicable_discount:
                        discount_percentage = applicable_discount.DiscountPercentage
                        offerprice = f"{float(price) * (1 - float(discount_percentage / 100)):.2f}"  # type: ignore
                        offer = f"{discount_percentage}%"
                    else:
                        offerprice = price
                        offer = "0%"

                    product_info = {
                        "product_id": product.id,  # type: ignore
                        "product_name": product.item_name,
                        "product_type": product.veg_or_non_veg_status,
                        "offer": offer,
                        "price": price,
                        "offerprice": offerprice,
                        "product_img": product_image_url,
                        "sku_name": sku_name,
                        "sku_quantity": sku_quantity,
                        "sku_unit": sku_unit,
                        "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,  # type: ignore
                            }
                            for sku in skus
                        ],
                        "wishlist": product.id in wishlist_items if request.user.is_authenticated else False,
                        # type: ignore

                    }
                    product_list.append(product_info)




            return Response(
                {
                    "status": 1,
                    "message": "Products retrieved successfully!",
                    "products": product_list,
                    "filters": {
                        "tags": [{"id": tag.id, "name": tag.tag_name} for tag in tags_list],  # type: ignore
                        "dynamic_filters": [{"id": filter.id, "name": filter.filter_name} for filter in
                                            dynamic_filters_list],  # type: ignore
                    },
                },
                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,
            )

