Source: utils/validationUtil.js

/**
 * @fileoverview Validation Utility for Satoshi Showdown.
 * Provides a comprehensive suite of validation functions for various data types and formats
 * within the application, leveraging the Joi library. This ensures data integrity and
 * conformity to application standards, particularly for user and event data.
 *
 * @module utils/validationUtil
 * @requires joi - Joi library for data validation.
 */

const Joi = require("joi");

// Common Validators
const validateEmail = Joi.string().email().label("Email");
const validateString = Joi.string().trim().min(1).label("String");
const validateNumber = Joi.number().label("Number");
const validateDate = Joi.date().iso().label("Date");

// Domain-Specific Validators
const validateCryptoAddress = Joi.string().label("Crypto Address");
const validatePassword = Joi.string().min(8).label("Password");
const validateObjectId = Joi.string()
  .regex(/^[0-9a-fA-F]{24}$/)
  .label("ObjectID");

/**
 * Validates user data against the defined schema.
 * The password is validated as a plain text string before hashing, ensuring it meets the defined criteria
 * (like minimum length). After validation, the password should be hashed before storing it in the database.
 *
 * @function validateUser
 * @param {Object} data - The user data to validate.
 * @return {Joi.ValidationResult} The result of the validation.
 */
const validateUser = (data) =>
  Joi.object({
    username: validateString.required(),
    email: validateEmail.optional(),
    password: validatePassword.required(), // Validate plain text password
    lastActive: validateDate.optional(),
    role: Joi.string()
      .valid("User", "Organizer", "Oracle", "Staff", "Admin", "SuperAdmin")
      .default("User"),
    profileInfo: Joi.object().optional(),
    ipAddress: validateString.optional(),
    organization: validateObjectId.optional(),
  }).validate(data, { abortEarly: false });

/**
 * Validates event data against the defined schema.
 * Ensures that the provided event data conforms to the structure and rules set in the Event model.
 * Includes validation for new fields like maxParticipants, minParticipants, isOpen, and closedAt.
 * This validation is crucial for maintaining data integrity and consistency in the application.
 *
 * @function validateEvent
 * @param {Object} data - The event data to validate.
 * @return {Joi.ValidationResult} The result of the validation.
 */
const validateEvent = (data) =>
  Joi.object({
    eventId: validateString.optional(),
    name: validateString.required(),
    description: validateString.optional(),
    type: validateString.optional(),
    startTime: validateDate.optional(),
    endTime: validateDate.optional(),
    status: Joi.string()
      .valid("planning", "ready", "active", "completed", "cancelled")
      .default("planning"),
    entryFee: validateNumber.min(0).required(),
    prizePool: validateNumber.min(0).required(),
    creator: validateObjectId.required(),
    participants: Joi.array()
      .items(
        Joi.object({
          userId: validateObjectId,
          joinedAt: validateDate,
        }),
      )
      .optional(),
    maxParticipants: validateNumber.required(),
    minParticipants: validateNumber.required(),
    isOpen: Joi.boolean().optional(),
    closedAt: validateDate.optional(),
    transactions: Joi.array().items(validateObjectId).optional(),
    winners: Joi.array().items(validateObjectId).optional(),
    config: Joi.object().optional(),
    streamingUrl: validateString.optional(),
    streamingSchedule: Joi.object({
      start: validateDate.optional(),
      end: validateDate.optional(),
    }).optional(),
    bettingOptions: Joi.array()
      .items(
        Joi.object({
          type: validateString.required(),
          description: validateString.optional(),
          odds: validateNumber.optional(),
        }),
      )
      .optional(),
    viewCount: validateNumber.optional(),
    feedback: Joi.array().items(validateObjectId).optional(),
    socialSharingLinks: Joi.array().items(validateString).optional(),
    ageRestriction: validateNumber.optional(),
    geographicRestrictions: Joi.array().items(validateString).optional(),
  }).validate(data, { abortEarly: false });

module.exports = {
  validateEmail,
  validateString,
  validateNumber,
  validateDate,
  validateCryptoAddress,
  validatePassword,
  validateObjectId,
  validateUser,
  validateEvent,
};