/**
 * Categories Controllers
 * Request handlers for category operations
 */

// Import category service functions
const categoryService = require('../services');
// Import async handler wrapper
const asyncHandler = require('../../../middlewares/asyncHandler');
// Import response helpers
const { success: successResponse } = require('../../../utils/response');
// Import logger
const logger = require('../../../utils/logger');
// Import custom error classes
const { ValidationError } = require('../../../utils/errors');

/**
 * Create category
 * Creates a new category
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
const createCategory = asyncHandler(async (req, res) => {
  // Extract category data from request body
  const categoryData = req.body; // Get category data
  
  // Create category using service
  const category = await categoryService.createCategory(categoryData); // Create category
  
  // Log category creation
  logger.info('Category created', {
    categoryId: category.id,
    name: category.name,
    parentId: category.parent_id,
  });
  
  // Return success response with category data
  return successResponse(res, category, 'Category created successfully', 201); // Return success response
});

/**
 * Get category by ID
 * Retrieves a category with details
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
const getCategory = asyncHandler(async (req, res) => {
  // Extract category ID from request params
  const { id } = req.params; // Get category ID
  
  // Get category using service
  const category = await categoryService.getCategory(parseInt(id)); // Get category
  
  // Return success response with category data
  return successResponse(res, category, 'Category retrieved successfully'); // Return success response
});

/**
 * Update category
 * Updates an existing category
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
const updateCategory = asyncHandler(async (req, res) => {
  // Extract category ID from request params
  const { id } = req.params; // Get category ID
  // Extract update data from request body
  const updateData = req.body; // Get update data
  
  // Update category using service
  const category = await categoryService.updateCategory(parseInt(id), updateData); // Update category
  
  // Log category update
  logger.info('Category updated', {
    categoryId: id,
    updateData,
  });
  
  // Return success response with updated category data
  return successResponse(res, category, 'Category updated successfully'); // Return success response
});

/**
 * Delete category
 * Deletes a category
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
const deleteCategory = asyncHandler(async (req, res) => {
  // Extract category ID from request params
  const { id } = req.params; // Get category ID
  
  // Delete category using service
  await categoryService.deleteCategory(parseInt(id)); // Delete category
  
  // Log category deletion
  logger.info('Category deleted', {
    categoryId: id,
  });
  
  // Return success response
  return successResponse(res, null, 'Category deleted successfully'); // Return success response
});

/**
 * List categories
 * Retrieves paginated list of categories with filters
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
const listCategories = asyncHandler(async (req, res) => {
  // Extract query parameters
  const {
    page = 1, // Page number (default: 1)
    limit = 10, // Items per page (default: 10)
    parent_id, // Filter by parent ID
    with_children = false, // Include children (default: false)
  } = req.query; // Extract query parameters
  
  // Build options object
  const options = {
    page: parseInt(page), // Convert to integer
    limit: parseInt(limit), // Convert to integer
    parentId: parent_id !== undefined ? (parent_id === 'null' ? null : parseInt(parent_id)) : undefined, // Convert to integer or null
    withChildren: with_children === 'true', // Convert to boolean
  };
  
  // List categories using service
  const result = await categoryService.listCategories(options); // List categories
  
  // Return success response with categories and pagination
  return successResponse(res, result, 'Categories retrieved successfully'); // Return success response
});

/**
 * Get category hierarchy
 * Retrieves full category hierarchy (tree structure)
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
const getCategoryHierarchy = asyncHandler(async (req, res) => {
  // Extract root category ID from query params (optional)
  const { root_category_id } = req.query; // Get root category ID
  
  // Get category hierarchy using service
  const hierarchy = await categoryService.getCategoryHierarchy(
    root_category_id ? parseInt(root_category_id) : null // Convert to integer if provided
  ); // Get hierarchy
  
  // Return success response with hierarchy
  return successResponse(res, hierarchy, 'Category hierarchy retrieved successfully'); // Return success response
});

/**
 * Assign product to categories
 * Assigns a product to one or more categories
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
const assignProductToCategories = asyncHandler(async (req, res) => {
  // Extract product ID from request params
  const { productId } = req.params; // Get product ID
  // Extract category IDs and primary category ID from request body
  const { category_ids, primary_category_id = null } = req.body; // Get category IDs and primary category ID
  
  // Validate category_ids is an array
  if (!Array.isArray(category_ids) || category_ids.length === 0) {
    throw new ValidationError('category_ids must be a non-empty array'); // Throw error if invalid
  }
  
  // Assign product to categories using service
  const assignments = await categoryService.assignProductToCategories(
    parseInt(productId), // Convert to integer
    category_ids.map(id => parseInt(id)), // Convert all to integers
    primary_category_id ? parseInt(primary_category_id) : null // Convert to integer if provided
  ); // Assign categories
  
  // Log assignment
  logger.info('Product assigned to categories', {
    productId,
    categoryIds: category_ids,
    primaryCategoryId: primary_category_id,
  });
  
  // Return success response with assignments
  return successResponse(res, assignments, 'Product assigned to categories successfully', 201); // Return success response
});

/**
 * Remove product from category
 * Removes a product from a category
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
const removeProductFromCategory = asyncHandler(async (req, res) => {
  // Extract product ID and category ID from request params
  const { productId, categoryId } = req.params; // Get product ID and category ID
  
  // Remove product from category using service
  await categoryService.removeProductFromCategory(
    parseInt(productId), // Convert to integer
    parseInt(categoryId) // Convert to integer
  ); // Remove from category
  
  // Log removal
  logger.info('Product removed from category', {
    productId,
    categoryId,
  });
  
  // Return success response
  return successResponse(res, null, 'Product removed from category successfully'); // Return success response
});

/**
 * Get product categories
 * Retrieves all categories for a product
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 */
const getProductCategories = asyncHandler(async (req, res) => {
  // Extract product ID from request params
  const { productId } = req.params; // Get product ID
  
  // Get product categories using service
  const productCategories = await categoryService.getProductCategories(parseInt(productId)); // Get categories
  
  // Transform to simpler format
  const categories = productCategories.map(pc => {
    const categoryData = pc.toJSON ? pc.toJSON() : pc;
    return {
      id: categoryData.id,
      product_id: categoryData.product_id,
      category_id: categoryData.category_id || categoryData.category?.id,
      is_primary: categoryData.is_primary,
      category: categoryData.category ? {
        id: categoryData.category.id,
        name: categoryData.category.name,
        slug: categoryData.category.slug,
      } : null,
    };
  });
  
  // Return success response with categories
  return successResponse(res, { categories }, 'Product categories retrieved successfully'); // Return success response
});

// Export controllers
module.exports = {
  createCategory, // Create category controller
  getCategory, // Get category controller
  updateCategory, // Update category controller
  deleteCategory, // Delete category controller
  listCategories, // List categories controller
  getCategoryHierarchy, // Get category hierarchy controller
  assignProductToCategories, // Assign product to categories controller
  removeProductFromCategory, // Remove product from category controller
  getProductCategories, // Get product categories controller
};

