// Pure, framework-free state machine behind the app-wide Undo flow (KAR-629).
// React lives one layer up in `use-undoable-delete.ts`; this module owns the
// "currently-undoable delete" slot and its optional auto-dismiss timer so it
// can be unit-tested with vi.useFakeTimers without dragging in jsdom or
// @testing-library/react.

export interface UndoableDeleteEngineOptions<TSnapshot> {
  /** Callback invoked with the captured snapshot when `undo()` is called. */
  onUndo: (snapshot: TSnapshot) => void
  /**
   * Optional change notification — fires after every state transition
   * (capture, undo, dismiss, auto-dismiss). React layer uses this to
   * trigger a re-render.
   */
  onChange?: () => void
  /**
   * Auto-clear after this many milliseconds. `0` (or omitted) disables the
   * timer; the slot stays until the user dismisses or another delete
   * replaces it. Matches the agenda editor's existing "no auto-dismiss"
   * UX.
   */
  autoDismissMs?: number
}

export interface UndoableDeleteEngine<TSnapshot> {
  /** Read the currently captured snapshot, or `null` if the slot is empty. */
  getState: () => TSnapshot | null
  /** Record what was just deleted. Replaces any previous capture. */
  capture: (snapshot: TSnapshot) => void
  /** Restore: call `onUndo` with the captured snapshot and clear the slot. */
  undo: () => void
  /** Drop the captured snapshot without calling `onUndo`. */
  dismiss: () => void
  /** Cancel any pending timer — call from the React unmount path. */
  teardown: () => void
}

export function createUndoableDeleteEngine<TSnapshot>(
  opts: UndoableDeleteEngineOptions<TSnapshot>,
): UndoableDeleteEngine<TSnapshot> {
  const { onUndo, onChange, autoDismissMs = 0 } = opts
  let state: TSnapshot | null = null
  let timer: ReturnType<typeof setTimeout> | null = null

  function clearTimer(): void {
    if (timer !== null) {
      clearTimeout(timer)
      timer = null
    }
  }

  function notify(): void {
    if (onChange) onChange()
  }

  function getState(): TSnapshot | null {
    return state
  }

  function capture(snapshot: TSnapshot): void {
    clearTimer()
    state = snapshot
    if (autoDismissMs > 0) {
      timer = setTimeout(() => {
        timer = null
        state = null
        notify()
      }, autoDismissMs)
    }
    notify()
  }

  function undo(): void {
    if (state === null) return
    const snapshot = state
    clearTimer()
    state = null
    onUndo(snapshot)
    notify()
  }

  function dismiss(): void {
    if (state === null && timer === null) return
    clearTimer()
    state = null
    notify()
  }

  function teardown(): void {
    clearTimer()
  }

  return { getState, capture, undo, dismiss, teardown }
}
