Source: models/product.model.js

import Product from "./product.mongo.js";
import logger from "../config/logger.js";

/**
 * @desc    Retrieve all products from the database (regardless of publish status)
 * @returns {Promise<Array>}  Array of product documents
 */
async function getAllProducts() {
  try {
    const products = await Product.find({});
    return products;
  } catch (error) {
    logger.error(`[products.model] Error fetching products: ${error}`);
    throw error;
  }
}

/**
 * @desc      Retrieve all products where isPublished is true
 * @returns   {Promise<Array>} Array of published product documents
 */
async function getAllPublishedProducts() {
  try {
    return await Product.find({ isPublished: true });
  } catch (error) {
    logger.error(
      `[products.model] Error fetching published products: ${error.message}`
    );
    throw error;
  }
}

/**
 * @desc    Retrieve the count of all products where isPublished is true
 * @returns {Promise<Number>} Count of published product documents
 */
async function countPublishedProducts() {
  try {
    return await Product.countDocuments({ isPublished: true });
  } catch (error) {
    logger.error(
      `[products.model] Error counting published products: ${error.message}`
    );
    throw error;
  }
}

/**
 * @desc    Retrieve a paginated set of published products
 * @param   {Number} page - Page number of results to return
 * @param   {Number} limit - Number of results per page
 * @returns {Promise<Array>} Array of published product documents
 * @throws  {Error} When there is an error fetching the paginated products
 */
async function getPaginatedPublishedProducts(page, limit) {
  try {
    const startIndex = (page - 1) * limit;

    return await Product.find({ isPublished: true })
      .sort({ createdAt: -1 })
      .skip(startIndex)
      .limit(limit);
  } catch (error) {
    logger.error(
      `[products.model] Error fetching paginated products: ${error.message}`
    );
    throw error;
  }
}

/**
 * @desc    Retrieve a single product by its MongoDB _id
 * @param   {String} id - Product ID
 * @returns {Promise<Object|null>} Product document or null if not found
 */
async function getProductById(id) {
  try {
    return await Product.findById(id);
  } catch (error) {
    logger.error(
      `[products.model] Error finding product by id ${id}: ${error.message}`
    );
    throw error;
  }
}

/**
 * @desc    Create a new product document in the database
 * @param   {Object} data - Product data (matches schema shape)
 * @returns {Promise<Object>} Created product document
 */
async function createProduct(data) {
  try {
    const product = await Product.create(data);
    return product;
  } catch (error) {
    logger.error(`[products.model] Error creating product: ${error.message}`);
    throw error;
  }
}

/**
 * @desc    Update a product document by ID
 * @param   {String} id - Product ID
 * @param   {Object} updates - Updated fields
 * @returns {Promise<Object|null>} Updated product or null if not found
 */
async function updateProduct(id, updates) {
  try {
    const updated = await Product.findByIdAndUpdate(id, updates, {
      new: true,
      runValidators: true,
    });
    return updated;
  } catch (error) {
    logger.error(
      `[products.model] Error updating product ${id}: ${error.message}`
    );
    throw error;
  }
}

/**
 * @desc    Delete a product by its ID
 * @param   {String} id - Product ID
 * @returns {Promise<Object|null>} Deleted document or null if not found
 */
async function deleteProduct(id) {
  try {
    const result = await Product.findByIdAndDelete(id);
    return result;
  } catch (error) {
    logger.error(
      `[products.model] Error deleting product ${id}: ${error.message}`
    );
    throw error;
  }
}

export {
  getAllProducts,
  getAllPublishedProducts,
  getPaginatedPublishedProducts,
  countPublishedProducts,
  getProductById,
  createProduct,
  updateProduct,
  deleteProduct,
};