/**
 * Categories Validations
 * Validation rules for category operations
 */

// Import express-validator
const { body, param, query, validationResult } = require('express-validator');
// Import custom error class
const { ValidationError } = require('../../../utils/errors');

/**
 * Validation middleware
 * Checks validation results and throws error if validation fails
 * @param {Object} req - Express request object
 * @param {Object} res - Express response object
 * @param {Function} next - Express next middleware
 */
const validate = (req, res, next) => {
  // Get validation results
  const errors = validationResult(req); // Get validation errors
  
  // If validation errors exist, format and throw error
  if (!errors.isEmpty()) {
    // Format errors
    const formattedErrors = errors.array().map((error) => ({
      field: error.path || error.param, // Field name
      message: error.msg, // Error message
      value: error.value, // Invalid value
    }));
    
    // Throw validation error
    throw new ValidationError('Validation failed', formattedErrors); // Throw error
  }
  
  // Continue to next middleware
  next(); // Proceed
};

/**
 * Validation rules for creating category
 */
const validateCreateCategory = [
  // Validate name
  body('name')
    .notEmpty()
    .withMessage('Category name is required')
    .trim()
    .isLength({ min: 1, max: 150 })
    .withMessage('Category name must be between 1 and 150 characters'),
  
  // Validate parent_id (optional)
  body('parent_id')
    .optional()
    .isInt({ min: 1 })
    .withMessage('Parent ID must be a positive integer')
    .toInt(), // Convert to integer
  
  // Validate slug (optional)
  body('slug')
    .optional()
    .trim()
    .isLength({ max: 150 })
    .withMessage('Slug must not exceed 150 characters')
    .matches(/^[a-z0-9-]+$/)
    .withMessage('Slug must contain only lowercase letters, numbers, and hyphens'),
  
  // Validate description (optional)
  body('description')
    .optional()
    .trim(),
  
  // Validate image_url (optional)
  body('image_url')
    .optional()
    .trim()
    .isURL()
    .withMessage('Image URL must be a valid URL')
    .isLength({ max: 255 })
    .withMessage('Image URL must not exceed 255 characters'),
  
  // Validate sort_order (optional)
  body('sort_order')
    .optional()
    .isInt({ min: 0 })
    .withMessage('Sort order must be a non-negative integer')
    .toInt(), // Convert to integer
  
  // Run validation
  validate, // Validate request
];

/**
 * Validation rules for updating category
 */
const validateUpdateCategory = [
  // Validate id parameter
  param('id')
    .notEmpty()
    .withMessage('Category ID is required')
    .isInt({ min: 1 })
    .withMessage('Category ID must be a positive integer')
    .toInt(), // Convert to integer
  
  // Validate name (optional)
  body('name')
    .optional()
    .trim()
    .isLength({ min: 1, max: 150 })
    .withMessage('Category name must be between 1 and 150 characters'),
  
  // Validate parent_id (optional)
  body('parent_id')
    .optional()
    .custom((value) => {
      // Accept null or positive integer
      if (value === null || value === 'null') return true; // Accept null
      const num = parseInt(value, 10); // Parse to integer
      if (isNaN(num) || num < 1) throw new Error('Parent ID must be a positive integer or null'); // Validate
      return true; // Validation passed
    }),
  
  // Validate slug (optional)
  body('slug')
    .optional()
    .trim()
    .isLength({ max: 150 })
    .withMessage('Slug must not exceed 150 characters')
    .matches(/^[a-z0-9-]+$/)
    .withMessage('Slug must contain only lowercase letters, numbers, and hyphens'),
  
  // Validate description (optional)
  body('description')
    .optional()
    .trim(),
  
  // Validate image_url (optional)
  body('image_url')
    .optional()
    .trim()
    .isURL()
    .withMessage('Image URL must be a valid URL')
    .isLength({ max: 255 })
    .withMessage('Image URL must not exceed 255 characters'),
  
  // Validate sort_order (optional)
  body('sort_order')
    .optional()
    .isInt({ min: 0 })
    .withMessage('Sort order must be a non-negative integer')
    .toInt(), // Convert to integer
  
  // Run validation
  validate, // Validate request
];

/**
 * Validation rules for getting category by ID
 */
const validateGetCategory = [
  // Validate id parameter
  param('id')
    .notEmpty()
    .withMessage('Category ID is required')
    .isInt({ min: 1 })
    .withMessage('Category ID must be a positive integer')
    .toInt(), // Convert to integer
  
  // Run validation
  validate, // Validate request
];

