// History entries
//   reorder: { type:'reorder', files:[...], affectedPaths: Set|null }
//   delete:  { type:'delete',  files:[...] /* filesAfter */,
//              deletedEntries:[{name, originalPath, stagingPath}] /* mutable */ }

const MAX = 50;
let _stack    = [];
let _cursor   = -1;
let _onUpdate = null;

export function setOnUpdate(fn) { _onUpdate = fn; }

// ── Push ─────────────────────────────────────────
export function pushReorder(files, affectedPaths = null) {
  _truncate();
  _stack.push({
    type: 'reorder',
    files: [...files],
    affectedPaths: affectedPaths ? new Set(affectedPaths) : null,
  });
  _finalize();
}

export function pushDelete(filesAfter, deletedEntries) {
  _truncate();
  _stack.push({ type: 'delete', files: [...filesAfter], deletedEntries });
  _finalize();
}

function _truncate() { _stack = _stack.slice(0, _cursor + 1); }
function _finalize() {
  if (_stack.length > MAX) _stack.shift();
  _cursor = _stack.length - 1;
  _onUpdate?.();
}

// ── Undo / Redo ───────────────────────────────────
// Returns { entry, targetFiles }
//   entry       — the entry being undone/redone (for type-specific side-effects)
//   targetFiles — the files[] to restore in state
export function undo() {
  if (!canUndo()) return null;
  const entry = _stack[_cursor]; // operation being undone
  --_cursor;
  _onUpdate?.();
  return { entry, targetFiles: [..._stack[_cursor].files] };
}

export function redo() {
  if (!canRedo()) return null;
  ++_cursor;
  _onUpdate?.();
  const entry = _stack[_cursor];
  return { entry, targetFiles: [...entry.files] };
}

// Peek at the next redo entry without moving cursor (for pre-processing)
export function peekRedo() {
  return canRedo() ? _stack[_cursor + 1] : null;
}

export function canUndo() { return _cursor > 0; }
export function canRedo() { return _cursor < _stack.length - 1; }

export function reset() {
  _stack  = [];
  _cursor = -1;
  _onUpdate?.();
}
