/**
 * BookingStatus Value Object
 *
 * Represents the current status of a booking
 */

import { InvalidBookingStatusException } from '../exceptions/invalid-booking-status.exception';

export type BookingStatusValue =
  | 'draft'
  | 'pending_confirmation'
  | 'confirmed'
  | 'in_transit'
  | 'delivered'
  | 'cancelled';

export class BookingStatus {
  private static readonly VALID_STATUSES: BookingStatusValue[] = [
    'draft',
    'pending_confirmation',
    'confirmed',
    'in_transit',
    'delivered',
    'cancelled',
  ];

  private static readonly STATUS_TRANSITIONS: Record<BookingStatusValue, BookingStatusValue[]> = {
    draft: ['pending_confirmation', 'cancelled'],
    pending_confirmation: ['confirmed', 'cancelled'],
    confirmed: ['in_transit', 'cancelled'],
    in_transit: ['delivered', 'cancelled'],
    delivered: [],
    cancelled: [],
  };

  private readonly _value: BookingStatusValue;

  private constructor(value: BookingStatusValue) {
    this._value = value;
  }

  get value(): BookingStatusValue {
    return this._value;
  }

  /**
   * Create BookingStatus from string
   */
  static create(value: string): BookingStatus {
    if (!BookingStatus.isValid(value)) {
      throw new InvalidBookingStatusException(value);
    }
    return new BookingStatus(value as BookingStatusValue);
  }

  /**
   * Validate status value
   */
  static isValid(value: string): boolean {
    return BookingStatus.VALID_STATUSES.includes(value as BookingStatusValue);
  }

  /**
   * Check if transition to another status is allowed
   */
  canTransitionTo(newStatus: BookingStatus): boolean {
    const allowedTransitions = BookingStatus.STATUS_TRANSITIONS[this._value];
    return allowedTransitions.includes(newStatus._value);
  }

  /**
   * Transition to new status
   */
  transitionTo(newStatus: BookingStatus): BookingStatus {
    if (!this.canTransitionTo(newStatus)) {
      throw new Error(`Invalid status transition from ${this._value} to ${newStatus._value}`);
    }
    return newStatus;
  }

  /**
   * Check if booking is in a final state
   */
  isFinal(): boolean {
    return this._value === 'delivered' || this._value === 'cancelled';
  }

  /**
   * Check if booking can be modified
   */
  canBeModified(): boolean {
    return this._value === 'draft' || this._value === 'pending_confirmation';
  }

  /**
   * Equality check
   */
  equals(other: BookingStatus): boolean {
    return this._value === other._value;
  }

  /**
   * String representation
   */
  toString(): string {
    return this._value;
  }
}
