import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Transform, Type } from 'class-transformer';
import { IsArray, IsIn, IsInt, IsOptional, Min } from 'class-validator';
import {
  USER_TYPE_FILTER_VALUES,
  UserTypeFilterValue,
} from 'src/common/utils/user-type-filter.util';
import { ProvisionRegistrationStatus } from '../interfaces/online-session.interface';

/**
 * The `userType` checkbox set, shared by both provisioning queries below — the
 * registrant's own account type (Org/Seeker). Multiple selections are OR'd (a
 * plain IN, see `resolveUserTypeFilter`); a single selection may be sent unwrapped.
 *
 * Unlike the other filters here it narrows the ELIGIBLE SET itself, so every
 * count in the response (totalEligible, generated, failed, yetToGenerate) is
 * computed over the filtered set — the tiles and the drilldown rows can never
 * disagree about which registrants are in scope.
 */
const USER_TYPE_API_PROPERTY = {
  enum: USER_TYPE_FILTER_VALUES,
  isArray: true,
  description:
    'Checkbox set over the registrant\'s own account type — "Org" and/or "Seeker", OR\'d together. "Seeker" also includes registrations made on someone else\'s behalf, which have no user account of their own. Narrows the eligible set, so all counts reflect it.',
} as const;

/**
 * Query params for the program-level provisioning overview: every online session
 * of `programId` (optionally narrowed to one `sessionId`) with live counts —
 * total eligible, generated, failed, and yet-to-generate.
 */
export class ProvisionStatusQueryDto {
  @ApiProperty({ description: 'Program whose online sessions to summarise.', minimum: 1 })
  @Type(() => Number)
  @IsInt()
  @Min(1)
  programId: number;

  @ApiPropertyOptional({ description: 'Narrow to a single program session.', minimum: 1 })
  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  sessionId?: number;

  @ApiPropertyOptional(USER_TYPE_API_PROPERTY)
  @IsOptional()
  @Transform(({ value }) => (value == null || Array.isArray(value) ? value : [value]))
  @IsArray()
  @IsIn(USER_TYPE_FILTER_VALUES, { each: true })
  userType?: UserTypeFilterValue[];
}

/**
 * Query params for the per-session provisioning drilldown: the eligible
 * registrations bucketed into generated / failed / yet-to-generate, optionally
 * filtered to one bucket, paginated.
 */
export class ProvisionRegistrationsQueryDto {
  @ApiPropertyOptional({
    description:
      "Filter to one bucket: 'generated' | 'failed' | 'pending' (yet-to-generate) | 'generalLink' (pre-generated staff/placeholder links, no ProgramRegistration of their own).",
    enum: ['generated', 'failed', 'pending', 'generalLink'],
  })
  @IsOptional()
  @IsIn(['generated', 'failed', 'pending', 'generalLink'])
  status?: ProvisionRegistrationStatus;

  @ApiPropertyOptional({ description: 'Page (1-based). Default 1.', minimum: 1, default: 1 })
  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  page = 1;

  @ApiPropertyOptional({ description: 'Rows per page. Default 20.', minimum: 1, default: 20 })
  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  limit = 20;

  @ApiPropertyOptional(USER_TYPE_API_PROPERTY)
  @IsOptional()
  @Transform(({ value }) => (value == null || Array.isArray(value) ? value : [value]))
  @IsArray()
  @IsIn(USER_TYPE_FILTER_VALUES, { each: true })
  userType?: UserTypeFilterValue[];
}
