import { NextRequest, NextResponse } from "next/server";
import dbConnect from "../../../src/lib/mongodb";
import Product from "../../../src/models/Product";
import ProductSKU from "../../../src/models/ProductSKU";
import ProductColorImage from "@/models/ProductColorImage";
import Category from "../../../src/models/Category";
import Color from "../../../src/models/Color";
import Size from "../../../src/models/Size";
import mongoose from "mongoose";
import ProductReview from "../../../src/models/Review";

export async function getProducts(req: NextRequest) {
  try {
    await dbConnect();

    const { searchParams } = new URL(req.url);

    // =========================
    // PAGINATION
    // =========================
    const page = parseInt(searchParams.get("page") || "1");

    const limit = parseInt(searchParams.get("limit") || "12");

    const skip = (page - 1) * limit;

    // =========================
    // FILTERS
    // =========================
    const categories = (searchParams.get("category") || "")
      .split(",")
      .filter(Boolean);

    const subcategories = (searchParams.get("subcategory") || "")
      .split(",")
      .filter(Boolean);

    const colors = (searchParams.get("color") || "").split(",").filter(Boolean);

    const sizes = (searchParams.get("size") || "").split(",").filter(Boolean);

    const minPrice = searchParams.get("minPrice");

    const maxPrice = searchParams.get("maxPrice");

    const ratings = (searchParams.get("ratings") || "")
      .split(",")
      .filter(Boolean)
      .map((rating) => parseFloat(rating));

    const search = searchParams.get("search");

    const isFeatured = searchParams.get("isFeatured");

    const isActive = searchParams.get("isActive") !== "false";

    // =========================
    // SORTING
    // =========================
    const sortBy = searchParams.get("sortBy") || "createdAt";

    const sortOrder = searchParams.get("sortOrder") || "desc";

    // =========================
    // PRODUCT QUERY
    // =========================
    const productQuery: any = {
      isActive,
    };

    if (isFeatured === "true") {
      productQuery.isFeatured = true;
    }

    // =========================
    // CATEGORY FILTER BY SLUG
    // =========================
    if (categories.length > 0) {
      const matchedCategories = await Category.find({
        slug: { $in: categories },
      }).select("_id");

      const categoryIds = matchedCategories.map(
        (category: any) => category._id,
      );

      productQuery.category = {
        $in: categoryIds,
      };
    }

    // =========================
    // SUBCATEGORY FILTER BY SLUG
    // =========================
    if (subcategories.length > 0) {
      const matchedSubcategories = await Category.find({
        slug: { $in: subcategories },
      }).select("_id");

      const subcategoryIds = matchedSubcategories.map(
        (subcategory: any) => subcategory._id,
      );

      productQuery.subcategory = {
        $in: subcategoryIds,
      };
    }

    // =========================
    // SEARCH FILTER
    // =========================
    if (search) {
      productQuery.$or = [
        {
          name: {
            $regex: search,
            $options: "i",
          },
        },
        {
          description: {
            $regex: search,
            $options: "i",
          },
        },
        {
          shortDescription: {
            $regex: search,
            $options: "i",
          },
        },
      ];
    }

    // =========================
    // FETCH PRODUCTS
    // =========================
    let products = await Product.find(productQuery)
      .populate("category", "name slug")
      .populate("subcategory", "name slug")
      .lean();

    if (products.length === 0) {
      return NextResponse.json({
        success: true,
        data: [],
        pagination: {
          page,
          limit,
          total: 0,
          pages: 0,
        },
      });
    }

    // =========================
    // REVIEW FILTER
    // =========================
    // if (ratings.length > 0) {
    //   const minSelectedRating =
    //     Math.min(...ratings);

    //   const reviewStats =
    //     await ProductReview.aggregate([
    //       {
    //         $group: {
    //           _id: '$product',
    //           averageRating: {
    //             $avg: '$rating',
    //           },
    //         },
    //       },
    //     ]);

    //   const validProductIds =
    //     reviewStats
    //       .filter(
    //         (review) =>
    //           review.averageRating >=
    //           minSelectedRating
    //       )
    //       .map((review) =>
    //         review._id.toString()
    //       );

    //   products = products.filter(
    //     (product: any) =>
    //       validProductIds.includes(
    //         product._id.toString()
    //       )
    //   );
    // }

    if (ratings.length > 0) {
      const reviewStats = await ProductReview.aggregate([
        {
          $group: {
            _id: "$product",
            averageRating: {
              $avg: "$rating",
            },
          },
        },
      ]);

      const ratingSet = ratings;

      const ratingMap = new Map(
        reviewStats.map((review) => [
          review._id.toString(),
          review.averageRating,
        ]),
      );

      products = products.filter((product: any) => {
        const rating = ratingMap.get(product._id.toString()) ?? 0;

        // checkbox OR logic
        return ratingSet.some((selectedRating) => rating >= selectedRating);
      });
    }

    const productIds = products.map((product: any) => product._id);

    // =========================
    // SKU QUERY
    // =========================
    const skuQuery: any = {
      product: {
        $in: productIds,
      },
    };

    // =========================
    // COLOR FILTER
    // =========================
    if (colors.length > 0) {
      const colorObjectIds = colors
        .filter((id) => mongoose.Types.ObjectId.isValid(id))
        .map((id) => new mongoose.Types.ObjectId(id));

      if (colorObjectIds.length > 0) {
        skuQuery.color = {
          $in: colorObjectIds,
        };
      }
    }

    // =========================
    // SIZE FILTER
    // =========================
    if (sizes.length > 0) {
      const sizeObjectIds = sizes
        .filter((id) => mongoose.Types.ObjectId.isValid(id))
        .map((id) => new mongoose.Types.ObjectId(id));

      if (sizeObjectIds.length > 0) {
        skuQuery.size = {
          $in: sizeObjectIds,
        };
      }
    }

    // =========================
    // FETCH SKUS
    // =========================
    let skus = await ProductSKU.find(skuQuery)
      .populate("color", "name hexCode")
      // .populate("ProductColorImage", "images")
      .populate("size", "name sortOrder")
      .lean();
    const colorImages = await ProductColorImage.find({
      product: { $in: productIds },
    }).lean();
    const colorImageMap = new Map();

    colorImages.forEach((item: any) => {
      const productId = item.product.toString();
      const colorId = item.color.toString();

      const key = `${productId}_${colorId}`;

      const firstImage = item.images?.sort(
        (a: any, b: any) => (a.sortOrder || 0) - (b.sortOrder || 0),
      )[0];

      colorImageMap.set(
      key,
      item.images
        .sort((a: any, b: any) => (a.sortOrder || 0) - (b.sortOrder || 0))
        .map((img: any) => ({
          url: img.url,
          altText: img.altText || "",
          sortOrder: img.sortOrder || 0,
          isPrimary: img.isPrimary || false,
        })),
    );;
    });
    // =========================
    // PRICE FILTER
    // =========================
    if (minPrice || maxPrice) {
      const min = minPrice ? parseFloat(minPrice) : 0;

      const max = maxPrice ? parseFloat(maxPrice) : Infinity;

      products = products.filter((product: any) => {
        const productPrice = parseFloat(product.price?.toString() || "0");

        return productPrice >= min && productPrice <= max;
      });
    }

    // =========================
    // GROUP SKUS BY PRODUCT
    // =========================
    const productSkusMap = new Map<string, any[]>();

    skus.forEach((sku: any) => {
      const productId =
        sku.product instanceof mongoose.Types.ObjectId
          ? sku.product.toString()
          : sku.product._id
            ? sku.product._id.toString()
            : sku.product.toString();

      if (!productSkusMap.has(productId)) {
        productSkusMap.set(productId, []);
      }

      productSkusMap.get(productId)?.push(sku);
    });

    // =========================
    // FILTER PRODUCTS BASED ON SKUS
    // =========================
    const filteredProducts = products.filter((product: any) => {
      const productSkus = productSkusMap.get(product._id.toString());

      // If any SKU related filter applied
      if (colors.length > 0 || sizes.length > 0) {
        return productSkus && productSkus.length > 0;
      }

      return true;
    });

    // =========================
    // ENHANCE PRODUCTS
    // =========================

    let enhancedProducts = await Promise.all(
      filteredProducts.map(async (product: any) => {
        const productSkus = productSkusMap.get(product._id.toString()) || [];

        const productPrice = parseFloat(product.price?.toString() || "0");

        const totalQuantity = productSkus.reduce((sum: number, sku: any) => {
          return sum + (sku.quantity || 0);
        }, 0);

        // =========================
        // PRODUCT REVIEW
        // =========================
        const reviewData = await ProductReview.aggregate([
          {
            $match: {
              product: product._id,
            },
          },
          {
            $group: {
              _id: "$product",
              averageRating: {
                $avg: "$rating",
              },
              totalReviews: {
                $sum: 1,
              },
            },
          },
        ]);

        const averageRating = reviewData[0]?.averageRating || 0;

        const totalReviews = reviewData[0]?.totalReviews || 0;

        // =========================
        // GROUP SKUS BY COLOR
        // =========================
        const colorMap = new Map();

        productSkus.forEach((sku: any) => {
          if (!sku.color) return;

          const colorId = sku.color._id.toString();

          // Create color entry
          if (!colorMap.has(colorId)) {
            const imageKey = `${product._id.toString()}_${colorId}`;

            colorMap.set(colorId, {
              _id: sku.color._id,
              name: sku.color.name,
              hexCode: sku.color.hexCode,

              // single image only
              images: colorImageMap?.get(imageKey) || null,

              sizes: [],
            });
          }

          const colorData = colorMap.get(colorId);

          // Add size under color
          if (sku.size) {
            colorData.sizes.push({
              _id: sku.size._id,
              name: sku.size.name,
              sortOrder: sku.size.sortOrder,

              sku_id: sku._id,

              price: sku.price,
              quantity: sku.quantity || 0,
            });
          }
        });

        // =========================
        // SORT SIZES
        // =========================
        const variants = Array.from(colorMap.values()).map((color: any) => ({
          ...color,
          sizes: color.sizes.sort(
            (a: any, b: any) => (a.sortOrder || 0) - (b.sortOrder || 0),
          ),
        }));

        return {
          ...product,
          minPrice: productPrice,
          maxPrice: productPrice,

          totalQuantity,

          averageRating: Number(averageRating.toFixed(1)),

          totalReviews,

          variants,

          hasSkus: productSkus.length > 0,
        };
      }),
    );

    // =========================
    // SORTING
    // =========================
    enhancedProducts = applySorting(enhancedProducts, sortBy, sortOrder);

    // =========================
    // PAGINATION
    // =========================
    const total = enhancedProducts.length;

    const paginatedProducts = enhancedProducts.slice(skip, skip + limit);

    // =========================
    // FILTERS
    // =========================
    const allSkus = await ProductSKU.find({
      product: {
        $in: productIds,
      },
    })
      .populate("color", "name hexCode")
      .populate("size", "name sortOrder")
      .lean();

    const uniqueColors = [
      ...new Map(
        allSkus.map((sku: any) => [sku.color?._id?.toString(), sku.color]),
      ).values(),
    ].filter(Boolean);

    const uniqueSizes = [
      ...new Map(
        allSkus.map((sku: any) => [sku.size?._id?.toString(), sku.size]),
      ).values(),
    ].filter(Boolean);

    const allPrices = allSkus.map((sku: any) =>
      parseFloat(sku.price?.toString() || "0"),
    );

    const filters = {
      colors: uniqueColors,

      sizes: uniqueSizes,

      priceRange: {
        min: allPrices.length > 0 ? Math.min(...allPrices) : 0,

        max: allPrices.length > 0 ? Math.max(...allPrices) : 0,
      },

      reviewFilters: [
        {
          value: 4.5,
          label: "4.5 and above",
        },
        {
          value: 4,
          label: "4 and above",
        },
        {
          value: 3.5,
          label: "3.5 and above",
        },
        {
          value: 3,
          label: "3 and above",
        },
        {
          value: 0,
          label: "0 and above",
        },
      ],
    };

    // =========================
    // RESPONSE
    // =========================
    return NextResponse.json({
      success: true,

      data: paginatedProducts,

      pagination: {
        page,
        limit,
        total,
        pages: Math.ceil(total / limit),
      },

      filters,
    });
  } catch (error: any) {
    console.error("Error fetching products:", error);

    return NextResponse.json(
      {
        success: false,
        error: error.message || "Failed to fetch products",
      },
      {
        status: 500,
      },
    );
  }
}

