'use strict';

// Decision logic for the post-restore read-pool stampede (pure; unit-tested in
// tests/restore-storm.test.js). See that file's header for the problem statement.
//
// Used by server.js to (A) keep the generous off-thread read timeout active through the
// restore window AND a grace period after it, so cold reads finish ON the pool instead of
// bailing to a main-thread compute; and (B) when an off-thread read still fails during the
// storm (pool wedged → breaker open, or even the long timeout exceeded), serve a degraded
// value instead of freezing the event loop with a synchronous main-thread build.

// True for the whole storm window: while the restore loop runs, plus a grace period after
// it completes. The grace covers the SECOND stampede — the post-restore broadcast +
// auto-resume + every UI tab cold-loading at once — which lands just after the loop clears
// _restoreInProgress, exactly when the protection used to switch off.
function inRestoreStorm({ restoreInProgress, restoreCompletedAt, now, graceMs }) {
  if (restoreInProgress) return true;
  if (!(restoreCompletedAt > 0)) return false;
  return (now - restoreCompletedAt) < graceMs;
}

// Decide what an off-thread read's onFail serves when the pool didn't answer:
//   * a last-good cached value, if present — always preferred, never stale-blocks;
//   * during the storm with no cache — the degraded value (e.g. [] / empty), so the heavy
//     compute NEVER runs on the main loop (the freeze we're eliminating);
//   * only when calm AND cold — build once on the main thread, so a normal cold cache miss
//     still returns an immediate, correct result (boot/first-load recovers without a retry).
function offthreadFallback({ inStorm, hasCached, cached, mainCompute, stormEmpty }) {
  if (hasCached) return cached;
  if (inStorm) return stormEmpty;
  return mainCompute();
}

module.exports = { inRestoreStorm, offthreadFallback };
