import { Money } from './money.vo';

/**
 * Surcharge Type Enumeration
 * Common maritime shipping surcharges
 */
export enum SurchargeType {
  BAF = 'BAF', // Bunker Adjustment Factor
  CAF = 'CAF', // Currency Adjustment Factor
  PSS = 'PSS', // Peak Season Surcharge
  THC = 'THC', // Terminal Handling Charge
  OTHER = 'OTHER',
}

/**
 * Surcharge Value Object
 * Represents additional fees applied to base freight rates
 */
export class Surcharge {
  constructor(
    public readonly type: SurchargeType,
    public readonly amount: Money,
    public readonly description?: string
  ) {
    this.validate();
  }

  private validate(): void {
    if (!Object.values(SurchargeType).includes(this.type)) {
      throw new Error(`Invalid surcharge type: ${this.type}`);
    }
  }

  /**
   * Get human-readable surcharge label
   */
  getLabel(): string {
    const labels: Record<SurchargeType, string> = {
      [SurchargeType.BAF]: 'Bunker Adjustment Factor',
      [SurchargeType.CAF]: 'Currency Adjustment Factor',
      [SurchargeType.PSS]: 'Peak Season Surcharge',
      [SurchargeType.THC]: 'Terminal Handling Charge',
      [SurchargeType.OTHER]: 'Other Surcharge',
    };
    return labels[this.type];
  }

  equals(other: Surcharge): boolean {
    return this.type === other.type && this.amount.isEqualTo(other.amount);
  }

  toString(): string {
    const label = this.description || this.getLabel();
    return `${label}: ${this.amount.toString()}`;
  }
}

/**
 * Collection of surcharges with utility methods
 */
export class SurchargeCollection {
  constructor(public readonly surcharges: Surcharge[]) {}

  /**
   * Calculate total surcharge amount in a specific currency
   * Note: This assumes all surcharges are in the same currency
   * In production, currency conversion would be needed
   */
  getTotalAmount(currency: string): Money {
    const relevantSurcharges = this.surcharges.filter(s => s.amount.getCurrency() === currency);

    if (relevantSurcharges.length === 0) {
      return Money.zero(currency);
    }

    return relevantSurcharges.reduce(
      (total, surcharge) => total.add(surcharge.amount),
      Money.zero(currency)
    );
  }

  /**
   * Check if collection has any surcharges
   */
  isEmpty(): boolean {
    return this.surcharges.length === 0;
  }

  /**
   * Get surcharges by type
   */
  getByType(type: SurchargeType): Surcharge[] {
    return this.surcharges.filter(s => s.type === type);
  }

  /**
   * Get formatted surcharge details for display
   */
  getDetails(): string {
    if (this.isEmpty()) {
      return 'All-in price (no separate surcharges)';
    }
    return this.surcharges.map(s => s.toString()).join(', ');
  }
}
