/**
 * RateQuote Entity
 *
 * Represents a shipping rate quote from a carrier
 *
 * Business Rules:
 * - Price must be positive
 * - ETA must be after ETD
 * - Transit days must be positive
 * - Rate quotes expire after 15 minutes (cache TTL)
 * - Availability must be between 0 and actual capacity
 */

export interface RouteSegment {
  portCode: string;
  portName: string;
  arrival?: Date;
  departure?: Date;
  vesselName?: string;
  voyageNumber?: string;
}

export interface Surcharge {
  type: string; // e.g., 'BAF', 'CAF', 'THC', 'ISPS'
  description: string;
  amount: number;
  currency: string;
}

export interface PriceBreakdown {
  baseFreight: number;
  surcharges: Surcharge[];
  totalAmount: number;
  currency: string;
}

export interface RateQuoteProps {
  id: string;
  carrierId: string;
  carrierName: string;
  carrierCode: string;
  origin: {
    code: string;
    name: string;
    country: string;
  };
  destination: {
    code: string;
    name: string;
    country: string;
  };
  pricing: PriceBreakdown;
  containerType: string; // e.g., '20DRY', '40HC', '40REEFER'
  mode: 'FCL' | 'LCL';
  etd: Date; // Estimated Time of Departure
  eta: Date; // Estimated Time of Arrival
  transitDays: number;
  route: RouteSegment[];
  availability: number; // Available container slots
  frequency: string; // e.g., 'Weekly', 'Bi-weekly'
  vesselType?: string; // e.g., 'Container Ship', 'Ro-Ro'
  co2EmissionsKg?: number; // CO2 emissions in kg
  validUntil: Date; // When this quote expires (typically createdAt + 15 min)
  createdAt: Date;
  updatedAt: Date;
}

export class RateQuote {
  private readonly props: RateQuoteProps;

  private constructor(props: RateQuoteProps) {
    this.props = props;
  }

  /**
   * Factory method to create a new RateQuote
   */
  static create(
    props: Omit<RateQuoteProps, 'id' | 'validUntil' | 'createdAt' | 'updatedAt'> & { id: string }
  ): RateQuote {
    const now = new Date();
    const validUntil = new Date(now.getTime() + 15 * 60 * 1000); // 15 minutes

    // Validate pricing
    if (props.pricing.totalAmount <= 0) {
      throw new Error('Total price must be positive.');
    }

    if (props.pricing.baseFreight <= 0) {
      throw new Error('Base freight must be positive.');
    }

    // Validate dates
    if (props.eta <= props.etd) {
      throw new Error('ETA must be after ETD.');
    }

    // Validate transit days
    if (props.transitDays <= 0) {
      throw new Error('Transit days must be positive.');
    }

    // Validate availability
    if (props.availability < 0) {
      throw new Error('Availability cannot be negative.');
    }

    // Validate route has at least origin and destination
    if (props.route.length < 2) {
      throw new Error('Route must have at least origin and destination ports.');
    }

    return new RateQuote({
      ...props,
      validUntil,
      createdAt: now,
      updatedAt: now,
    });
  }

  /**
   * Factory method to reconstitute from persistence
   */
  static fromPersistence(props: RateQuoteProps): RateQuote {
    return new RateQuote(props);
  }

  // Getters
  get id(): string {
    return this.props.id;
  }

  get carrierId(): string {
    return this.props.carrierId;
  }

  get carrierName(): string {
    return this.props.carrierName;
  }

  get carrierCode(): string {
    return this.props.carrierCode;
  }

  get origin(): { code: string; name: string; country: string } {
    return { ...this.props.origin };
  }

  get destination(): { code: string; name: string; country: string } {
    return { ...this.props.destination };
  }

  get pricing(): PriceBreakdown {
    return {
      ...this.props.pricing,
      surcharges: [...this.props.pricing.surcharges],
    };
  }

  get containerType(): string {
    return this.props.containerType;
  }

  get mode(): 'FCL' | 'LCL' {
    return this.props.mode;
  }

  get etd(): Date {
    return this.props.etd;
  }

  get eta(): Date {
    return this.props.eta;
  }

  get transitDays(): number {
    return this.props.transitDays;
  }

  get route(): RouteSegment[] {
    return [...this.props.route];
  }

  get availability(): number {
    return this.props.availability;
  }

  get frequency(): string {
    return this.props.frequency;
  }

  get vesselType(): string | undefined {
    return this.props.vesselType;
  }

  get co2EmissionsKg(): number | undefined {
    return this.props.co2EmissionsKg;
  }

  get validUntil(): Date {
    return this.props.validUntil;
  }

  get createdAt(): Date {
    return this.props.createdAt;
  }

  get updatedAt(): Date {
    return this.props.updatedAt;
  }

  // Business methods
  /**
   * Check if the rate quote is still valid (not expired)
   */
  isValid(): boolean {
    return new Date() < this.props.validUntil;
  }

  /**
   * Check if the rate quote has expired
   */
  isExpired(): boolean {
    return new Date() >= this.props.validUntil;
  }

  /**
   * Check if containers are available
   */
  hasAvailability(): boolean {
    return this.props.availability > 0;
  }

  /**
   * Get total surcharges amount
   */
  getTotalSurcharges(): number {
    return this.props.pricing.surcharges.reduce((sum, surcharge) => sum + surcharge.amount, 0);
  }

  /**
   * Get number of transshipments (route segments minus 2 for origin and destination)
   */
  getTransshipmentCount(): number {
    return Math.max(0, this.props.route.length - 2);
  }

  /**
   * Check if this is a direct route (no transshipments)
   */
  isDirectRoute(): boolean {
    return this.getTransshipmentCount() === 0;
  }

  /**
   * Get price per day (for comparison)
   */
  getPricePerDay(): number {
    return this.props.pricing.totalAmount / this.props.transitDays;
  }

  /**
   * Convert to plain object for persistence
   */
  toObject(): RateQuoteProps {
    return {
      ...this.props,
      origin: { ...this.props.origin },
      destination: { ...this.props.destination },
      pricing: {
        ...this.props.pricing,
        surcharges: [...this.props.pricing.surcharges],
      },
      route: [...this.props.route],
    };
  }
}
