import {
  ValidationArguments,
  ValidatorConstraint,
  ValidatorConstraintInterface,
} from 'class-validator';

import { FREIGHT_TYPES, FreightType } from '../../entities/booking.entity';

export interface BookingFreightShapeInput {
  freightType?: string;
  cargoTypeId?: string | null;
  containers?: Array<{ containerTypeId?: string }> | null;
}

@ValidatorConstraint({ name: 'BookingFreightShape', async: false })
export class BookingFreightShapeConstraint implements ValidatorConstraintInterface {
  validate(_value: unknown, args: ValidationArguments): boolean {
    const dto = args.object as BookingFreightShapeInput;
    if (!dto.freightType || !FREIGHT_TYPES.includes(dto.freightType as FreightType)) {
      return true;
    }

    const containers = dto.containers ?? [];
    const hasContainers = containers.length > 0;
    const hasCargoType =
      dto.cargoTypeId !== undefined &&
      dto.cargoTypeId !== null &&
      String(dto.cargoTypeId).trim() !== '';

    if (dto.freightType === 'BULK') {
      if (hasContainers) return false;
      if (!hasCargoType) return false;
      return true;
    }

    if (dto.freightType === 'CONTAINER') {
      if (hasCargoType) return false;
      if (!hasContainers) return false;
      return containers.every(
        (c) =>
          c.containerTypeId !== undefined &&
          c.containerTypeId !== null &&
          String(c.containerTypeId).trim() !== '',
      );
    }

    return true;
  }

  defaultMessage(args: ValidationArguments): string {
    const dto = args.object as BookingFreightShapeInput;
    if (dto.freightType === 'BULK') {
      return 'BULK freight requires cargoTypeId and must not include container lines';
    }
    if (dto.freightType === 'CONTAINER') {
      return 'CONTAINER freight requires at least one container line with containerTypeId and must not include cargoTypeId';
    }
    return 'Invalid freight type shape';
  }
}
