import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Transform, Type } from 'class-transformer';
import {
  IsArray,
  IsInt,
  IsOptional,
  IsString,
  MaxLength,
  Min,
  MinLength,
} from 'class-validator';

// In multipart/form-data a list of ids arrives as a JSON string ("[3,7]") or
// as a single value, and every item is text. This turns any of those shapes
// into a real number array. The numbers are converted here rather than with
// @Type, because @Type only converts the value itself, not the items inside.
function parseAgencyIds(value: unknown): unknown {
  if (value === undefined || value === null) return value;

  let items: unknown[];

  if (Array.isArray(value)) {
    items = value;
  } else if (typeof value === 'string') {
    try {
      const parsed: unknown = JSON.parse(value);
      items = Array.isArray(parsed) ? parsed : [parsed];
    } catch {
      items = [value];
    }
  } else {
    items = [value];
  }

  return items.map((item) => Number(item));
}

// What a Ministry sends when it adds an issue to a meeting request.
// The issue status and the primary agency are NOT accepted from the client:
// the status is always "New Submission" and the primary agency is always the
// Ministry the request was addressed to.
export class AddMeetingRequestIssueDto {
  @ApiProperty({ example: 'Slow customs clearance at the border' })
  @IsString()
  @MinLength(1)
  @MaxLength(100)
  title!: string;

  @ApiProperty({ example: 'Trucks wait up to three days at the checkpoint.' })
  @IsString()
  @MinLength(1)
  description!: string;

  @ApiProperty({ example: 'Add a second inspection lane during peak hours.' })
  @IsString()
  @MinLength(1)
  recommendation!: string;

  @ApiPropertyOptional({
    example: 4,
    description: 'Optional. If empty, the backend uses the default category.',
  })
  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  categoryId?: number;

  @ApiPropertyOptional({
    example: 14,
    description:
      'Private-sector working group that owns the issue. If empty, the working group that raised the meeting request is used.',
  })
  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  workingGroupId?: number;

  @ApiPropertyOptional({
    type: [Number],
    example: [3, 7],
    description:
      'Optional second to fifth responsible agencies, in the order shown.',
  })
  @IsOptional()
  @Transform(({ value }) => parseAgencyIds(value))
  @IsArray()
  @IsInt({ each: true })
  @Min(1, { each: true })
  additionalAgencyIds?: number[];

  @ApiPropertyOptional({
    type: 'string',
    format: 'binary',
    description: 'Optional issue attachment file.',
  })
  @IsOptional()
  attachmentFile?: unknown;
}