// GET /api/products/:slug - Get single product by slug
export async function getProductBySlug(
  req: NextRequest,
  { params }: { params: Promise<{ slug: string }> },
) {
  try {
    await dbConnect();

    const { slug } = await params;

    // =========================
    // FETCH PRODUCT
    // =========================
    const product = await Product.findOne({
      slug,
    })
      .populate("category", "name slug")
      .populate("subcategory", "name slug")
      .lean();

    if (!product) {
      return NextResponse.json(
        {
          success: false,
          error: "Product not found",
        },
        {
          status: 404,
        },
      );
    }

    // =========================
    // FETCH PRODUCT SKUS
    // =========================
    const skus = await ProductSKU.find({
      product: product._id,
    })
      .populate("color", "name hexCode")
      .populate("size", "name sortOrder")
      .lean();

    // =========================
    // FETCH COLOR IMAGES
    // =========================
    const colorImages = await ProductColorImage.find({
      product: product._id,
    }).lean();

    // =========================
    // PRICE RANGE
    // =========================
    const prices = skus.map((sku: any) =>
      parseFloat(sku.price?.toString() || "0"),
    );

    const minPrice = prices.length > 0 ? Math.min(...prices) : 0;

    const maxPrice = prices.length > 0 ? Math.max(...prices) : 0;

    // =========================
    // COLOR IMAGE MAP
    // =========================
    const colorImageMap = new Map();

    colorImages.forEach((item: any) => {
      colorImageMap.set(
        item.color.toString(),
        item.images
          .sort((a: any, b: any) => (a.sortOrder || 0) - (b.sortOrder || 0))
          .map((img: any) => ({
            url: img.url,
            altText: img.altText || "",
            sortOrder: img.sortOrder || 0,
            isPrimary: img.isPrimary || false,
          })),
      );
    });

    // =========================
    // GROUP BY COLOR
    // =========================
    const colorMap = new Map();

    skus.forEach((sku: any) => {
      if (!sku.color) return;

      const colorId = sku.color._id.toString();

      // Create color object
      if (!colorMap.has(colorId)) {
        colorMap.set(colorId, {
          _id: sku.color._id,
          name: sku.color.name,
          hexCode: sku.color.hexCode,

          images: colorImageMap.get(colorId) || [],

          sizes: [],
        });
      }

      const colorData = colorMap.get(colorId);

      // Add size under color
      if (sku.size) {
        colorData.sizes.push({
          _id: sku.size._id,

          name: sku.size.name,

          sortOrder: sku.size.sortOrder || 0,

          sku_id: sku._id,

          sku: sku.sku,

          sku_quantity: sku.quantity || 0,

          price: parseFloat(sku.price?.toString() || "0"),

          comparePrice: parseFloat(sku.comparePrice?.toString() || "0"),
        });
      }
    });

    // =========================
    // SORT SIZES
    // =========================
    const variants = Array.from(colorMap.values()).map((color: any) => ({
      ...color,

      sizes: color.sizes.sort(
        (a: any, b: any) => (a.sortOrder || 0) - (b.sortOrder || 0),
      ),
    }));
    const reviews = await ProductReview.find({
      product: product._id,
      status: "approved",
    })
      // .populate({ path: 'customer', model: mongoose.models.User, select: 'name email avatar' })
      .lean();
    // =========================
    // RESPONSE
    // =========================
    const productWithDetails = {
      ...product,

      minPrice,

      maxPrice,

      variants,
      reviews,

      hasSkus: skus.length > 0,
    };

    return NextResponse.json({
      success: true,
      data: productWithDetails,
    });
  } catch (error: any) {
    console.error("Error fetching product:", error);

    return NextResponse.json(
      {
        success: false,
        error: error.message || "Failed to fetch product",
      },
      {
        status: 500,
      },
    );
  }
}

