import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Transform, Type } from 'class-transformer';
import {
  ArrayMinSize,
  IsArray,
  IsBoolean,
  IsDateString,
  IsIn,
  IsInt,
  IsNumber,
  IsOptional,
  IsString,
  IsUUID,
  Min,
  Validate,
  ValidateIf,
  ValidateNested,
} from 'class-validator';
import { BOOKING_STATUSES, FREIGHT_TYPES } from '../entities/booking.entity';
import { BookingFreightShapeConstraint } from './validators/booking-freight.validator';

const CONTRACT_TYPES = ['NEW', 'RENEWAL'] as const;
const EQUIPMENT_RETURNS = ['WITH_RETURN', 'WITHOUT_RETURN', 'NA'] as const;
const TRADE_DIRECTIONS = ['IMPORT', 'EXPORT', 'DOMESTIC'] as const;
const PAYMENT_CURRENCIES = ['ETB', 'USD'] as const;

export {
  BOOKING_STATUSES,
  CONTRACT_TYPES,
  EQUIPMENT_RETURNS,
  FREIGHT_TYPES,
  TRADE_DIRECTIONS,
  PAYMENT_CURRENCIES,
};

export class CreateBookingContainerDto {
  @ApiProperty({ format: 'uuid', description: 'FK to container_types.id' })
  @IsUUID()
  containerTypeId!: string;

  @ApiProperty({ description: 'Quantity of containers', minimum: 1 })
  @IsInt()
  @Min(1)
  @Transform(({ value }) => Number(value))
  quantity!: number;

  @ApiProperty({ description: 'VGM per container in tons', minimum: 0 })
  @IsNumber()
  @Min(0)
  @Transform(({ value }) => Number(value))
  vgmPerUnitTons!: number;
}

export class CreateBookingDto {
  /** Class-level freight shape check (not a request field). */
  @Validate(BookingFreightShapeConstraint)
  freightShapeValidation?: boolean;
  @ApiPropertyOptional({ description: 'Unique booking reference (auto-generated if omitted)' })
  @IsOptional()
  @IsString()
  @Transform(({ value }) => (typeof value === 'string' ? value.trim() : value))
  reference?: string;

  // @ApiPropertyOptional({ format: 'uuid', description: 'Admin only: target customer (legacy)' })
  // @IsOptional()
  // @IsUUID()
  // customerId?: string;

  @ApiPropertyOptional({ format: 'uuid', description: 'Admin only: target company' })
  @IsOptional()
  @IsUUID()
  companyId?: string;

  @ApiPropertyOptional({ format: 'uuid' })
  @IsOptional()
  @IsUUID()
  trainId?: string;

  @ApiProperty({ example: '2026-06-15T00:00:00.000Z' })
  @IsDateString()
  scheduledDate!: string;

  @ApiProperty({ enum: CONTRACT_TYPES })
  @IsIn([...CONTRACT_TYPES])
  contractType!: string;

  @ApiPropertyOptional({ format: 'uuid' })
  @IsOptional()
  @IsUUID()
  @Transform(({ value }) => (value === '' || value == null ? undefined : value))
  previousContractId?: string;

  @ApiProperty({ format: 'uuid', description: 'FK to service_types.id' })
  @IsUUID()
  serviceTypeId!: string;

  @ApiPropertyOptional()
  @IsOptional()
  @IsString()
  firstMilePickupAddress?: string;

  @ApiPropertyOptional()
  @IsOptional()
  @IsString()
  lastMileDeliveryAddress?: string;

  @ApiProperty({ enum: EQUIPMENT_RETURNS })
  @IsIn([...EQUIPMENT_RETURNS])
  equipmentReturn!: string;

  @ApiProperty({ format: 'uuid', description: 'FK to yards.id (origin)' })
  @IsUUID()
  originYardId!: string;

  @ApiProperty({ format: 'uuid', description: 'FK to yards.id (destination)' })
  @IsUUID()
  destinationYardId!: string;

  @ApiProperty({ enum: TRADE_DIRECTIONS })
  @IsIn([...TRADE_DIRECTIONS])
  tradeDirection!: string;

  @ApiProperty({ enum: FREIGHT_TYPES, description: 'CONTAINER or BULK (mutually exclusive cargo shape)' })
  @IsIn([...FREIGHT_TYPES])
  freightType!: string;

  @ApiPropertyOptional({
    format: 'uuid',
    description: 'Required for BULK; must be omitted for CONTAINER',
  })
  @ValidateIf((o) => o.freightType === 'BULK')
  @IsUUID()
  cargoTypeId?: string;

  @ApiPropertyOptional({ maxLength: 200 })
  @IsOptional()
  @IsString()
  cargoFreeText?: string;

  @ApiPropertyOptional({ format: 'uuid', description: 'FK to shipping_lines.id' })
  @IsOptional()
  @IsUUID()
  shippingLineId?: string;

  @ApiProperty({ description: 'Total cargo weight VGM in tons', minimum: 0 })
  @IsNumber()
  @Min(0)
  @Transform(({ value }) => Number(value))
  cargoTotalWeightVgm!: number;

  @ApiPropertyOptional({ default: false })
  @IsOptional()
  @IsBoolean()
  @Transform(({ value }) => value === 'true' || value === true)
  isHazardous?: boolean;

  @ApiProperty({ enum: PAYMENT_CURRENCIES })
  @IsIn([...PAYMENT_CURRENCIES])
  paymentCurrency!: string;

  @ApiPropertyOptional()
  @IsOptional()
  @IsString()
  pnrCode?: string;

  @ApiPropertyOptional()
  @IsOptional()
  @IsDateString()
  startDate?: string;

  @ApiPropertyOptional()
  @IsOptional()
  @IsDateString()
  endDate?: string;

  @ApiPropertyOptional()
  @IsOptional()
  @IsString()
  financialTerms?: string;

  @ApiPropertyOptional({
    type: [CreateBookingContainerDto],
    description: 'Required for CONTAINER (min 1 line); must be empty for BULK',
  })
  @ValidateIf((o) => o.freightType === 'CONTAINER')
  @IsArray()
  @ArrayMinSize(1)
  @ValidateNested({ each: true })
  @Type(() => CreateBookingContainerDto)
  containers?: CreateBookingContainerDto[];

  @ApiPropertyOptional({ default: false })
  @IsOptional()
  @IsBoolean()
  @Transform(({ value }) => value === 'true' || value === true)
  allowConsolidation?: boolean;
}
