// @ts-nocheck
import { Request, Response } from 'express';
import asyncHandler from '../utils/asyncHandler';
import ApiError from '../utils/apiError';
import ApiResponse from '../utils/apiResponse';
import prisma from '../DB/db';
import { Prisma } from '@prisma/client';

// --- Get All Products (Filter, Search, Sort, Paginate) ---
// Helper to recursively get all sub-category IDs
// (You need this for the category filter to work properly)
const getAllCategoryIds = async (rootId: string): Promise<string[]> => {
  const categories = await prisma.category.findMany({
    where: { parentId: rootId },
    select: { id: true },
  });

  let ids = [rootId];
  for (const cat of categories) {
    const subIds = await getAllCategoryIds(cat.id);
    ids = [...ids, ...subIds];
  }
  return ids;
};

export const getProducts = asyncHandler(async (req: Request, res: Response) => {
  const { page, limit, search, category, minPrice, maxPrice, sort } = req.query;

  // ================= PAGINATION =================
  const pageNum = Math.max(Number(page) || 1, 1);
  const limitNum = Math.min(Math.max(Number(limit) || 12, 1), 50);
  const skip = (pageNum - 1) * limitNum;

  // ================= BUILD FILTERS =================
  // We use a separate array to build 'AND' conditions to satisfy TypeScript
  const andConditions: Prisma.ProductWhereInput[] = [
    { isArchived: false }, // Always exclude archived
  ];

  // 🔍 Search (Name OR Description)
  if (search) {
    const searchTerm = String(search).trim();
    andConditions.push({
      OR: [
        { name: { contains: searchTerm, mode: 'insensitive' } },
        { description: { contains: searchTerm, mode: 'insensitive' } },
      ],
    });
  }

  // 🧵 Category (Include Subcategories)
  if (category) {
    const categoryParam = String(category).trim();

    // 1. Try finding by NAME first using findFirst (Case Insensitive)
    // We use findFirst because 'name' is usually not unique
    let categoryRecord = await prisma.category.findFirst({
      where: {
        name: { equals: categoryParam, mode: 'insensitive' },
      },
      select: { id: true },
    });

    // 2. If not found by Name, try finding by SLUG (Exact match)
    if (!categoryRecord) {
      categoryRecord = await prisma.category.findUnique({
        where: { slug: categoryParam },
        select: { id: true },
      });
    }

    // 3. Apply Filter
    if (categoryRecord) {
      const categoryIds = await getAllCategoryIds(categoryRecord.id);

      // Push to your filter array
      andConditions.push({
        categoryId: { in: categoryIds },
      });
    } else {
      // Edge case: Category not found -> Return 0 results
      andConditions.push({ categoryId: 'invalid_id_force_empty' });
    }
  }

  // 💰 Price Filter
  if (minPrice || maxPrice) {
    const priceFilter: Prisma.DecimalFilter = {};
    if (minPrice) priceFilter.gte = new Prisma.Decimal(Number(minPrice));
    if (maxPrice) priceFilter.lte = new Prisma.Decimal(Number(maxPrice));

    andConditions.push({ price: priceFilter });
  }

  // ================= COMBINE CLAUSE =================
  const whereClause: Prisma.ProductWhereInput = {
    AND: andConditions,
  };

  // ================= SORTING =================
  const sortOption = String(sort || 'latest');
  let orderBy: Prisma.ProductOrderByWithRelationInput = { createdAt: 'desc' };

  switch (sortOption) {
    case 'price-low':
      orderBy = { price: 'asc' };
      break;
    case 'price-high':
      orderBy = { price: 'desc' };
      break;
    case 'latest':
    default:
      orderBy = { createdAt: 'desc' };
  }

  // ================= EXECUTE QUERY =================
  const [products, total] = await prisma.$transaction([
    prisma.product.findMany({
      where: whereClause,
      orderBy,
      skip,
      take: limitNum,
      include: {
        category: {
          select: { name: true, slug: true }, // Select only needed fields
        },
        variants: true, // Fetch variants for UI selection
      },
    }),
    prisma.product.count({ where: whereClause }),
  ]);

  return res.status(200).json(
    new ApiResponse(true, 200, 'Products fetched successfully', {
      products,
      pagination: {
        total,
        page: pageNum,
        limit: limitNum,
        pages: Math.ceil(total / limitNum),
      },
    })
  );
});

// --- Get Single Product by Slug or ID ---
export const getProductById = asyncHandler(async (req: Request, res: Response) => {
  const { id } = req.params;

  const product = await prisma.product.findFirst({
    where: {
      OR: [{ id }, { slug: id }],
    },
    include: {
      variants: true,
      category: true,
      reviews: {
        include: { user: { select: { fullName: true, image: true } } },
        orderBy: { createdAt: 'desc' },
        take: 5,
      },
    },
  });

  if (!product) {
    throw new ApiError(false, 404, 'Product not found');
  }

  return res.status(200).json(new ApiResponse(true, 200, 'Product fetched successfully', product));
});

// --- Get This Month's Favorite Products (Best Sellers) ---
export const getMonthlyFavorites = asyncHandler(async (req: Request, res: Response) => {
  // 1. Calculate Start of Month
  const now = new Date();
  const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);

  // 2. Aggregate: Find top selling product IDs this month
  const topSellingItems = await prisma.orderItem.groupBy({
    by: ['productId'],
    _sum: {
      quantity: true,
    },
    where: {
      order: {
        createdAt: {
          gte: startOfMonth, // From start of this month
        },
        status: {
          not: 'CANCELLED', // Exclude cancelled orders
        },
      },
    },
    orderBy: {
      _sum: {
        quantity: 'desc',
      },
    },
    take: 4,
  });

  // If no sales this month, return empty or fallback logic (e.g., all-time best sellers)
  if (topSellingItems.length === 0) {
    return res.status(200).json(new ApiResponse(false, 200, 'No trending products this month'));
  }

  // 3. Fetch Product Details
  // Note: findMany does not preserve the order of the IDs in the 'where' clause
  const productIds = topSellingItems.map((item) => item.productId);

  const products = await prisma.product.findMany({
    where: {
      id: { in: productIds },
    },
    select: {
      id: true,
      name: true,
      slug: true,
      price: true,
      compareAtPrice: true,
      images: true,
      stock: true, // or stoke
      category: {
        select: { name: true, slug: true },
      },
      variants: true,
    },
  });

  const sortedProducts = topSellingItems
    .map((item) => products.find((p) => p.id === item.productId))
    .filter(Boolean); // Remove any nulls if product was deleted

  return res
    .status(200)
    .json(
      new ApiResponse(true, 200, 'Monthly favorite products fetched successfully', sortedProducts)
    );
});

// Get Discounted Products
export const getDiscountedProducts = asyncHandler(async (req, res) => {
  const getProducts = await prisma.product.findMany({
    where: {
      compareAtPrice: {
        gt: 0,
      },
    },
    take: 4,
    orderBy: {
      createdAt: 'desc',
    },
    include: {
      category: true,
      variants: true,
    },
  });

  res.status(200).json(new ApiResponse(true, 200, 'Successfully get Products', getProducts));

});


// get features Products 
export const getFeaturesProducts=asyncHandler(async(req ,res)=>{

  const featuredProducts=await prisma.product.findMany({
    where:{
      isFeatured:true
    },
    include:{
      category:true,
      variants:true
    },
    take:4,
    orderBy:{
      createdAt:"desc"
    }
  })
 res.status(200).json(new ApiResponse(true, 200, 'Successfully get Products', featuredProducts));

})
