import { invariant } from "../../utilities/globals/index.js";
import * as React from "rehackt";
import { canUseLayoutEffect } from "../../utilities/index.js";
var didWarnUncachedGetSnapshot = false;
// Prevent webpack from complaining about our feature detection of the
// useSyncExternalStore property of the React namespace, which is expected not
// to exist when using React 17 and earlier, and that's fine.
var uSESKey = "useSyncExternalStore";
var realHook = React[uSESKey];
// Adapted from https://www.npmjs.com/package/use-sync-external-store, with
// Apollo Client deviations called out by "// DEVIATION ..." comments.
// When/if React.useSyncExternalStore is defined, delegate fully to it.
export var useSyncExternalStore = realHook ||
    (function (subscribe, getSnapshot, getServerSnapshot) {
        // Read the current snapshot from the store on every render. Again, this
        // breaks the rules of React, and only works here because of specific
        // implementation details, most importantly that updates are
        // always synchronous.
        var value = getSnapshot();
        if (
        // DEVIATION: Using __DEV__
        globalThis.__DEV__ !== false &&
            !didWarnUncachedGetSnapshot &&
            // DEVIATION: Not using Object.is because we know our snapshots will never
            // be exotic primitive values like NaN, which is !== itself.
            value !== getSnapshot()) {
            didWarnUncachedGetSnapshot = true;
            // DEVIATION: Using invariant.error instead of console.error directly.
            globalThis.__DEV__ !== false && invariant.error(58);
        }
        // Because updates are synchronous, we don't queue them. Instead we force a
        // re-render whenever the subscribed state changes by updating an some
        // arbitrary useState hook. Then, during render, we call getSnapshot to read
        // the current value.
        //
        // Because we don't actually use the state returned by the useState hook, we
        // can save a bit of memory by storing other stuff in that slot.
        //
        // To implement the early bailout, we need to track some things on a mutable
        // object. Usually, we would put that in a useRef hook, but we can stash it in
        // our useState hook instead.
        //
        // To force a re-render, we call forceUpdate({inst}). That works because the
        // new object always fails an equality check.
        var _a = React.useState({
            inst: { value: value, getSnapshot: getSnapshot },
        }), inst = _a[0].inst, forceUpdate = _a[1];
        // Track the latest getSnapshot function with a ref. This needs to be updated
        // in the layout phase so we can access it during the tearing check that
        // happens on subscribe.
        if (canUseLayoutEffect) {
            // DEVIATION: We avoid calling useLayoutEffect when !canUseLayoutEffect,
            // which may seem like a conditional hook, but this code ends up behaving
            // unconditionally (one way or the other) because canUseLayoutEffect is
            // constant.
            React.useLayoutEffect(function () {
                Object.assign(inst, { value: value, getSnapshot: getSnapshot });
                // Whenever getSnapshot or subscribe changes, we need to check in the
                // commit phase if there was an interleaved mutation. In concurrent mode
                // this can happen all the time, but even in synchronous mode, an earlier
                // effect may have mutated the store.
                if (checkIfSnapshotChanged(inst)) {
                    // Force a re-render.
                    forceUpdate({ inst: inst });
                }
            }, [subscribe, value, getSnapshot]);
        }
        else {
            Object.assign(inst, { value: value, getSnapshot: getSnapshot });
        }
        React.useEffect(function () {
            // Check for changes right before subscribing. Subsequent changes will be
            // detected in the subscription handler.
            if (checkIfSnapshotChanged(inst)) {
                // Force a re-render.
                forceUpdate({ inst: inst });
            }
            // Subscribe to the store and return a clean-up function.
            return subscribe(function handleStoreChange() {
                // TODO: Because there is no cross-renderer API for batching updates, it's
                // up to the consumer of this library to wrap their subscription event
                // with unstable_batchedUpdates. Should we try to detect when this isn't
                // the case and print a warning in development?
                // The store changed. Check if the snapshot changed since the last time we
                // read from the store.
                if (checkIfSnapshotChanged(inst)) {
                    // Force a re-render.
                    forceUpdate({ inst: inst });
                }
            });
        }, [subscribe]);
        return value;
    });
function checkIfSnapshotChanged(_a) {
    var value = _a.value, getSnapshot = _a.getSnapshot;
    try {
        return value !== getSnapshot();
    }
    catch (_b) {
        return true;
    }
}
//# sourceMappingURL=useSyncExternalStore.js.map