Source: validators/user.validator.js

import Joi from "joi";
import { EMAIL_REGEX, STRONG_PASSWORD_REGEX } from "../utils/validators.js";
import mongoose from "mongoose";

/**
 * Joi schema for a single item in the user's cart.
 *
 * - productId: required, ObjectId string
 * - quantity: required, number, min 1
 */
export const cartItemSchema = Joi.object({
  productId: Joi.string()
    .custom((value, helpers) => {
      if (!mongoose.Types.ObjectId.isValid(value)) {
        return helpers.error("any.invalid");
      }
      return value; // must return the value if valid
    })
    .required()
    .messages({ "any.required": "Invalid MongoDB ObjectId in productId" }),
  quantity: Joi.number().min(1).required(), // validate quantity (min 1)
});

/**
 * Joi validation schema for User creation/update.
 *
 * Fields:
 * - displayName: optional, trimmed, min 3, max 30
 * - email: required, lowercase, trimmed, matches email regex
 * - googleId: optional string
 * - password: required if googleId is missing, min 6, max 128
 * - role: 'user' | 'admin'
 * - cartItems: array of validated cartItemSchema
 * - previousOrders: array of ObjectId strings
 */

export const userValidator = Joi.object({
  displayName: Joi.string().min(3).max(30).trim().optional(), // validate username (3-30 chars)
  email: Joi.string().trim().lowercase().pattern(EMAIL_REGEX).required(), // validate email format
  googleId: Joi.string().trim().optional(), // optional Google ID
  password: Joi.string()
    .pattern(STRONG_PASSWORD_REGEX)
    .min(8)
    .max(128)
    .when("googleId", {
      is: Joi.exist(),
      then: Joi.optional(),
      otherwise: Joi.required(),
    }), // validate password if googleId is not present
  role: Joi.string().valid("user", "admin").default("user"), // validate role (default to 'user')
  cartItems: Joi.array().items(cartItemSchema).optional(), // validate cart items
  previousOrders: Joi.array().items(
    Joi.string()
      .optional()
      .custom((value, helpers) => {
        if (!mongoose.Types.ObjectId.isValid(value)) {
          return helpers.error("any.invalid");
        }
        return value; // must return the value if valid
      }, "ObjectId Validation")
      .messages({
        "any.invalid": "Invalid MongoDB ObjectId in previousOrders",
      })
  ),
});