import {
  ArrayMinSize,
  IsArray,
  IsBooleanString,
  IsInt,
  IsNotEmpty,
  IsOptional,
  IsString,
  Matches,
  MaxLength,
  MinLength,
} from 'class-validator';

import { Transform, Type } from 'class-transformer';

/**
 * Multipart form body for POST /documents (Admin upload).
 *
 * NOTE: because this arrives as multipart/form-data, arrays and booleans
 * come in as strings — the class-transformer decorators cast them.
 */
export class UploadDocumentDto {
  @IsString()
  @IsNotEmpty()
  @MaxLength(200)
  title: string;

  @IsString()
  @IsNotEmpty()
  @MaxLength(100)
  category: string;

  @IsOptional()
  @IsString()
  @MaxLength(2000)
  description?: string;

  // ─── Role assignment ─────────────────────────────────────────────────
  //
  // Frontend sends:
  // role_ids = "[1,4]"
  //
  // Transform converts it back to:
  // role_ids = [1, 4]
  //
  // This is required because multipart/form-data sends the value as a
  // string when JSON.stringify() is used on the frontend.

  // ─── Role assignment ─────────────────────────────────────────────────

  @Transform(({ value }) => {
    if (Array.isArray(value)) {
      return value.map((id) => Number(id));
    }

    if (typeof value === 'string') {
      try {
        const parsed = JSON.parse(value);

        if (Array.isArray(parsed)) {
          return parsed.map((id) => Number(id));
        }

        return [];
      } catch {
        return [];
      }
    }

    return [];
  })
  @IsArray()
  @ArrayMinSize(1, {
    message: 'Assign the document to at least one role',
  })
  @IsInt({ each: true })
  role_ids: number[];

  // ─── Notification opt-outs ───────────────────────────────────────────
  //
  // Frontend sends:
  // notify_user_ids = "[10,12,15]"
  //
  // Transform converts it back to:
  // notify_user_ids = [10, 12, 15]

  // ─── Notification opt-outs ───────────────────────────────────────────

  @Transform(({ value }) => {
    if (Array.isArray(value)) {
      return value.map((id) => Number(id));
    }

    if (typeof value === 'string') {
      try {
        const parsed = JSON.parse(value);

        if (Array.isArray(parsed)) {
          return parsed.map((id) => Number(id));
        }

        return [];
      } catch {
        return [];
      }
    }

    return [];
  })
  @IsOptional()
  @IsArray()
  @IsInt({ each: true })
  notify_user_ids?: number[];

  // ─── Security switches ───────────────────────────────────────────────
  //
  // Multipart booleans arrive as 'true' / 'false' strings.

  @IsOptional()
  @IsBooleanString()
  require_otp?: string;

  @IsOptional()
  @IsBooleanString()
  allow_download?: string;

  // ─── Password ────────────────────────────────────────────────────────
  //
  // Plain-text password from the form — service bcrypts it before saving.
  // Empty string = no password.

  @IsOptional()
  @IsString()
  @MinLength(4, {
    message: 'Password must be at least 4 characters',
  })
  @MaxLength(120)
  password?: string;

  // ─── Optional expiry ─────────────────────────────────────────────────

  @IsOptional()
  @IsString()
  @Matches(/^\d{4}-\d{2}-\d{2}$/, {
    message: 'expiry_date must be YYYY-MM-DD',
  })
  expiry_date?: string;
}