/**
 * Input Validation Utilities
 * Reusable validation functions with consistent error messages
 */

const { AppError } = require("../middleware/errorHandler");
const { HTTP_STATUS } = require("../config/constants");

/**
 * Validate required fields
 * @param {Object} data - Data object to validate
 * @param {string[]} requiredFields - Array of required field names
 * @throws {AppError} If validation fails
 */
const validateRequiredFields = (data, requiredFields) => {
  const missingFields = requiredFields.filter(
    (field) =>
      !data[field] ||
      (typeof data[field] === "string" && data[field].trim() === ""),
  );

  if (missingFields.length > 0) {
    throw new AppError(
      `Missing required fields: ${missingFields.join(", ")}`,
      HTTP_STATUS.BAD_REQUEST,
    );
  }
};

/**
 * Validate email format
 * @param {string} email - Email to validate
 * @returns {boolean} True if valid
 */
const isValidEmail = (email) => {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
};

/**
 * Validate email field
 * @param {string} email - Email to validate
 * @throws {AppError} If validation fails
 */
const validateEmail = (email) => {
  if (!email || !isValidEmail(email)) {
    throw new AppError("Invalid email format", HTTP_STATUS.BAD_REQUEST);
  }
};

/**
 * Validate UUID format
 * @param {string} id - UUID to validate
 * @returns {boolean} True if valid UUID
 */
const isValidUUID = (id) => {
  const uuidRegex =
    /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
  return uuidRegex.test(id);
};

/**
 * Validate number range
 * @param {number} value - Value to validate
 * @param {number} min - Minimum value
 * @param {number} max - Maximum value
 * @param {string} fieldName - Field name for error message
 * @throws {AppError} If validation fails
 */
const validateNumberRange = (value, min, max, fieldName = "Value") => {
  const num = parseFloat(value);
  if (isNaN(num) || num < min || num > max) {
    throw new AppError(
      `${fieldName} must be between ${min} and ${max}`,
      HTTP_STATUS.BAD_REQUEST,
    );
  }
  return num;
};

/**
 * Validate string length
 * @param {string} value - String to validate
 * @param {number} min - Minimum length
 * @param {number} max - Maximum length
 * @param {string} fieldName - Field name for error message
 * @throws {AppError} If validation fails
 */
const validateStringLength = (value, min, max, fieldName = "Field") => {
  if (!value || value.length < min || value.length > max) {
    throw new AppError(
      `${fieldName} must be between ${min} and ${max} characters`,
      HTTP_STATUS.BAD_REQUEST,
    );
  }
};

/**
 * Sanitize string input (remove HTML tags, trim)
 * @param {string} input - String to sanitize
 * @returns {string} Sanitized string
 */
const sanitizeString = (input) => {
  if (typeof input !== "string") return "";
  return input
    .replace(/<[^>]*>/g, "") // Remove HTML tags
    .trim();
};

/**
 * Validate and sanitize slug
 * @param {string} slug - Slug to validate
 * @returns {string} Valid slug
 * @throws {AppError} If validation fails
 */
const validateSlug = (slug) => {
  const slugRegex = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
  const sanitized = slug.toLowerCase().trim();

  if (!slugRegex.test(sanitized)) {
    throw new AppError(
      "Slug can only contain lowercase letters, numbers, and hyphens",
      HTTP_STATUS.BAD_REQUEST,
    );
  }

  return sanitized;
};

/**
 * Generate slug from string
 * @param {string} text - Text to convert to slug
 * @returns {string} Generated slug
 */
const generateSlug = (text) => {
  return text
    .toLowerCase()
    .replace(/[^a-z0-9\s-]/g, "")
    .replace(/\s+/g, "-")
    .replace(/-+/g, "-")
    .trim();
};

/**
 * Validate pagination parameters
 * @param {Object} query - Query parameters
 * @returns {Object} Validated pagination params
 */
const validatePagination = (query) => {
  const page = Math.max(1, parseInt(query.page) || 1);
  const limit = Math.min(100, Math.max(1, parseInt(query.limit) || 20));

  return { page, limit };
};

/**
 * Validate image file
 * @param {Object} file - Multer file object
 * @throws {AppError} If validation fails
 */
const validateImageFile = (file) => {
  const allowedMimeTypes = [
    "image/jpeg",
    "image/jpg",
    "image/png",
    "image/gif",
    "image/webp",
    "image/bmp",
    "image/tiff",
    "image/svg+xml",
    "image/x-icon",
    "image/vnd.microsoft.icon",
    "image/ico",
    "image/avif",
    "image/heic",
    "image/heif",
  ];
  const maxSize = 10 * 1024 * 1024; // 10MB for larger image formats

  if (!file) {
    throw new AppError("No file provided", HTTP_STATUS.BAD_REQUEST);
  }

  if (!allowedMimeTypes.includes(file.mimetype)) {
    throw new AppError(
      "Invalid file type. Allowed: JPEG, PNG, GIF, WebP, BMP, TIFF, SVG, ICO, AVIF, HEIC",
      HTTP_STATUS.BAD_REQUEST,
    );
  }

  if (file.size > maxSize) {
    throw new AppError(
      "File too large. Maximum size is 5MB",
      HTTP_STATUS.BAD_REQUEST,
    );
  }
};

/**
 * Validate price value
 * @param {number} price - Price to validate
 * @param {string} fieldName - Field name for error message
 * @returns {number} Validated price
 * @throws {AppError} If validation fails
 */
const validatePrice = (price, fieldName = "Price") => {
  return validateNumberRange(price, 0, 999999, fieldName);
};

/**
 * Validate stock quantity
 * @param {number} stock - Stock to validate
 * @returns {number} Validated stock
 * @throws {AppError} If validation fails
 */
const validateStock = (stock) => {
  return validateNumberRange(stock, 0, 999999, "Stock quantity");
};

/**
 * Validate color code (hex format)
 * @param {string} colorCode - Color code to validate
 * @returns {boolean} True if valid
 */
const isValidColorCode = (colorCode) => {
  const hexRegex = /^#[0-9A-F]{6}$/i;
  return hexRegex.test(colorCode);
};

module.exports = {
  validateRequiredFields,
  validateEmail,
  isValidEmail,
  isValidUUID,
  validateNumberRange,
  validateStringLength,
  sanitizeString,
  validateSlug,
  generateSlug,
  validatePagination,
  validateImageFile,
  validatePrice,
  validateStock,
  isValidColorCode,
};
