import { ApiPropertyOptional } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import {
  IsArray,
  IsBoolean,
  IsOptional,
  IsString,
  ValidateNested,
} from 'class-validator';
import { PaginationDto } from 'src/config/pagination/paginationDto';
import { DateRangeDto } from 'src/utils/datetime/dateRangeDto';

/**
 * Generic Search Data Transfer Object (DTO) with comprehensive filtering options.
 *
 * This DTO extends PaginationDto to include pagination capabilities while adding
 * a wide range of search and filter parameters. It's designed to be reusable
 * across different search endpoints with common filtering requirements.
 *
 * Features:
 * - Pagination support (inherited from PaginationDto)
 * - Text search on titles/names
 * - Multi-select filters (arrays for created_by, updated_by, active status)
 * - Date range filters (created_on, updated_on)
 * - CSV export flag
 *
 * @extends PaginationDto - Inherits page, limit, sort, order properties
 *
 * @example
 * // Basic search with pagination:
 * {
 *   "search_title": "commission",
 *   "page": 1,
 *   "limit": 20,
 *   "sort": "created_at",
 *   "order": "DESC"
 * }
 *
 * @example
 * // Advanced search with multiple filters:
 * {
 *   "search_title": "difference",
 *   "created_by": ["admin", "system"],
 *   "active": ["1"],
 *   "created_on": {
 *     "start": "2024-01-01",
 *     "end": "2024-12-31"
 *   },
 *   "is_csv": true,
 *   "page": 1,
 *   "limit": 50
 * }
 */
export class SearchDto extends PaginationDto {
  /**
   * Text search on record titles or names.
   * Typically performs partial/contains matching on relevant fields.
   *
   * @type {string}
   * @optional
   * @example "commission report"
   * @example "user profile"
   *
   * @isString - Validation: Must be a string if provided
   *   Error message: "search_title must be a string"
   *
   * @isOptional - Validation: Field is not required
   *
   * @apiPropertyOptional - Swagger documentation for optional field
   *
   * @note Consider adding @MinLength(2) to prevent single-character searches
   */
  @ApiPropertyOptional({
    description: 'Search text for record titles or names',
    example: 'commission report',
    type: String,
  })
  @IsOptional()
  @IsString({ message: 'Search title must be a string if provided' })
  search_title?: string;

  /**
   * Filter by user(s) who created the records.
   * Supports multi-select (array of user identifiers).
   *
   * @type {string[]}
   * @optional
   * @example ["admin", "john.doe"]
   * @example ["system"]
   *
   * @isArray - Validation: Must be an array if provided
   *   Error message: "created_by must be an array"
   *
   * @isString - Validation: Each array element must be a string
   *   Error message: "each value in created_by must be a string"
   *
   * @isOptional - Validation: Field is not required
   *
   * @note Typically expects usernames, user IDs, or user roles
   */
  @ApiPropertyOptional({
    description: 'Filter by creators (usernames, IDs, or roles)',
    example: ['admin', 'john.doe'],
    type: [String],
  })
  @IsOptional()
  @IsArray({ message: 'Created by must be an array if provided' })
  @IsString({ each: true, message: 'Each creator must be a string' })
  created_by?: string[];

  /**
   * Filter by user(s) who last updated the records.
   * Supports multi-select (array of user identifiers).
   *
   * @type {string[]}
   * @optional
   * @example ["admin", "jane.smith"]
   *
   * @isArray - Validation: Must be an array if provided
   *   Error message: "updated_by must be an array"
   *
   * @isString - Validation: Each array element must be a string
   *   Error message: "each value in updated_by must be a string"
   *
   * @isOptional - Validation: Field is not required
   */
  @ApiPropertyOptional({
    description: 'Filter by last updaters (usernames, IDs, or roles)',
    example: ['admin', 'jane.smith'],
    type: [String],
  })
  @IsOptional()
  @IsArray({ message: 'Updated by must be an array if provided' })
  @IsString({ each: true, message: 'Each updater must be a string' })
  updated_by?: string[];

  /**
   * Filter by active status (multi-select).
   * Typically uses string representations of boolean values.
   *
   * @type {string[]}
   * @optional
   * @example ["1"] (active only)
   * @example ["0"] (inactive only)
   * @example ["1", "0"] (both active and inactive)
   *
   * @isArray - Validation: Must be an array if provided
   *   Error message: "active must be an array"
   *
   * @isString - Validation: Each array element must be a string
   *   Error message: "each value in active must be a string"
   *
   * @isOptional - Validation: Field is not required
   *
   * @note Consider using @IsIn(['0', '1'], { each: true }) for validation
   */
  @ApiPropertyOptional({
    description: 'Filter by active status (string representations)',
    example: ['1'],
    type: [String],
    enum: ['0', '1'],
  })
  @IsOptional()
  @IsArray({ message: 'Active status must be an array if provided' })
  @IsString({ each: true, message: 'Each status must be a string' })
  active?: string[];

  /**
   * Flag to indicate CSV export request.
   * When true, the endpoint should return CSV data instead of paginated JSON.
   *
   * @type {boolean}
   * @optional
   * @default false
   * @example true (export as CSV)
   * @example false (return paginated JSON)
   *
   * @isBoolean - Validation: Must be a boolean if provided
   *   Error message: "is_csv must be a boolean"
   *
   * @isOptional - Validation: Field is not required
   *
   * @note When true, pagination parameters may be ignored and all matching
   * records should be returned in CSV format.
   */
  @ApiPropertyOptional({
    description: 'Flag to request CSV export instead of JSON',
    example: false,
    type: Boolean,
    default: false,
  })
  @IsOptional()
  @IsBoolean({ message: 'CSV flag must be a boolean if provided' })
  is_csv?: boolean = false;

  /**
   * Date range filter for record creation dates.
   * Uses the DateRangeDto for standardized date range handling.
   *
   * @type {DateRangeDto}
   * @optional
   * @example { start: "2024-01-01", end: "2024-12-31" }
   *
   * @validateNested - Validation: Validate nested object properties
   *
   * @type - Transformation: Ensure proper class instantiation
   *
   * @isOptional - Validation: Field is not required
   *
   * @note DateRangeDto should handle date validation and formatting
   */
  @ApiPropertyOptional({
    description: 'Date range filter for creation dates',
    type: DateRangeDto,
    example: { start: '2024-01-01', end: '2024-12-31' },
  })
  @IsOptional()
  @ValidateNested({ message: 'Creation date range must be a valid date range' })
  @Type(() => DateRangeDto)
  created_on?: DateRangeDto;

  /**
   * Date range filter for record update dates.
   * Uses the DateRangeDto for standardized date range handling.
   *
   * @type {DateRangeDto}
   * @optional
   * @example { start: "2024-06-01", end: "2024-06-30" }
   *
   * @validateNested - Validation: Validate nested object properties
   *
   * @type - Transformation: Ensure proper class instantiation
   *
   * @isOptional - Validation: Field is not required
   */
  @ApiPropertyOptional({
    description: 'Date range filter for update dates',
    type: DateRangeDto,
    example: { start: '2024-06-01', end: '2024-06-30' },
  })
  @IsOptional()
  @ValidateNested({ message: 'Update date range must be a valid date range' })
  @Type(() => DateRangeDto)
  updated_on?: DateRangeDto;
}
