import {
  registerDecorator,
  ValidationOptions,
  ValidationArguments,
} from 'class-validator';

/**
 * MatchPassword - Custom validation decorator for confirming password matching
 *
 * This decorator validates that a field's value matches the value of another
 * specified field, typically used for password confirmation scenarios.
 * It's commonly applied to fields like 'passwordConfirmation' to ensure they
 * match the original 'password' field.
 *
 * Features:
 * - Reusable across different DTOs/classes
 * - Customizable validation error messages
 * - Integrates seamlessly with class-validator
 * - Supports dependency injection context
 *
 * @param property - The name of the field to compare against (e.g., 'password')
 * @param validationOptions - Optional validation configuration (message, groups, etc.)
 *
 * @example
 * // Basic usage in a DTO
 * export class CreateUserDto {
 *   @IsString()
 *   @MinLength(8)
 *   password: string;
 *
 *   @IsString()
 *   @MatchPassword('password')
 *   passwordConfirmation: string;
 * }
 *
 * @example
 * // With custom error message
 * export class ResetPasswordDto {
 *   @IsString()
 *   newPassword: string;
 *
 *   @MatchPassword('newPassword', {
 *     message: 'Password confirmation does not match new password'
 *   })
 *   confirmNewPassword: string;
 * }
 *
 * @see https://github.com/typestack/class-validator#custom-validation-decorators
 */
export function MatchPassword(
  property: string,
  validationOptions?: ValidationOptions,
) {
  /**
   * Returns a decorator factory function that registers the custom validator
   *
   * @param object - The target class prototype (automatically provided by TypeScript)
   * @param propertyName - The name of the property being decorated
   */
  return function (object: Record<string, any>, propertyName: string) {
    // Register the custom decorator with class-validator
    registerDecorator({
      /**
       * Unique name for this validator
       * Used for error messages and validator lookup
       */
      name: 'matchPassword',

      /**
       * The constructor of the target class
       * Required for proper decorator registration
       */
      target: object.constructor,

      /**
       * The property this decorator is applied to
       */
      propertyName: propertyName,

      /**
       * Additional data passed to the validator
       * Contains the name of the property to compare against
       */
      constraints: [property],

      /**
       * Validation configuration options
       * Can include custom message, validation groups, etc.
       */
      options: validationOptions,

      /**
       * The validator implementation
       * Contains the validation logic and error message generation
       */
      validator: {
        /**
         * Validation logic - compares two field values
         *
         * @param value - The value of the decorated field (e.g., passwordConfirmation)
         * @param args - ValidationArguments containing context and constraints
         * @returns boolean indicating if validation passed (true) or failed (false)
         */
        validate(value: any, args: ValidationArguments) {
          // Extract the name of the field to compare against from constraints
          const [relatedPropertyName] = args.constraints;

          // Get the value of the related field from the object
          const relatedValue = (args.object as any)[relatedPropertyName];

          // Perform the comparison
          return value === relatedValue;
        },

        /**
         * Generates the default error message when validation fails
         *
         * @param args - ValidationArguments containing property names
         * @returns Formatted error message string
         */
        defaultMessage(args: ValidationArguments) {
          const [relatedPropertyName] = args.constraints;
          return `${propertyName} must match ${relatedPropertyName}`;
        },
      },
    });
  };
}
