import { Type } from 'class-transformer';
import {
  IsEnum,
  IsInt,
  IsISO8601,
  IsOptional,
  IsString,
  Max,
  MaxLength,
  Min,
} from 'class-validator';

/**
 * Query parameters for `GET /api/admin/users`. Mirrors the
 * audit-viewer DTO's pagination posture per ADR-0020 §"User list" —
 * offset/limit with hard caps, every filter optional. Bound from
 * the URL via Nest's `@Query()` + global ValidationPipe so unknown
 * keys are rejected by `forbidNonWhitelisted` before reaching the
 * handler.
 *
 * Filters target the `public.users` directory (PR #140). The
 * `username` filter is exact-prefix match (Prisma `startsWith`)
 * because audit users typically search by exact known prefix —
 * `jane.doe`, `admin`, etc. `displayName` filter uses
 * case-insensitive contains since display names have natural
 * variation in casing.
 */
export const MAX_LIMIT = 200;
export const DEFAULT_LIMIT = 50;

const ADMIN_USERS_AUDIENCES = ['workforce', 'customer'] as const;
type AudienceFilter = (typeof ADMIN_USERS_AUDIENCES)[number];

export class AdminUsersQueryDto {
  /** Exact-prefix match on `username`. */
  @IsOptional()
  @IsString()
  @MaxLength(128)
  username?: string;

  /** Case-insensitive `contains` match on `display_name`. */
  @IsOptional()
  @IsString()
  @MaxLength(128)
  displayName?: string;

  @IsOptional()
  @IsEnum(ADMIN_USERS_AUDIENCES)
  audience?: AudienceFilter;

  /** ISO-8601 lower bound on `last_seen_at` (inclusive). */
  @IsOptional()
  @IsISO8601()
  lastSeenAtFrom?: string;

  /** ISO-8601 upper bound on `last_seen_at` (exclusive). */
  @IsOptional()
  @IsISO8601()
  lastSeenAtTo?: string;

  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  @Max(MAX_LIMIT)
  limit?: number;

  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(0)
  offset?: number;
}
