import { parse } from "../../../shared/src/valita.js";
import { errorKindSchema } from "../../../zero-protocol/src/error.js";
import { updateNeededReasonTypeSchema } from "./options.js";
import { tuple, union, string, object, number } from "@badrap/valita";
const RELOAD_REASON_STORAGE_KEY = "_zeroReloadReason";
const RELOAD_BACKOFF_STATE_KEY = "_zeroReloadBackoffState";
const reloadReasonSchema = tuple([
  union(updateNeededReasonTypeSchema, errorKindSchema),
  string()
]);
const backoffStateSchema = object({
  lastReloadTime: number().default(0),
  nextIntervalMs: number().default(0)
});
const MIN_RELOAD_INTERVAL_MS = 500;
const MAX_RELOAD_INTERVAL_MS = 6e4;
const FALLBACK_RELOAD_INTERVAL_MS = 1e4;
let reloadTimer = null;
function reloadWithReason(lc, reload, reason, message) {
  if (reloadTimer) {
    lc.info?.("reload timer already scheduled");
    return;
  }
  const now = Date.now();
  const backoff = nextBackoff(lc, now);
  if (typeof sessionStorage !== "undefined") {
    sessionStorage.setItem(RELOAD_BACKOFF_STATE_KEY, JSON.stringify(backoff));
    sessionStorage.setItem(
      RELOAD_REASON_STORAGE_KEY,
      JSON.stringify([reason, message])
    );
  }
  const delay = backoff.lastReloadTime - now;
  lc.error?.(
    reason,
    "\n",
    "reloading",
    delay > 0 ? `in ${delay / 1e3} seconds` : ""
  );
  reloadTimer = setTimeout(() => {
    reloadTimer = null;
    reload();
  }, delay);
}
function reportReloadReason(lc) {
  if (typeof sessionStorage !== "undefined") {
    const value = sessionStorage.getItem(RELOAD_REASON_STORAGE_KEY);
    if (value) {
      sessionStorage.removeItem(RELOAD_REASON_STORAGE_KEY);
      try {
        const parsed = JSON.parse(value);
        const [reasonType, message] = parse(parsed, reloadReasonSchema);
        lc.error?.(reasonType, "Zero reloaded the page.", message);
      } catch (e) {
        lc.error?.("Zero reloaded the page.", e);
        return;
      }
    }
  }
}
function reloadScheduled() {
  return reloadTimer !== null;
}
function resetBackoff() {
  if (typeof sessionStorage !== "undefined") {
    sessionStorage.removeItem(RELOAD_BACKOFF_STATE_KEY);
  }
}
function nextBackoff(lc, now) {
  if (typeof sessionStorage === "undefined") {
    lc.warn?.(
      `sessionStorage not supported. backing off in ${FALLBACK_RELOAD_INTERVAL_MS / 1e3} seconds`
    );
    return {
      lastReloadTime: now + FALLBACK_RELOAD_INTERVAL_MS,
      nextIntervalMs: MIN_RELOAD_INTERVAL_MS
    };
  }
  const val = sessionStorage.getItem(RELOAD_BACKOFF_STATE_KEY);
  if (!val) {
    return { lastReloadTime: now, nextIntervalMs: MIN_RELOAD_INTERVAL_MS };
  }
  let parsed;
  try {
    parsed = parse(JSON.parse(val), backoffStateSchema, "passthrough");
  } catch (e) {
    lc.warn?.("ignoring unparsable backoff state", val, e);
    return { lastReloadTime: now, nextIntervalMs: MIN_RELOAD_INTERVAL_MS };
  }
  const { lastReloadTime, nextIntervalMs } = parsed;
  if (now - lastReloadTime > MAX_RELOAD_INTERVAL_MS * 2) {
    return { lastReloadTime: now, nextIntervalMs: MIN_RELOAD_INTERVAL_MS };
  }
  if (now < lastReloadTime) {
    return parsed;
  }
  const nextReloadTime = Math.max(now, lastReloadTime + nextIntervalMs);
  return {
    lastReloadTime: nextReloadTime,
    nextIntervalMs: Math.min(nextIntervalMs * 2, MAX_RELOAD_INTERVAL_MS)
  };
}
export {
  FALLBACK_RELOAD_INTERVAL_MS,
  MAX_RELOAD_INTERVAL_MS,
  MIN_RELOAD_INTERVAL_MS,
  RELOAD_BACKOFF_STATE_KEY,
  RELOAD_REASON_STORAGE_KEY,
  reloadScheduled,
  reloadWithReason,
  reportReloadReason,
  resetBackoff
};
//# sourceMappingURL=reload-error-handler.js.map
