import { ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; import { IsArray, IsOptional, IsUUID, ValidateNested } from 'class-validator'; export class ConsistWagonSwitchDto { @ApiPropertyOptional({ format: 'uuid', description: 'Coupled wagon being taken out of the consist.' }) @IsUUID() fromWagonId!: string; @ApiPropertyOptional({ format: 'uuid', description: 'AVAILABLE same-type wagon from the current yard that takes its place (and its slot, cargo included).' }) @IsUUID() toWagonId!: string; } export class AdjustScheduleConsistDto { @ApiPropertyOptional({ type: [String], format: 'uuid', description: "AVAILABLE wagons from the train's current yard to couple onto the built train (blocked when they push gross weight or length past the locomotive limits incl. tolerance).", }) @IsOptional() @IsArray() @IsUUID('all', { each: true }) addWagonIds?: string[]; @ApiPropertyOptional({ type: [String], format: 'uuid', description: 'Free (unloaded) wagons to detach permanently from the built train — e.g. trimming tare when gross weight exceeds the pull limit.', }) @IsOptional() @IsArray() @IsUUID('all', { each: true }) removeWagonIds?: string[]; @ApiPropertyOptional({ type: [ConsistWagonSwitchDto], description: "Wagon swaps: the replacement takes over the outgoing wagon's position AND its slot, so cargo allocations ride the new wagon. This is how a LOADED wagon leaves the train — removal is blocked for it, switching is not. Replacement must be the same wagon type, AVAILABLE, standing in the train's current yard.", }) @IsOptional() @IsArray() @ValidateNested({ each: true }) @Type(() => ConsistWagonSwitchDto) switches?: ConsistWagonSwitchDto[]; }