/**
 * ContainerType Value Object
 *
 * Encapsulates container type validation and behavior
 *
 * Business Rules:
 * - Container type must be valid (e.g., 20DRY, 40HC, 40REEFER)
 * - Container type is immutable
 *
 * Format: {SIZE}{HEIGHT_MODIFIER?}{CATEGORY}
 * Examples: 20DRY, 40HC, 40REEFER, 45HCREEFER
 */

export class ContainerType {
  private readonly value: string;

  // Valid container types
  private static readonly VALID_TYPES = [
    'LCL', // Less than Container Load
    '20DRY',
    '40DRY',
    '20HC',
    '40HC',
    '45HC',
    '20REEFER',
    '40REEFER',
    '40HCREEFER',
    '45HCREEFER',
    '20OT', // Open Top
    '40OT',
    '20FR', // Flat Rack
    '40FR',
    '20TANK',
    '40TANK',
  ];

  private constructor(type: string) {
    this.value = type;
  }

  static create(type: string): ContainerType {
    if (!type || type.trim().length === 0) {
      throw new Error('Container type cannot be empty.');
    }

    const normalized = type.trim().toUpperCase();

    if (!ContainerType.isValid(normalized)) {
      throw new Error(
        `Invalid container type: ${type}. Valid types: ${ContainerType.VALID_TYPES.join(', ')}`
      );
    }

    return new ContainerType(normalized);
  }

  private static isValid(type: string): boolean {
    return ContainerType.VALID_TYPES.includes(type);
  }

  getValue(): string {
    return this.value;
  }

  getSize(): string {
    // Extract size (first 2 digits)
    return this.value.match(/^\d+/)?.[0] || '';
  }

  getTEU(): number {
    const size = this.getSize();
    if (size === '20') return 1;
    if (size === '40' || size === '45') return 2;
    return 0;
  }

  isDry(): boolean {
    return this.value.includes('DRY');
  }

  isReefer(): boolean {
    return this.value.includes('REEFER');
  }

  isHighCube(): boolean {
    return this.value.includes('HC');
  }

  isOpenTop(): boolean {
    return this.value.includes('OT');
  }

  isFlatRack(): boolean {
    return this.value.includes('FR');
  }

  isTank(): boolean {
    return this.value.includes('TANK');
  }

  isLCL(): boolean {
    return this.value === 'LCL';
  }

  equals(other: ContainerType): boolean {
    return this.value === other.value;
  }

  toString(): string {
    return this.value;
  }
}