/**
 * Validation rules for deleting category
 */
const validateDeleteCategory = [
  // Validate id parameter
  param('id')
    .notEmpty()
    .withMessage('Category ID is required')
    .isInt({ min: 1 })
    .withMessage('Category ID must be a positive integer')
    .toInt(), // Convert to integer
  
  // Run validation
  validate, // Validate request
];

/**
 * Validation rules for listing categories
 */
const validateListCategories = [
  // Validate page query parameter
  query('page')
    .optional()
    .isInt({ min: 1 })
    .withMessage('Page must be a positive integer')
    .toInt(), // Convert to integer
  
  // Validate limit query parameter
  query('limit')
    .optional()
    .isInt({ min: 1, max: 100 })
    .withMessage('Limit must be between 1 and 100')
    .toInt(), // Convert to integer
  
  // Validate parent_id query parameter
  query('parent_id')
    .optional()
    .custom((value) => {
      // Accept null string or positive integer
      if (value === 'null' || value === null || value === undefined) return true; // Accept null
      const num = parseInt(value, 10); // Parse to integer
      if (isNaN(num) || num < 1) throw new Error('Parent ID must be a positive integer or null'); // Validate
      return true; // Validation passed
    }),
  
  // Validate with_children query parameter
  query('with_children')
    .optional()
    .isIn(['true', 'false'])
    .withMessage('with_children must be "true" or "false"'),
  
  // Run validation
  validate, // Validate request
];

/**
 * Validation rules for getting category hierarchy
 */
const validateGetCategoryHierarchy = [
  // Validate root_category_id query parameter
  query('root_category_id')
    .optional()
    .isInt({ min: 1 })
    .withMessage('Root category ID must be a positive integer')
    .toInt(), // Convert to integer
  
  // Run validation
  validate, // Validate request
];

/**
 * Validation rules for assigning product to categories
 */
const validateAssignProductToCategories = [
  // Validate productId parameter
  param('productId')
    .notEmpty()
    .withMessage('Product ID is required')
    .isInt({ min: 1 })
    .withMessage('Product ID must be a positive integer')
    .toInt(), // Convert to integer
  
  // Validate category_ids
  body('category_ids')
    .notEmpty()
    .withMessage('Category IDs are required')
    .isArray({ min: 1 })
    .withMessage('Category IDs must be a non-empty array')
    .custom((value) => {
      // Validate each category ID
      for (const id of value) {
        const num = parseInt(id, 10); // Parse to integer
        if (isNaN(num) || num < 1) {
          throw new Error('Each category ID must be a positive integer'); // Throw error if invalid
        }
      }
      return true; // Validation passed
    }),
  
  // Validate primary_category_id (optional)
  body('primary_category_id')
    .optional()
    .isInt({ min: 1 })
    .withMessage('Primary category ID must be a positive integer')
    .toInt(), // Convert to integer
  
  // Run validation
  validate, // Validate request
];

/**
 * Validation rules for removing product from category
 */
const validateRemoveProductFromCategory = [
  // Validate productId parameter
  param('productId')
    .notEmpty()
    .withMessage('Product ID is required')
    .isInt({ min: 1 })
    .withMessage('Product ID must be a positive integer')
    .toInt(), // Convert to integer
  
  // Validate categoryId parameter
  param('categoryId')
    .notEmpty()
    .withMessage('Category ID is required')
    .isInt({ min: 1 })
    .withMessage('Category ID must be a positive integer')
    .toInt(), // Convert to integer
  
  // Run validation
  validate, // Validate request
];

/**
 * Validation rules for getting product categories
 */
const validateGetProductCategories = [
  // Validate productId parameter
  param('productId')
    .notEmpty()
    .withMessage('Product ID is required')
    .isInt({ min: 1 })
    .withMessage('Product ID must be a positive integer')
    .toInt(), // Convert to integer
  
  // Run validation
  validate, // Validate request
];

// Export validation rules
module.exports = {
  validateCreateCategory, // Create category validation
  validateUpdateCategory, // Update category validation
  validateGetCategory, // Get category validation
  validateDeleteCategory, // Delete category validation
  validateListCategories, // List categories validation
  validateGetCategoryHierarchy, // Get category hierarchy validation
  validateAssignProductToCategories, // Assign product to categories validation
  validateRemoveProductFromCategory, // Remove product from category validation
  validateGetProductCategories, // Get product categories validation
};

