import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { JoiSchema, JoiSchemaOptions } from 'nestjs-joi';
import * as Joi from 'joi';

/**
 * Login modes enumeration
 *
 * Defines the different methods a user can use to identify themselves during login.
 * This allows flexible authentication supporting multiple identifier types.
 *
 * @enum
 * @example LOGIN_MODES.EMAIL // Login using email address
 * @example LOGIN_MODES.PHONE // Login using phone number
 * @example LOGIN_MODES.UID   // Login using unique system identifier
 */
export enum LOGIN_MODES {
  /** Login using a unique system-generated identifier */
  UID = 'uid',

  /** Login using a phone number (typically with country code) */
  PHONE = 'phone',

  /** Login using an email address (most common method) */
  EMAIL = 'email',
}

/**
 * LoginUserDto - Flexible user authentication Data Transfer Object
 *
 * This DTO supports multiple login methods using Joi schema validation alongside
 * class-validator. It allows users to authenticate using different identifiers
 * (email, phone, or unique ID) based on the selected login_mode.
 *
 * Features:
 * - Multiple login identifier options (email, phone, unique_id)
 * - Conditional validation based on login_mode
 * - Joi schema validation with automatic sanitization
 * - OpenAPI/Swagger documentation
 *
 * @example
 * // Login with email
 * {
 *   "email": "user@example.com",
 *   "password": "SecurePass123!",
 *   "login_mode": "email"
 * }
 *
 * @example
 * // Login with phone number
 * {
 *   "phone": "+1234567890",
 *   "password": "SecurePass123!",
 *   "login_mode": "phone"
 * }
 *
 * @example
 * // Login with unique ID
 * {
 *   "unique_id": "user_12345abc",
 *   "password": "SecurePass123!",
 *   "login_mode": "uid"
 * }
 *
 * @note The appropriate identifier field must match the selected login_mode
 */
@JoiSchemaOptions({
  /**
   * Strip unknown fields from the request
   * Removes any fields not defined in the schema
   */
  stripUnknown: true,

  /**
   * Abort validation on first error
   * Returns immediately when any validation fails
   */
  abortEarly: true,
})
export class LoginUserDto {
  /**
   * Email address for authentication
   *
   * Required only when login_mode is 'email'
   * Should be validated for format and existence in the system
   *
   * @optional Conditional based on login_mode
   * @example "user@example.com"
   */
  @ApiPropertyOptional({
    description: 'Email address for email-based login',
    example: 'user@example.com',
  })
  email?: string;

  /**
   * Unique system identifier for authentication
   *
   * Required only when login_mode is 'uid'
   * Typically a system-generated ID like UUID or custom identifier
   *
   * @optional Conditional based on login_mode
   * @example "550e8400-e29b-41d4-a716-446655440000"
   * @example "user_12345abc"
   */
  @ApiPropertyOptional({
    description: 'Unique system identifier for UID-based login',
    example: '550e8400-e29b-41d4-a716-446655440000',
  })
  unique_id?: string;

  /**
   * Phone number for authentication
   *
   * Required only when login_mode is 'phone'
   * Should include country code and follow E.164 format
   *
   * @optional Conditional based on login_mode
   * @example "+1234567890"
   * @example "+441234567890"
   */
  @ApiPropertyOptional({
    description: 'Phone number for phone-based login (E.164 format)',
    example: '+1234567890',
  })
  phone?: string;

  /**
   * User password for authentication
   *
   * Required for all login modes
   * Should be compared against securely hashed password in database
   *
   * @required Always required
   * @example "SecurePass123!"
   */
  @ApiProperty({
    description: 'User password for authentication',
    example: 'SecurePass123!',
    required: true,
  })
  password: string;

  /**
   * Login mode/authentication method
   *
   * Determines which identifier field (email, phone, or unique_id) to use
   * for user lookup and validation.
   *
   * @required Always required
   * @example LOGIN_MODES.EMAIL
   */
  @ApiProperty({
    description: 'Login method/authentication mode',
    enum: LOGIN_MODES,
    example: LOGIN_MODES.EMAIL,
    required: true,
  })
  @JoiSchema(
    Joi.string()
      .valid(...Object.values(LOGIN_MODES))
      .required()
      .messages({
        'any.only': 'login_mode must be one of: uid, phone, email',
        'any.required': 'login_mode is required',
      }),
  )
  login_mode: LOGIN_MODES;
}
