text: import asyncHandler from 'express-async-handler'
  import Product from '../models/productModel.js'
  import Variant from '../models/variantModel.js'
  
  
  // @desc    Fetch all categories
  // @route   GET /api/products/categories
  // @access  Public
  const getCategories = asyncHandler(async (req, res) => {
    const categories = await Product.find({}).select('category').distinct('category');
    res.json({ categories: ["All", ...categories] })
  })
  
  // @desc    Fetch all products
  // @route   GET /api/products
  // @access  Public
  const getProducts = asyncHandler(async (req, res) => {
    const pageSize = 12
    const page = Number(req.query.pageNumber) || 1
  
    const keyword = req.query.keyword && req.query.keyword !== 'All'
      ? {
        name: {
          $regex: req.query.keyword,
          $options: 'i',
        },
      }
      : {}
    const category = req.query.category !== 'All'
      ? {
        category: {
          $regex: req.query.category,
          $options: 'i',
        },
      }
      : {}
  
    const price = req.query.price > 0
      ? {
        price: {
          $lte: req.query.price,
        },
      }
      : {}
  
    const count = await Product.countDocuments({ ...keyword, ...category, ...price })
    const products = await Product.find({ ...keyword, ...category, ...price })
      .limit(pageSize)
      .skip(pageSize * (page - 1))
  
    res.json({ products, page, pages: Math.ceil(count / pageSize) })
  })
  
  // @desc    Fetch single product
  // @route   GET /api/products/:id
  // @access  Public
  const getProductById = asyncHandler(async (req, res) => {
    const product = await Product.findById(req.params.id)
    const variants = await Variant.find({ type: 'Size' })
  
    if (product) {
      res.json({ product, variants })
    } else {
      res.status(404)
      throw new Error('Product not found')
    }
  })
  
  // @desc    Delete a product
  // @route   DELETE /api/products/:id
  // @access  Private/Admin
  const deleteProduct = asyncHandler(async (req, res) => {
    const product = await Product.findById(req.params.id)
  
    if (product) {
      await product.remove()
      res.json({ message: 'Product removed' })
    } else {
      res.status(404)
      throw new Error('Product not found')
    }
  })
  
  // @desc    Create a product
  // @route   POST /api/products
  // @access  Private/Admin
  const createProduct = asyncHandler(async (req, res) => {
    const product = new Product({
      name: 'Sample name',
      price: 0,
      user: req.user._id,
      image: '/images/sample.jpg',
      brand: 'Sample brand',
      category: 'Sample category',
      countInStock: 0,
      numReviews: 0,
      description: 'Sample description',
    })
    const variants = await Variant.find({ type: 'Size' })
    variants.map((variant) => {
      product.variants.push({ name: variant.name })
    })
  
  
    const createdProduct = await product.save()
    res.status(201).json(createdProduct)
  })
  
  // @desc    Update a product
  // @route   PUT /api/products/:id
  // @access  Private/Admin
  const updateProduct = asyncHandler(async (req, res) => {
    const {
      name,
      price,
      description,
      image,
      brand,
      category,
      countInStock,
      sizeVariants
    } = req.body
    const product = await Product.findById(req.params.id)
  
    if (product) {
      product.name = name
      product.price = price
      product.description = description
      product.image = image
      product.brand = brand
      product.category = category
      product.countInStock = countInStock
      let variants = []
      sizeVariants.map((variant) => {
        variants.push({ name: variant })
      })
      product.variants = variants
      const updatedProduct = await product.save()
      res.json(updatedProduct)
    } else {
      res.status(404)
      throw new Error('Product not found')
    }
  })
  
  // @desc    Create new review
  // @route   POST /api/products/:id/reviews
  // @access  Private
  const createProductReview = asyncHandler(async (req, res) => {
    const { rating, comment } = req.body
  
    const product = await Product.findById(req.params.id)
  
    if (product) {
      const alreadyReviewed = product.reviews.find(
        (r) => r.user.toString() === req.user._id.toString()
      )
  
      if (alreadyReviewed) {
        res.status(400)
        throw new Error('Product already reviewed')
      }
  
      const review = {
        name: req.user.name,
        rating: Number(rating),
        comment,
        user: req.user._id,
      }
  
      product.reviews.push(review)
  
      product.numReviews = product.reviews.length
  
      product.rating =
        product.reviews.reduce((acc, item) => item.rating + acc, 0) /
        product.reviews.length
  
      await product.save()
      res.status(201).json({ message: 'Review added' })
    } else {
      res.status(404)
      throw new Error('Product not found')
    }
  })
  
  // @desc    Get top rated products
  // @route   GET /api/products/top
  // @access  Public
  const getTopProducts = asyncHandler(async (req, res) => {
    const products = await Product.find({}).sort({ rating: -1 }).limit(3)
  
    res.json(products)
  })
  
  export {
    getProducts,
    getProductById,
    deleteProduct,
    createProduct,
    updateProduct,
    createProductReview,
    getTopProducts,
    getCategories
  }
  