/**
 * GroupReservation domain events — discriminated union.
 *
 * Covers the reservation.status state machine driven by workflows/group-reservation.ts:
 *   HELD + cancel_requested(within_14d)           → CANCELLED
 *   HELD + cancel_requested(past_14d, FLEXIBLE)   → CANCELLED
 *   HELD + cancel_requested(past_14d, LEGAL_ONLY) → rejected (INVALID_STATE error)
 *
 * Also covers the post-reservation-creation flow (after hold succeeds):
 *   AWAITING_FANOUT + reservation_placed(below_min)       → no transition, no effects
 *   AWAITING_FANOUT + reservation_placed(>= min, < max)   → fan-out: record-threshold-met
 *   AWAITING_FANOUT + reservation_placed(>= max)          → fan-out: record-threshold-met + execute-requested
 *
 * Also covers waitlist promotion:
 *   AWAITING_PROMOTION + promote_requested(no_next) → no effects
 *   AWAITING_PROMOTION + promote_requested(has_next, user) → promote + push + outbox
 *   AWAITING_PROMOTION + promote_requested(has_next, guest) → promote + outbox (no push)
 *
 * Pure module: no imports from @/server/db, do-client, outbox-producer, payments, fetch.
 */

export type ReservationStatus = 'HELD' | 'CANCELLED' | 'CAPTURED' | 'RELEASED';
// CUSTOM_WINDOW = custom cancellation window (hours from groupCancellationWindowHours);
// treated like FLEXIBLE at the machine level — not blocked by the 14-day LEGAL_ONLY gate.
export type CancellationPolicy = 'LEGAL_ONLY' | 'FLEXIBLE' | 'CUSTOM_WINDOW';
export type GroupState =
  | 'COLLECTING'
  | 'THRESHOLD_MET'
  | 'EXTENDED'
  | 'PARTIAL_PENDING'
  | 'SUCCEEDED'
  | 'FAILED'
  | 'CANCELLED'
  | 'EXECUTED';

export type GroupReservationEvent =
  /** User-initiated cancellation. */
  | {
      kind: 'cancel_requested';
      reservationId: string;
      groupDealId: string;
      dealId: string;
      dealTitle: string;
      userId: string;
      quantity: number;
      cancellationPolicy: CancellationPolicy;
      daysSinceReservation: number;
      hasHold: boolean;
      providerAuthorizationId: string | null;
      at: Date;
    }
  /** Fired after a J5 hold succeeds + the count increments. */
  | {
      kind: 'reservation_placed';
      groupDealId: string;
      dealId: string;
      vendorId: string;
      dealTitle: string;
      newCount: number;
      minGroupSize: number;
      maxGroupSize: number;
      previousGroupState: GroupState;
      /** True when a registered user placed this reservation. Guest path
       *  intentionally suppresses the vendor push notification. */
      isRegisteredPath: boolean;
      at: Date;
    }
  /** Cancellation post-write: count dropped, decide threshold-lost effect. */
  | {
      kind: 'cancellation_finalized';
      reservationId: string;
      groupDealId: string;
      dealId: string;
      dealTitle: string;
      vendorId: string;
      userId: string;
      newCount: number;
      minGroupSize: number;
      currentGroupState: GroupState;
      at: Date;
    }
  /** Waitlist promotion after a cancellation freed a slot. */
  | {
      kind: 'promote_requested';
      groupDealId: string;
      dealId: string;
      dealTitle: string;
      promotedWaitlistId: string | null;
      promotedUserId: string | null;
      at: Date;
    };
