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('minRating') || ''
    )
      .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()
      )
  );
}

    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(
        'size',
        'name sortOrder'
      )
      .lean();

// =========================
// 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 prices = productSkus.map(
        (sku: any) =>
          parseFloat(
            sku.price?.toString() || '0'
          )
      );

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

      const maxProductPrice =
        prices.length > 0
          ? Math.max(...prices)
          : 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)) {
          colorMap.set(colorId, {
            _id: sku.color._id,
            name: sku.color.name,
            hexCode:
              sku.color.hexCode,
            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:
          minProductPrice,

        maxPrice:
          maxProductPrice,

        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 ProductSKU.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 }
  };
}