// src/engine/messaging/LamportClock.ts
//
// LamportClock - Logical clock for causal message ordering.
//
// Leslie Lamport (1978, "Time, Clocks, and the Ordering of Events in Distributed Systems"):
//   "The partial ordering is obtained from a logical clock, which is a way
//    of assigning a number to an event, where the number is thought of as the
//    time at which the event occurred."
//
// This implementation provides Lamport timestamps for causal ordering of transport messages,
// specifically to ensure that events emitted before an exit signal are delivered before
// the exit signal itself.
//
// Algorithm:
//   1. Each process maintains a counter C, initially 0
//   2. Before local event: C := C + 1
//   3. Before sending message: C := C + 1, attach C to message
//   4. On receiving message with timestamp T: C := max(C, T) + 1
//
// Guarantee: If event a causally precedes event b, then timestamp(a) < timestamp(b)
//
// Reference: Vision 41 §8.4 (Topic Structure with causal ordering)
// Reference: FOLD-EXPERT-COMMITTEE-REVIEW.md (Leslie Lamport CRITICAL enhancement)

/**
 * Lamport logical clock for causal message ordering.
 *
 * Leslie Lamport (TLA+, Turing Award):
 *   "The fundamental idea is that a process increments its counter before
 *    each event in that process."
 *
 * Properties:
 * - Thread-safe for single-process use (no async operations modify counter)
 * - O(1) time complexity for all operations
 * - Provides partial ordering guarantee
 *
 * Usage:
 * ```typescript
 * const clock = new LamportClock();
 *
 * // Before local event
 * clock.tick();
 *
 * // Before sending message
 * const timestamp = clock.send();
 * message.lamportClock = timestamp;
 *
 * // On receiving message
 * clock.receive(message.lamportClock);
 * ```
 */
export class LamportClock {
  /**
   * The logical clock counter.
   * Incremented on local events and message sends.
   * Updated to max(local, remote) + 1 on message receives.
   */
  private _counter: number = 0;

  /**
   * Get current clock value (read-only).
   * Do not modify the counter directly - use tick(), send(), or receive().
   */
  get value(): number {
    return this._counter;
  }

  /**
   * Tick clock for a local event.
   *
   * Call this before executing any local event that should be causally ordered.
   * Returns the new clock value.
   *
   * Example:
   * ```typescript
   * clock.tick();
   * await processLocalEvent();
   * ```
   */
  tick(): number {
    this._counter += 1;
    return this._counter;
  }

  /**
   * Prepare to send a message.
   *
   * Call this when preparing to send a message. Returns the timestamp
   * that should be attached to the message.
   *
   * Example:
   * ```typescript
   * const timestamp = clock.send();
   * transport.publish(topic, { ...payload, __lamportClock: timestamp });
   * ```
   *
   * @returns The Lamport timestamp to attach to the message
   */
  send(): number {
    this._counter += 1;
    return this._counter;
  }

  /**
   * Process a received message with remote timestamp.
   *
   * Call this when receiving a message with a Lamport timestamp.
   * Updates local clock to respect causality: C := max(C, remote) + 1
   *
   * Example:
   * ```typescript
   * const message = await receive();
   * clock.receive(message.lamportClock);
   * processMessage(message);
   * ```
   *
   * @param remoteTimestamp - The Lamport timestamp from the received message
   * @returns The new local clock value
   */
  receive(remoteTimestamp: number): number {
    // Leslie Lamport: "The receiving process sets its clock to the maximum
    // of its current value and the timestamp of the received message, then
    // increments it."
    this._counter = Math.max(this._counter, remoteTimestamp) + 1;
    return this._counter;
  }

  /**
   * Reset clock to zero.
   * Useful for testing. Should NOT be used in production.
   */
  reset(): void {
    this._counter = 0;
  }

  /**
   * Create a snapshot of the current clock state (for debugging).
   */
  snapshot(): { value: number } {
    return { value: this._counter };
  }

  /**
   * Compare two Lamport timestamps for causal ordering.
   *
   * Returns:
   *  - negative if a < b (a causally precedes b)
   *  - zero if a === b (concurrent or same event)
   *  - positive if a > b (b causally precedes a)
   *
   * Note: Equal timestamps do NOT prove events are concurrent - they may be
   * from different processes with no causal relationship.
   */
  static compare(a: number, b: number): number {
    return a - b;
  }

  /**
   * Merge two Lamport clocks (takes maximum).
   * Useful when combining state from multiple sources.
   *
   * Example:
   * ```typescript
   * const merged = LamportClock.merge(clock1.value, clock2.value);
   * clock.receive(merged);
   * ```
   */
  static merge(a: number, b: number): number {
    return Math.max(a, b);
  }
}
