/**
 * Pure undo/redo history reducer over immutable snapshots. Framework-agnostic
 * so it can be unit-tested in isolation; the facade wraps it with debounced
 * commits and Angular signals. `past` is oldest-to-newest; `future` is the
 * redo stack, newest-undone first.
 */

export const HISTORY_LIMIT = 50;

export interface History<T> {
  readonly past: readonly T[];
  readonly future: readonly T[];
}

export interface HistoryStep<T> {
  readonly history: History<T>;
  readonly value: T;
}

export function emptyHistory<T>(): History<T> {
  return { past: [], future: [] };
}

/** Records a snapshot as a new undo point and drops the redo stack. Caps depth at `limit`. */
export function commit<T>(history: History<T>, snapshot: T, limit = HISTORY_LIMIT): History<T> {
  const past = [...history.past, snapshot].slice(-limit);
  return { past, future: [] };
}

/** Steps back one snapshot, pushing `current` onto the redo stack. Null when nothing to undo. */
export function undo<T>(history: History<T>, current: T): HistoryStep<T> | null {
  if (history.past.length === 0) {
    return null;
  }
  const value = history.past[history.past.length - 1];
  return {
    history: { past: history.past.slice(0, -1), future: [current, ...history.future] },
    value,
  };
}

/** Steps forward one snapshot, pushing `current` back onto the undo stack. Null when nothing to redo. */
export function redo<T>(history: History<T>, current: T): HistoryStep<T> | null {
  if (history.future.length === 0) {
    return null;
  }
  const value = history.future[0];
  return {
    history: { past: [...history.past, current], future: history.future.slice(1) },
    value,
  };
}
