import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsString, IsNotEmpty, IsOptional } from 'class-validator';
import { IsNumberOrStringDto } from 'src/utils/common/numberOrStringDto';

/**
 * Generic Update Data Transfer Object (DTO)
 *
 * This DTO is used for updating existing records in the system.
 * It extends the CreateDto pattern by adding an ID field to identify
 * which record to update, and typically includes fields for tracking
 * who made the modification.
 *
 * Commonly used for updating master data entries like:
 * - Reason codes
 * - Categories
 * - Configuration settings
 * - Reference data
 *
 * The DTO supports flexible input types for numeric fields that might
 * come as strings from frontend forms or API clients.
 *
 * @example
 * // Updating a difference reason:
 * {
 *   "id": 123,
 *   "reason": "Updated: Price discrepancy calculation",
 *   "active": 1,
 *   "modified_by_user": 456
 * }
 *
 * @example
 * // Updating with string numeric values:
 * {
 *   "id": "123",
 *   "reason": "Client adjustment process",
 *   "active": "0",
 *   "modified_by_user": "789"
 * }
 *
 * @example
 * // Partial update without specifying modifier:
 * {
 *   "id": 456,
 *   "reason": "Updated procedure description",
 *   "active": 1
 * }
 */
export class UpdateDto {
  /**
   * Identifier of the record to update.
   * Can be provided as either a number or numeric string.
   *
   * @type {number | string}
   * @required
   * @example 123 (number)
   * @example "456" (string)
   *
   * @isNotEmpty - Validation: Cannot be null, undefined, or empty
   *   Error message: "id should not be empty"
   *
   * @isNumberOrStringDto - Custom validation: Must be number or string
   *   First parameter (1): Default value if invalid (likely not used for ID)
   *   Second parameter ('Id'): Field name for error messages
   *   Validates and converts string numbers to actual numbers
   *
   * @note For IDs, the default value parameter (1) might not be appropriate.
   * Consider a custom validator that doesn't set defaults for IDs.
   */
  @ApiProperty({
    description: 'ID of the record to update',
    example: 123,
    oneOf: [
      { type: 'number', example: 123 },
      { type: 'string', example: '456' },
    ],
  })
  @IsNotEmpty({ message: 'Record ID is required' })
  @IsNumberOrStringDto(1, 'Id')
  id: number | string;

  /**
   * Updated descriptive reason or explanation for the record.
   *
   * @type {string}
   * @required
   * @example "Updated: Price discrepancy in commission calculation"
   * @example "Revised client adjustment process"
   *
   * @isNotEmpty - Validation: Cannot be empty string
   *   Error message: "reason should not be empty"
   *
   * @isString - Validation: Must be a string
   *   Error message: "reason must be a string"
   *
   * @apiProperty - Swagger documentation with example
   *
   * @note Consider adding length validation: @MinLength(3), @MaxLength(500)
   */
  @ApiProperty({
    description: 'Updated descriptive reason or explanation',
    example: 'Difference Reason is required',
    type: String,
    minLength: 3,
    maxLength: 500,
  })
  @IsNotEmpty({ message: 'Reason is required' })
  @IsString({ message: 'Reason must be a string' })
  reason: string;

  /**
   * Updated activation status of the record.
   * Typically 1 for active, 0 for inactive. Supports both number and string input.
   *
   * @type {number | string}
   * @required
   * @example 1 (active)
   * @example 0 (inactive)
   * @example "1" (string representation)
   *
   * @isNotEmpty - Validation: Cannot be null, undefined, or empty
   *   Error message: "active should not be empty"
   *
   * @isNumberOrStringDto - Custom validation: Must be number or string
   *   First parameter (1): Default value if invalid
   *   Second parameter ('Status'): Field name for error messages
   *   Validates and converts string numbers to actual numbers
   */
  @ApiProperty({
    description: 'Updated activation status (1 = active, 0 = inactive)',
    example: 1,
    oneOf: [
      { type: 'number', example: 1 },
      { type: 'string', example: '1' },
    ],
    default: 1,
  })
  @IsNotEmpty({ message: 'Status is required' })
  @IsNumberOrStringDto(1, 'Status')
  active: number | string;

  /**
   * Optional user ID of the person modifying the record.
   * Used for audit trails to track who updated the record.
   *
   * @type {number | string}
   * @optional
   * @example 456
   * @example "789"
   *
   * @isOptional - Validation: Field is not required
   *
   * @isNumberOrStringDto - Custom validation: Must be number or string if provided
   *   First parameter (0): Default value if invalid
   *   Second parameter ('User ID'): Field name for error messages
   *
   * @apiPropertyOptional - Swagger documentation for optional field
   *
   * @note In practice, this is often populated from the authenticated user's session
   * rather than client input, for security and accuracy.
   */
  @ApiPropertyOptional({
    description: 'ID of the user modifying the record (for audit trail)',
    example: 1,
    oneOf: [
      { type: 'number', example: 456 },
      { type: 'string', example: '789' },
    ],
  })
  @IsOptional()
  @IsNumberOrStringDto(0, 'User ID')
  modified_by_user?: number | string;
}