// GET /api/products/filters - Get all available filter options
// GET /api/products/filters - Get all available filter options
export async function getFilterOptionsAPI(req: NextRequest) {
  try {
    await dbConnect();
    // =========================
    // CATEGORIES
    // =========================
    const categories = await Category.find({
      isActive: true,
      level: 1,
    })
      .select("name slug")
      .lean();

    // =========================
    // SUBCATEGORIES
    // =========================
    const subcategories = await Category.find({
      isActive: true,
      level: 2,
    })
      .select("name slug parent")
      .populate("parent", "name slug")
      .lean();

    // =========================
    // COLORS
    // =========================
    const colors = await Color.find({
      isActive: true,
    })
      .select("name hexCode")
      .sort("name")
      .lean();

    // =========================
    // SIZES
    // =========================
    const sizes = await Size.find({
      isActive: true,
    })
      .select("name sortOrder")
      .sort("sortOrder")
      .lean();

    // =========================
    // PRICE RANGE
    // =========================
    const allSkus = await Product.find({}).select("price").lean();

    const allPrices = allSkus.map((sku: any) =>
      parseFloat(sku.price?.toString() || "0"),
    );

    const minPrice = allPrices.length > 0 ? Math.min(...allPrices) : 0;

    const maxPrice = allPrices.length > 0 ? Math.max(...allPrices) : 0;

    // =========================
    // REVIEW FILTERS
    // =========================
    const reviewFilters = [
      {
        value: 4.5,
        label: "4.5 and above",
      },
      {
        value: 4,
        label: "4 and above",
      },
      {
        value: 3.5,
        label: "3.5 and above",
      },
      {
        value: 3,
        label: "3 and above",
      },
      {
        value: 0,
        label: "0 and above",
      },
    ];

    return NextResponse.json({
      success: true,
      data: {
        categories,
        subcategories,
        colors,
        sizes,

        // NEW
        minPrice,
        maxPrice,

        // NEW
        reviewFilters,

        sortOptions: [
          {
            value: "createdAt_desc",
            label: "Newest First",
            sortBy: "createdAt",
            sortOrder: "desc",
          },
          {
            value: "createdAt_asc",
            label: "Oldest First",
            sortBy: "createdAt",
            sortOrder: "asc",
          },
          {
            value: "name_asc",
            label: "Name A-Z",
            sortBy: "name",
            sortOrder: "asc",
          },
          {
            value: "name_desc",
            label: "Name Z-A",
            sortBy: "name",
            sortOrder: "desc",
          },
          {
            value: "price_asc",
            label: "Price Low to High",
            sortBy: "price",
            sortOrder: "asc",
          },
          {
            value: "price_desc",
            label: "Price High to Low",
            sortBy: "price",
            sortOrder: "desc",
          },
        ],
      },
    });
  } catch (error: any) {
    console.error("Error fetching filter options:", error);

    return NextResponse.json(
      {
        success: false,
        error: error.message,
      },
      {
        status: 500,
      },
    );
  }
}

