import { focusManager as F } from "./focusManager.js";
import { onlineManager as h } from "./onlineManager.js";
import { pendingThenable as b } from "./thenable.js";
import { environmentManager as j } from "./environmentManager.js";
import { sleep as D } from "./utils.js";
function E(e) {
  return Math.min(1e3 * 2 ** e, 3e4);
}
function O(e) {
  return (e ?? "online") === "online" ? h.isOnline() : !0;
}
var k = class extends Error {
  constructor(e) {
    super("CancelledError"), this.revert = e?.revert, this.silent = e?.silent;
  }
};
function z(e) {
  let c = !1, s = 0, a;
  const n = b(), r = () => n.status !== "pending", v = (t) => {
    if (!r()) {
      const i = new k(t);
      u(i), e.onCancel?.(i);
    }
  }, R = () => {
    c = !0;
  }, C = () => {
    c = !1;
  }, f = () => F.isFocused() && (e.networkMode === "always" || h.isOnline()) && e.canRun(), d = () => O(e.networkMode) && e.canRun(), M = (t) => {
    r() || (a?.(), n.resolve(t));
  }, u = (t) => {
    r() || (a?.(), n.reject(t));
  }, p = () => new Promise((t) => {
    a = (i) => {
      (r() || f()) && t(i);
    }, e.onPause?.();
  }).then(() => {
    a = void 0, r() || e.onContinue?.();
  }), m = () => {
    if (r())
      return;
    let t;
    const i = s === 0 ? e.initialPromise : void 0;
    try {
      t = i ?? e.fn();
    } catch (o) {
      t = Promise.reject(o);
    }
    Promise.resolve(t).then(M).catch((o) => {
      if (r())
        return;
      const l = e.retry ?? (j.isServer() ? 0 : 3), y = e.retryDelay ?? E, P = typeof y == "function" ? y(s, o) : y, w = l === !0 || typeof l == "number" && s < l || typeof l == "function" && l(s, o);
      if (c || !w) {
        u(o);
        return;
      }
      s++, e.onFail?.(s, o), D(P).then(() => f() ? void 0 : p()).then(() => {
        c ? u(o) : m();
      });
    });
  };
  return {
    promise: n,
    status: () => n.status,
    cancel: v,
    continue: () => (a?.(), n),
    cancelRetry: R,
    continueRetry: C,
    canStart: d,
    start: () => (d() ? m() : p().then(m), n)
  };
}
export {
  k as CancelledError,
  O as canFetch,
  z as createRetryer
};
