import {
  IsArray,
  IsBoolean,
  IsIn,
  IsInt,
  IsNumber,
  IsOptional,
  IsString,
  ArrayUnique,
  IsDateString,
} from 'class-validator'
import { Type } from 'class-transformer'
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'

export class ReportFilterDto {
  @ApiPropertyOptional()
  @IsOptional()
  @IsInt()
  @Type(() => Number)
  programId?: number

  @ApiPropertyOptional()
  @IsOptional()
  @IsInt()
  @Type(() => Number)
  programSessionId?: number

  @ApiPropertyOptional({ type: [String] })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  registrationStatus?: string[]

  @ApiPropertyOptional({ type: [String] })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  approvalStatus?: string[]

  @ApiPropertyOptional({ type: [String] })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  gender?: string[]

  @ApiPropertyOptional({ type: [String], description: "'self' | 'other'" })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  registrationMode?: string[]

  @ApiPropertyOptional({ description: "'yes' | 'no'" })
  @IsOptional()
  @IsString()
  organisation?: string

  @ApiPropertyOptional({ description: "'defaulter' | 'non_defaulter'" })
  @IsOptional()
  @IsString()
  defaulterStatus?: string

  @ApiPropertyOptional({ type: [String], description: "'payment_completed' | 'payment_pending' | 'no_payment'" })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  paymentStatus?: string[]

  @ApiPropertyOptional({ type: [String] })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  paymentMode?: string[]

  @ApiPropertyOptional({ type: [String], description: "'invoice_completed' | 'invoice_pending'" })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  invoiceStatus?: string[]

  @ApiPropertyOptional({ type: [String], description: "'travel_completed' | 'travel_pending'" })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  travelStatus?: string[]

  @ApiPropertyOptional({ type: [String] })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  travelPlan?: string[]

  @ApiPropertyOptional({ type: [String], description: "'0-20' | '21-30' | '31-50' | '51-65' | '>65'" })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  age?: string[]

  @ApiPropertyOptional({ type: [String], description: "'0-5' | '>10' | '=5'" })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  numberOfHdbs?: string[]

  @ApiPropertyOptional({ type: [String] })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  experienceTags?: string[]

  @ApiPropertyOptional({ type: [String] })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  location?: string[]

  // Client sends this as a multi-select array (e.g. ["no"]); scalar is also accepted.
  // The service normalizes it to the scalar the report SQL function expects.
  @ApiPropertyOptional({ description: "'yes' | 'no' (accepts string or string[])" })
  @IsOptional()
  freeSeat?: string | string[]

  @ApiPropertyOptional({ type: [String], description: "'seat_released' | 'denied'" })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  waitlistStatus?: string[]

  @ApiPropertyOptional({ type: [String], description: "'room_allocation_completed' | 'room_allocation_pending'" })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  roomAllocationStatus?: string[]

  @ApiPropertyOptional({ enum: ['before', 'after'] })
  @IsOptional()
  @IsIn(['before', 'after'])
  waitlistCategory?: 'before' | 'after'

  @ApiPropertyOptional()
  @IsOptional()
  @IsBoolean()
  seatReleased?: boolean

  @ApiPropertyOptional()
  @IsOptional()
  @IsInt()
  @Type(() => Number)
  allocatedProgramId?: number

  @ApiPropertyOptional()
  @IsOptional()
  @IsInt()
  @Type(() => Number)
  allocatedSessionId?: number

  @ApiPropertyOptional()
  @IsOptional()
  @IsInt()
  @Type(() => Number)
  preferredProgramId?: number

  @ApiPropertyOptional()
  @IsOptional()
  @IsInt()
  @Type(() => Number)
  preferredSessionId?: number

  @ApiPropertyOptional({ type: [String] })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  swapRequests?: string[]

  @ApiPropertyOptional()
  @IsOptional()
  @IsString()
  kpiCategory?: string

  @ApiPropertyOptional()
  @IsOptional()
  @IsString()
  kpiFilter?: string

  @ApiPropertyOptional()
  @IsOptional()
  @IsDateString()
  createdFrom?: string

  @ApiPropertyOptional()
  @IsOptional()
  @IsDateString()
  createdTo?: string

  @ApiPropertyOptional({ type: [String], description: "'goodies_completed' | 'goodies_pending'" })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  goodiesStatus?: string[]

  @ApiPropertyOptional({ type: [String], description: 'recommendation keys or "none"' })
  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  recommendation?: string[]

  @ApiPropertyOptional({ type: [Number], description: 'Array of RM user IDs' })
  @IsOptional()
  @IsArray()
  @IsInt({ each: true })
  @Type(() => Number)
  rmContact?: number[]

  @ApiPropertyOptional({ description: 'Minimum avg RM rating threshold (e.g. 4.5)' })
  @IsOptional()
  @IsNumber()
  @Type(() => Number)
  rmRating?: number

  @ApiPropertyOptional({ type: [Number], description: 'Array of preferred program IDs (priority 1 preference)' })
  @IsOptional()
  @IsArray()
  @IsInt({ each: true })
  @Type(() => Number)
  preferredPrograms?: number[]

  @ApiPropertyOptional({ description: 'Filter by swap first-requested program ID' })
  @IsOptional()
  @IsInt()
  @Type(() => Number)
  swapPreferredProgramId?: number

  @ApiPropertyOptional({ description: 'Filter by latest ON_HOLD swap demand first-requested program ID' })
  @IsOptional()
  @IsInt()
  @Type(() => Number)
  swapDemandPreferredProgramId?: number

  @ApiPropertyOptional({ description: 'Filter REJECTED registrations with this program preference OR ON_HOLD with swap demand for this program' })
  @IsOptional()
  @IsInt()
  @Type(() => Number)
  pendingProgramId?: number
}

export class GenerateReportDto {
  @ApiProperty({ type: [String], description: 'List of field keys to include in the report' })
  @IsArray()
  @ArrayUnique()
  @IsString({ each: true })
  fields: string[]

  @ApiPropertyOptional({ type: ReportFilterDto, description: 'Optional filters to narrow down report results' })
  @IsOptional()
  filters?: ReportFilterDto

  @ApiPropertyOptional({ enum: ['json', 'excel'] })
  @IsOptional()
  @IsIn(['json', 'excel'])
  format?: 'json' | 'excel'

  @ApiPropertyOptional({ description: 'Custom file name for excel download (without extension)' })
  @IsOptional()
  @IsString()
  fileName?: string
}