// Helper: Apply sorting
function applySorting(products: any[], sortBy: string, sortOrder: string) {
  const sorted = [...products];

  switch (sortBy) {
    case "name":
      sorted.sort((a, b) => {
        const comparison = a.name.localeCompare(b.name);
        return sortOrder === "asc" ? comparison : -comparison;
      });
      break;
    case "price":
      sorted.sort((a, b) => {
        const comparison = (a.minPrice || 0) - (b.minPrice || 0);
        return sortOrder === "asc" ? comparison : -comparison;
      });
      break;
    case "createdAt":
    default:
      sorted.sort((a, b) => {
        const comparison =
          new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime();
        return sortOrder === "asc" ? comparison : -comparison;
      });
      break;
  }

  return sorted;
}

// Helper: Get filter options based on products
async function getFilterOptions(
  productIds: any[],
  selectedColors: string[],
  selectedSizes: string[],
) {
  try {
    const skus = await ProductSKU.find({ product: { $in: productIds } })
      .populate("color", "name hexCode")
      .populate("size", "name sortOrder");

    const colorsMap = new Map();
    const sizesMap = new Map();

    skus.forEach((sku) => {
      if (sku.color && !colorsMap.has(sku.color._id.toString())) {
        colorsMap.set(sku.color._id.toString(), {
          _id: sku.color._id,
          name: sku.color.name,
          hexCode: sku.color.hexCode,
        });
      }
      if (sku.size && !sizesMap.has(sku.size._id.toString())) {
        sizesMap.set(sku.size._id.toString(), {
          _id: sku.size._id,
          name: sku.size.name,
          sortOrder: sku.size.sortOrder,
        });
      }
    });

    const prices = skus.map((sku) => parseFloat(sku.price.toString()));
    const minAvailablePrice = prices.length > 0 ? Math.min(...prices) : 0;
    const maxAvailablePrice = prices.length > 0 ? Math.max(...prices) : 0;

    return {
      colors: Array.from(colorsMap.values()),
      sizes: Array.from(sizesMap.values()).sort(
        (a, b) => (a.sortOrder || 0) - (b.sortOrder || 0),
      ),
      priceRange: {
        min: minAvailablePrice,
        max: maxAvailablePrice,
      },
    };
  } catch (error) {
    console.error("Error getting filter options:", error);
    return {
      colors: [],
      sizes: [],
      priceRange: { min: 0, max: 0 },
    };
  }
}

// Helper: Empty filter options
async function getEmptyFilterOptions() {
  return {
    colors: [],
    sizes: [],
    priceRange: { min: 0, max: 0 },
  };
}
