function hasInitialValue(atom) {
  return "init" in atom;
}
function isActuallyWritableAtom(atom) {
  return !!atom.write;
}
function isAtomStateInitialized(atomState) {
  return "v" in atomState || "e" in atomState;
}
function returnAtomValue(atomState) {
  if ("e" in atomState) {
    throw atomState.e;
  }
  if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && !("v" in atomState)) {
    throw new Error("[Bug] atom state is not initialized");
  }
  return atomState.v;
}
const promiseStateMap = /* @__PURE__ */ new WeakMap();
function isPendingPromise(value) {
  var _a;
  return isPromiseLike(value) && !!((_a = promiseStateMap.get(value)) == null ? void 0 : _a[0]);
}
function abortPromise(promise) {
  const promiseState = promiseStateMap.get(promise);
  if (promiseState == null ? void 0 : promiseState[0]) {
    promiseState[0] = false;
    promiseState[1].forEach((fn) => fn());
  }
}
function registerAbortHandler(promise, abortHandler) {
  let promiseState = promiseStateMap.get(promise);
  if (!promiseState) {
    promiseState = [true, /* @__PURE__ */ new Set()];
    promiseStateMap.set(promise, promiseState);
    const settle = () => {
      promiseState[0] = false;
    };
    promise.then(settle, settle);
  }
  promiseState[1].add(abortHandler);
}
function isPromiseLike(p) {
  return typeof (p == null ? void 0 : p.then) === "function";
}
function addPendingPromiseToDependency(atom, promise, dependencyAtomState) {
  if (!dependencyAtomState.p.has(atom)) {
    dependencyAtomState.p.add(atom);
    const cleanup = () => dependencyAtomState.p.delete(atom);
    promise.then(cleanup, cleanup);
  }
}
function getMountedOrPendingDependents(atom, atomState, mountedMap) {
  var _a;
  const dependents = /* @__PURE__ */ new Set();
  for (const a of ((_a = mountedMap.get(atom)) == null ? void 0 : _a.t) || []) {
    if (mountedMap.has(a)) {
      dependents.add(a);
    }
  }
  for (const atomWithPendingPromise of atomState.p) {
    dependents.add(atomWithPendingPromise);
  }
  return dependents;
}
const createStoreHook = () => {
  const callbacks = /* @__PURE__ */ new Set();
  const notify = () => callbacks.forEach((fn) => fn());
  notify.add = (fn) => {
    callbacks.add(fn);
    return () => callbacks.delete(fn);
  };
  return notify;
};
const createStoreHookForAtoms = () => {
  const all = {};
  const callbacks = /* @__PURE__ */ new WeakMap();
  const notify = (atom) => {
    var _a, _b;
    (_a = callbacks.get(all)) == null ? void 0 : _a.forEach((fn) => fn(atom));
    (_b = callbacks.get(atom)) == null ? void 0 : _b.forEach((fn) => fn());
  };
  notify.add = (atom, fn) => {
    const key = atom || all;
    const fns = (callbacks.has(key) ? callbacks : callbacks.set(key, /* @__PURE__ */ new Set())).get(key);
    fns.add(fn);
    return () => {
      fns == null ? void 0 : fns.delete(fn);
      if (!fns.size) {
        callbacks.delete(key);
      }
    };
  };
  return notify;
};
function initializeStoreHooks(storeHooks) {
  storeHooks.r || (storeHooks.r = createStoreHookForAtoms());
  storeHooks.c || (storeHooks.c = createStoreHookForAtoms());
  storeHooks.m || (storeHooks.m = createStoreHookForAtoms());
  storeHooks.u || (storeHooks.u = createStoreHookForAtoms());
  storeHooks.f || (storeHooks.f = createStoreHook());
  return storeHooks;
}
const atomRead = (_store, atom, ...params) => atom.read(...params);
const atomWrite = (_store, atom, ...params) => atom.write(...params);
const atomOnInit = (store, atom) => {
  var _a;
  return (_a = atom.unstable_onInit) == null ? void 0 : _a.call(atom, store);
};
const atomOnMount = (_store, atom, setAtom) => {
  var _a;
  return (_a = atom.onMount) == null ? void 0 : _a.call(atom, setAtom);
};
const ensureAtomState = (store, atom) => {
  const buildingBlocks = getInternalBuildingBlocks(store);
  const atomStateMap = buildingBlocks[0];
  const atomOnInit2 = buildingBlocks[9];
  if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && !atom) {
    throw new Error("Atom is undefined or null");
  }
  let atomState = atomStateMap.get(atom);
  if (!atomState) {
    atomState = { d: /* @__PURE__ */ new Map(), p: /* @__PURE__ */ new Set(), n: 0 };
    atomStateMap.set(atom, atomState);
    atomOnInit2 == null ? void 0 : atomOnInit2(store, atom);
  }
  return atomState;
};
const flushCallbacks = (store) => {
  const buildingBlocks = getInternalBuildingBlocks(store);
  const mountedMap = buildingBlocks[1];
  const changedAtoms = buildingBlocks[3];
  const mountCallbacks = buildingBlocks[4];
  const unmountCallbacks = buildingBlocks[5];
  const storeHooks = buildingBlocks[6];
  const recomputeInvalidatedAtoms2 = buildingBlocks[13];
  const errors = [];
  const call = (fn) => {
    try {
      fn();
    } catch (e) {
      errors.push(e);
    }
  };
  do {
    if (storeHooks.f) {
      call(storeHooks.f);
    }
    const callbacks = /* @__PURE__ */ new Set();
    const add = callbacks.add.bind(callbacks);
    changedAtoms.forEach((atom) => {
      var _a;
      return (_a = mountedMap.get(atom)) == null ? void 0 : _a.l.forEach(add);
    });
    changedAtoms.clear();
    unmountCallbacks.forEach(add);
    unmountCallbacks.clear();
    mountCallbacks.forEach(add);
    mountCallbacks.clear();
    callbacks.forEach(call);
    if (changedAtoms.size) {
      recomputeInvalidatedAtoms2(store);
    }
  } while (changedAtoms.size || unmountCallbacks.size || mountCallbacks.size);
  if (errors.length) {
    throw new AggregateError(errors);
  }
};
const recomputeInvalidatedAtoms = (store) => {
  const buildingBlocks = getInternalBuildingBlocks(store);
  const mountedMap = buildingBlocks[1];
  const invalidatedAtoms = buildingBlocks[2];
  const changedAtoms = buildingBlocks[3];
  const ensureAtomState2 = buildingBlocks[11];
  const readAtomState2 = buildingBlocks[14];
  const mountDependencies2 = buildingBlocks[17];
  const topSortedReversed = [];
  const visiting = /* @__PURE__ */ new WeakSet();
  const visited = /* @__PURE__ */ new WeakSet();
  const stack = Array.from(changedAtoms);
  while (stack.length) {
    const a = stack[stack.length - 1];
    const aState = ensureAtomState2(store, a);
    if (visited.has(a)) {
      stack.pop();
      continue;
    }
    if (visiting.has(a)) {
      if (invalidatedAtoms.get(a) === aState.n) {
        topSortedReversed.push([a, aState]);
      } else if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && invalidatedAtoms.has(a)) {
        throw new Error("[Bug] invalidated atom exists");
      }
      visited.add(a);
      stack.pop();
      continue;
    }
    visiting.add(a);
    for (const d of getMountedOrPendingDependents(a, aState, mountedMap)) {
      if (!visiting.has(d)) {
        stack.push(d);
      }
    }
  }
  for (let i = topSortedReversed.length - 1; i >= 0; --i) {
    const [a, aState] = topSortedReversed[i];
    let hasChangedDeps = false;
    for (const dep of aState.d.keys()) {
      if (dep !== a && changedAtoms.has(dep)) {
        hasChangedDeps = true;
        break;
      }
    }
    if (hasChangedDeps) {
      readAtomState2(store, a);
      mountDependencies2(store, a);
    }
    invalidatedAtoms.delete(a);
  }
};
const readAtomState = (store, atom) => {
  var _a, _b;
  const buildingBlocks = getInternalBuildingBlocks(store);
  const mountedMap = buildingBlocks[1];
  const invalidatedAtoms = buildingBlocks[2];
  const changedAtoms = buildingBlocks[3];
  const storeHooks = buildingBlocks[6];
  const atomRead2 = buildingBlocks[7];
  const ensureAtomState2 = buildingBlocks[11];
  const flushCallbacks2 = buildingBlocks[12];
  const recomputeInvalidatedAtoms2 = buildingBlocks[13];
  const readAtomState2 = buildingBlocks[14];
  const writeAtomState2 = buildingBlocks[16];
  const mountDependencies2 = buildingBlocks[17];
  const atomState = ensureAtomState2(store, atom);
  if (isAtomStateInitialized(atomState)) {
    if (mountedMap.has(atom) && invalidatedAtoms.get(atom) !== atomState.n) {
      return atomState;
    }
    if (Array.from(atomState.d).every(
      ([a, n]) => (
        // Recursively, read the atom state of the dependency, and
        // check if the atom epoch number is unchanged
        readAtomState2(store, a).n === n
      )
    )) {
      return atomState;
    }
  }
  atomState.d.clear();
  let isSync = true;
  function mountDependenciesIfAsync() {
    if (mountedMap.has(atom)) {
      mountDependencies2(store, atom);
      recomputeInvalidatedAtoms2(store);
      flushCallbacks2(store);
    }
  }
  function getter(a) {
    var _a2;
    if (a === atom) {
      const aState2 = ensureAtomState2(store, a);
      if (!isAtomStateInitialized(aState2)) {
        if (hasInitialValue(a)) {
          setAtomStateValueOrPromise(store, a, a.init);
        } else {
          throw new Error("no atom init");
        }
      }
      return returnAtomValue(aState2);
    }
    const aState = readAtomState2(store, a);
    try {
      return returnAtomValue(aState);
    } finally {
      atomState.d.set(a, aState.n);
      if (isPendingPromise(atomState.v)) {
        addPendingPromiseToDependency(atom, atomState.v, aState);
      }
      (_a2 = mountedMap.get(a)) == null ? void 0 : _a2.t.add(atom);
      if (!isSync) {
        mountDependenciesIfAsync();
      }
    }
  }
  let controller;
  let setSelf;
  const options = {
    get signal() {
      if (!controller) {
        controller = new AbortController();
      }
      return controller.signal;
    },
    get setSelf() {
      if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && !isActuallyWritableAtom(atom)) {
        console.warn("setSelf function cannot be used with read-only atom");
      }
      if (!setSelf && isActuallyWritableAtom(atom)) {
        setSelf = (...args) => {
          if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && isSync) {
            console.warn("setSelf function cannot be called in sync");
          }
          if (!isSync) {
            try {
              return writeAtomState2(store, atom, ...args);
            } finally {
              recomputeInvalidatedAtoms2(store);
              flushCallbacks2(store);
            }
          }
        };
      }
      return setSelf;
    }
  };
  const prevEpochNumber = atomState.n;
  try {
    const valueOrPromise = atomRead2(store, atom, getter, options);
    setAtomStateValueOrPromise(store, atom, valueOrPromise);
    if (isPromiseLike(valueOrPromise)) {
      registerAbortHandler(valueOrPromise, () => controller == null ? void 0 : controller.abort());
      valueOrPromise.then(mountDependenciesIfAsync, mountDependenciesIfAsync);
    }
    (_a = storeHooks.r) == null ? void 0 : _a.call(storeHooks, atom);
    return atomState;
  } catch (error) {
    delete atomState.v;
    atomState.e = error;
    ++atomState.n;
    return atomState;
  } finally {
    isSync = false;
    if (prevEpochNumber !== atomState.n && invalidatedAtoms.get(atom) === prevEpochNumber) {
      invalidatedAtoms.set(atom, atomState.n);
      changedAtoms.add(atom);
      (_b = storeHooks.c) == null ? void 0 : _b.call(storeHooks, atom);
    }
  }
};
const invalidateDependents = (store, atom) => {
  const buildingBlocks = getInternalBuildingBlocks(store);
  const mountedMap = buildingBlocks[1];
  const invalidatedAtoms = buildingBlocks[2];
  const ensureAtomState2 = buildingBlocks[11];
  const stack = [atom];
  while (stack.length) {
    const a = stack.pop();
    const aState = ensureAtomState2(store, a);
    for (const d of getMountedOrPendingDependents(a, aState, mountedMap)) {
      const dState = ensureAtomState2(store, d);
      invalidatedAtoms.set(d, dState.n);
      stack.push(d);
    }
  }
};
const writeAtomState = (store, atom, ...args) => {
  const buildingBlocks = getInternalBuildingBlocks(store);
  const changedAtoms = buildingBlocks[3];
  const storeHooks = buildingBlocks[6];
  const atomWrite2 = buildingBlocks[8];
  const ensureAtomState2 = buildingBlocks[11];
  const flushCallbacks2 = buildingBlocks[12];
  const recomputeInvalidatedAtoms2 = buildingBlocks[13];
  const readAtomState2 = buildingBlocks[14];
  const invalidateDependents2 = buildingBlocks[15];
  const mountDependencies2 = buildingBlocks[17];
  let isSync = true;
  const getter = (a) => returnAtomValue(readAtomState2(store, a));
  const setter = (a, ...args2) => {
    var _a;
    const aState = ensureAtomState2(store, a);
    try {
      if (a === atom) {
        if (!hasInitialValue(a)) {
          throw new Error("atom not writable");
        }
        const prevEpochNumber = aState.n;
        const v = args2[0];
        setAtomStateValueOrPromise(store, a, v);
        mountDependencies2(store, a);
        if (prevEpochNumber !== aState.n) {
          changedAtoms.add(a);
          (_a = storeHooks.c) == null ? void 0 : _a.call(storeHooks, a);
          invalidateDependents2(store, a);
        }
        return void 0;
      } else {
        return writeAtomState(store, a, ...args2);
      }
    } finally {
      if (!isSync) {
        recomputeInvalidatedAtoms2(store);
        flushCallbacks2(store);
      }
    }
  };
  try {
    return atomWrite2(store, atom, getter, setter, ...args);
  } finally {
    isSync = false;
  }
};
const mountDependencies = (store, atom) => {
  var _a;
  const buildingBlocks = getInternalBuildingBlocks(store);
  const mountedMap = buildingBlocks[1];
  const changedAtoms = buildingBlocks[3];
  const storeHooks = buildingBlocks[6];
  const ensureAtomState2 = buildingBlocks[11];
  const invalidateDependents2 = buildingBlocks[15];
  const mountAtom2 = buildingBlocks[18];
  const unmountAtom2 = buildingBlocks[19];
  const atomState = ensureAtomState2(store, atom);
  const mounted = mountedMap.get(atom);
  if (mounted && !isPendingPromise(atomState.v)) {
    for (const [a, n] of atomState.d) {
      if (!mounted.d.has(a)) {
        const aState = ensureAtomState2(store, a);
        const aMounted = mountAtom2(store, a);
        aMounted.t.add(atom);
        mounted.d.add(a);
        if (n !== aState.n) {
          changedAtoms.add(a);
          (_a = storeHooks.c) == null ? void 0 : _a.call(storeHooks, a);
          invalidateDependents2(store, a);
        }
      }
    }
    for (const a of mounted.d || []) {
      if (!atomState.d.has(a)) {
        mounted.d.delete(a);
        const aMounted = unmountAtom2(store, a);
        aMounted == null ? void 0 : aMounted.t.delete(atom);
      }
    }
  }
};
const mountAtom = (store, atom) => {
  var _a;
  const buildingBlocks = getInternalBuildingBlocks(store);
  const mountedMap = buildingBlocks[1];
  const mountCallbacks = buildingBlocks[4];
  const storeHooks = buildingBlocks[6];
  const atomOnMount2 = buildingBlocks[10];
  const ensureAtomState2 = buildingBlocks[11];
  const flushCallbacks2 = buildingBlocks[12];
  const recomputeInvalidatedAtoms2 = buildingBlocks[13];
  const readAtomState2 = buildingBlocks[14];
  const writeAtomState2 = buildingBlocks[16];
  const atomState = ensureAtomState2(store, atom);
  let mounted = mountedMap.get(atom);
  if (!mounted) {
    readAtomState2(store, atom);
    for (const a of atomState.d.keys()) {
      const aMounted = mountAtom(store, a);
      aMounted.t.add(atom);
    }
    mounted = {
      l: /* @__PURE__ */ new Set(),
      d: new Set(atomState.d.keys()),
      t: /* @__PURE__ */ new Set()
    };
    mountedMap.set(atom, mounted);
    (_a = storeHooks.m) == null ? void 0 : _a.call(storeHooks, atom);
    if (isActuallyWritableAtom(atom)) {
      const processOnMount = () => {
        let isSync = true;
        const setAtom = (...args) => {
          try {
            return writeAtomState2(store, atom, ...args);
          } finally {
            if (!isSync) {
              recomputeInvalidatedAtoms2(store);
              flushCallbacks2(store);
            }
          }
        };
        try {
          const onUnmount = atomOnMount2(store, atom, setAtom);
          if (onUnmount) {
            mounted.u = () => {
              isSync = true;
              try {
                onUnmount();
              } finally {
                isSync = false;
              }
            };
          }
        } finally {
          isSync = false;
        }
      };
      mountCallbacks.add(processOnMount);
    }
  }
  return mounted;
};
const unmountAtom = (store, atom) => {
  var _a;
  const buildingBlocks = getInternalBuildingBlocks(store);
  const mountedMap = buildingBlocks[1];
  const unmountCallbacks = buildingBlocks[5];
  const storeHooks = buildingBlocks[6];
  const ensureAtomState2 = buildingBlocks[11];
  const unmountAtom2 = buildingBlocks[19];
  const atomState = ensureAtomState2(store, atom);
  let mounted = mountedMap.get(atom);
  if (mounted && !mounted.l.size && !Array.from(mounted.t).some((a) => {
    var _a2;
    return (_a2 = mountedMap.get(a)) == null ? void 0 : _a2.d.has(atom);
  })) {
    if (mounted.u) {
      unmountCallbacks.add(mounted.u);
    }
    mounted = void 0;
    mountedMap.delete(atom);
    (_a = storeHooks.u) == null ? void 0 : _a.call(storeHooks, atom);
    for (const a of atomState.d.keys()) {
      const aMounted = unmountAtom2(store, a);
      aMounted == null ? void 0 : aMounted.t.delete(atom);
    }
    return void 0;
  }
  return mounted;
};
const setAtomStateValueOrPromise = (store, atom, valueOrPromise) => {
  const ensureAtomState2 = getInternalBuildingBlocks(store)[11];
  const atomState = ensureAtomState2(store, atom);
  const hasPrevValue = "v" in atomState;
  const prevValue = atomState.v;
  if (isPromiseLike(valueOrPromise)) {
    for (const a of atomState.d.keys()) {
      addPendingPromiseToDependency(
        atom,
        valueOrPromise,
        ensureAtomState2(store, a)
      );
    }
  }
  atomState.v = valueOrPromise;
  delete atomState.e;
  if (!hasPrevValue || !Object.is(prevValue, atomState.v)) {
    ++atomState.n;
    if (isPromiseLike(prevValue)) {
      abortPromise(prevValue);
    }
  }
};
const storeGet = (store, atom) => {
  const readAtomState2 = getInternalBuildingBlocks(store)[14];
  return returnAtomValue(readAtomState2(store, atom));
};
const storeSet = (store, atom, ...args) => {
  const buildingBlocks = getInternalBuildingBlocks(store);
  const flushCallbacks2 = buildingBlocks[12];
  const recomputeInvalidatedAtoms2 = buildingBlocks[13];
  const writeAtomState2 = buildingBlocks[16];
  try {
    return writeAtomState2(store, atom, ...args);
  } finally {
    recomputeInvalidatedAtoms2(store);
    flushCallbacks2(store);
  }
};
const storeSub = (store, atom, listener) => {
  const buildingBlocks = getInternalBuildingBlocks(store);
  const flushCallbacks2 = buildingBlocks[12];
  const mountAtom2 = buildingBlocks[18];
  const unmountAtom2 = buildingBlocks[19];
  const mounted = mountAtom2(store, atom);
  const listeners = mounted.l;
  listeners.add(listener);
  flushCallbacks2(store);
  return () => {
    listeners.delete(listener);
    unmountAtom2(store, atom);
    flushCallbacks2(store);
  };
};
const buildingBlockMap = /* @__PURE__ */ new WeakMap();
const getInternalBuildingBlocks = (store) => {
  const buildingBlocks = buildingBlockMap.get(store);
  if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && !buildingBlocks) {
    throw new Error(
      "Store must be created by buildStore to read its building blocks"
    );
  }
  return buildingBlocks;
};
function getBuildingBlocks(store) {
  const buildingBlocks = getInternalBuildingBlocks(store);
  const enhanceBuildingBlocks = buildingBlocks[24];
  if (enhanceBuildingBlocks) {
    return enhanceBuildingBlocks(buildingBlocks);
  }
  return buildingBlocks;
}
function buildStore(...buildArgs) {
  const store = {
    get(atom) {
      const storeGet2 = getInternalBuildingBlocks(store)[21];
      return storeGet2(store, atom);
    },
    set(atom, ...args) {
      const storeSet2 = getInternalBuildingBlocks(store)[22];
      return storeSet2(store, atom, ...args);
    },
    sub(atom, listener) {
      const storeSub2 = getInternalBuildingBlocks(store)[23];
      return storeSub2(store, atom, listener);
    }
  };
  const buildingBlocks = [
    // store state
    /* @__PURE__ */ new WeakMap(),
    // atomStateMap
    /* @__PURE__ */ new WeakMap(),
    // mountedMap
    /* @__PURE__ */ new WeakMap(),
    // invalidatedAtoms
    /* @__PURE__ */ new Set(),
    // changedAtoms
    /* @__PURE__ */ new Set(),
    // mountCallbacks
    /* @__PURE__ */ new Set(),
    // unmountCallbacks
    {},
    // storeHooks
    // atom interceptors
    atomRead,
    atomWrite,
    atomOnInit,
    atomOnMount,
    // building-block functions
    ensureAtomState,
    flushCallbacks,
    recomputeInvalidatedAtoms,
    readAtomState,
    invalidateDependents,
    writeAtomState,
    mountDependencies,
    mountAtom,
    unmountAtom,
    setAtomStateValueOrPromise,
    storeGet,
    storeSet,
    storeSub,
    void 0
  ].map((fn, i) => buildArgs[i] || fn);
  buildingBlockMap.set(store, Object.freeze(buildingBlocks));
  return store;
}

export { abortPromise as INTERNAL_abortPromise, addPendingPromiseToDependency as INTERNAL_addPendingPromiseToDependency, buildStore as INTERNAL_buildStoreRev2, getBuildingBlocks as INTERNAL_getBuildingBlocksRev2, getMountedOrPendingDependents as INTERNAL_getMountedOrPendingDependents, hasInitialValue as INTERNAL_hasInitialValue, initializeStoreHooks as INTERNAL_initializeStoreHooksRev2, isActuallyWritableAtom as INTERNAL_isActuallyWritableAtom, isAtomStateInitialized as INTERNAL_isAtomStateInitialized, isPendingPromise as INTERNAL_isPendingPromise, isPromiseLike as INTERNAL_isPromiseLike, promiseStateMap as INTERNAL_promiseStateMap, registerAbortHandler as INTERNAL_registerAbortHandler, returnAtomValue as INTERNAL_returnAtomValue };
