import { PortCode } from '../value-objects/port-code.vo';
import { ContainerType } from '../value-objects/container-type.vo';
import { DateRange } from '../value-objects/date-range.vo';

export type DgSurchargeValue = number | 'ON REQUEST' | 'NOT ACCEPTED';
export type HandlingUnit = 'W' | 'UP'; // W = tonne revenue (max CBM/T), UP = per CBM
export type FrequencyType = 'Weekly' | 'Bi-Weekly' | 'Bi-Monthly' | 'Monthly';

export interface FreightPricing {
  freightCurrency: string;
  freightRatePerCBM: number; // 0.0 = included/to negotiate
  freightMinimum: number;
}

export interface FobCharges {
  fobCurrency: string;
  fobDocumentation: number;
  fobISPS: number;
  fobHandling: number;
  fobHandlingUnit: HandlingUnit;
  fobHandlingMinimum: number;
  fobSolas: number;
  fobCustoms: number;
  fobAMS_ACI: number;
  fobISF5: number;
  fobDGAdmin: number; // Only if DG shipment
}

export interface DgSurchargeInfo {
  dgSurchargeCurrency: string;
  dgSurchargeRate: DgSurchargeValue;
  dgSurchargeUnit: 'UP' | 'LS' | '%'; // per CBM, lump sum, or percentage
  dgSurchargeMin: DgSurchargeValue;
}

/**
 * CsvRate — Shipping rate from a consolidator CSV file.
 *
 * Business Rules:
 * - Route matching uses originCode + destinationCode (UN/LOCODE)
 * - Price = max(freightRatePerCBM×V, freightMinimum) + FOB fixed + handling
 * - FOB and freight may be in different currencies
 * - DG surcharge applies only when hasDangerousGoods = true
 */
export class CsvRate {
  constructor(
    // Supplier identity
    public readonly companyName: string,
    public readonly companyEmail: string,
    // Route geography
    public readonly originCFS: string,
    public readonly originCode: PortCode,
    public readonly portOfLoading: string,
    public readonly routing: string,
    public readonly destinationCFS: string,
    public readonly destinationCode: PortCode,
    public readonly destinationCountry: string,
    // Container
    public readonly containerType: ContainerType,
    // Pricing
    public readonly freight: FreightPricing,
    public readonly fob: FobCharges,
    public readonly dgSurcharge: DgSurchargeInfo,
    // Metadata
    public readonly remarks: string,
    public readonly frequency: FrequencyType,
    public readonly transitDays: number,
    public readonly validity: DateRange
  ) {
    this.validate();
  }

  private validate(): void {
    if (!this.companyName?.trim()) throw new Error('Company name is required');
    if (!this.companyEmail?.trim()) throw new Error('Company email is required');
    if (this.transitDays <= 0) throw new Error('Transit days must be positive');
    if (this.freight.freightMinimum < 0) throw new Error('Freight minimum cannot be negative');
    if (this.fob.fobHandling < 0) throw new Error('FOB handling cannot be negative');
  }

  isValidForDate(date: Date): boolean {
    return this.validity.contains(date);
  }

  isCurrentlyValid(): boolean {
    return this.validity.isCurrentRange();
  }

  matchesRoute(origin: PortCode, destination: PortCode): boolean {
    return this.originCode.equals(origin) && this.destinationCode.equals(destination);
  }

  isDgAccepted(): boolean {
    return this.dgSurcharge.dgSurchargeRate !== 'NOT ACCEPTED';
  }

  isDgOnRequest(): boolean {
    return this.dgSurcharge.dgSurchargeRate === 'ON REQUEST';
  }

  isDirectRoute(): boolean {
    return this.routing.trim().toLowerCase() === 'direct';
  }

  getFrequencyScore(): number {
    switch (this.frequency) {
      case 'Weekly':
        return 4;
      case 'Bi-Weekly':
        return 3;
      case 'Bi-Monthly':
        return 2;
      case 'Monthly':
        return 1;
      default:
        return 2;
    }
  }

  getRouteDescription(): string {
    return `${this.originCode.getValue()} → ${this.destinationCode.getValue()}`;
  }

  getSummary(): string {
    return `${this.companyName}: ${this.getRouteDescription()} (${this.containerType.getValue()})`;
  }

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