import * as Debug from "@effect/data/Debug";
import { seconds } from "@effect/data/Duration";
import { globalValue } from "@effect/data/Global";
import * as BlockedRequests from "@effect/io/internal_effect_untraced/blockedRequests";
import { unsafeMakeWith } from "@effect/io/internal_effect_untraced/cache";
import { isInterruptedOnly } from "@effect/io/internal_effect_untraced/cause";
import * as core from "@effect/io/internal_effect_untraced/core";
import { currentRequestBatchingEnabled, ensuring } from "@effect/io/internal_effect_untraced/fiberRuntime";
import { Listeners } from "@effect/io/internal_effect_untraced/request";
/** @internal */
export const currentCache = /*#__PURE__*/core.fiberRefUnsafeMake( /*#__PURE__*/unsafeMakeWith(65536, () => core.map(core.deferredMake(), handle => ({
  listeners: new Listeners(),
  handle
})), () => seconds(60)));
/** @internal */
export const currentCacheEnabled = /*#__PURE__*/globalValue( /*#__PURE__*/Symbol.for("@effect/io/FiberRef/currentCacheEnabled"), () => core.fiberRefUnsafeMake(false));
/** @internal */
export const fromRequest = /*#__PURE__*/Debug.methodWithTrace(trace => (request, dataSource) => {
  // @ts-expect-error
  return core.flatMap(core.isEffect(dataSource) ? dataSource : core.succeed(dataSource), ds => core.fiberIdWith(id => {
    const proxy = new Proxy(request, {});
    return core.fiberRefGetWith(currentCacheEnabled, cacheEnabled => {
      if (cacheEnabled) {
        return core.fiberRefGetWith(currentCache, cache => core.flatMap(cache.getEither(proxy), orNew => {
          switch (orNew._tag) {
            case "Left":
              {
                orNew.left.listeners.increment();
                return core.blocked(BlockedRequests.empty, core.flatMap(core.exit(core.deferredAwait(orNew.left.handle)), exit => {
                  if (exit._tag === "Failure" && isInterruptedOnly(exit.cause)) {
                    orNew.left.listeners.decrement();
                    return core.flatMap(cache.invalidateWhen(proxy, entry => entry.handle === orNew.left.handle), () => fromRequest(proxy, dataSource));
                  }
                  return ensuring(core.deferredAwait(orNew.left.handle), core.sync(() => orNew.left.listeners.decrement()));
                }));
              }
            case "Right":
              {
                orNew.right.listeners.increment();
                return core.blocked(BlockedRequests.single(ds, BlockedRequests.makeEntry(proxy, orNew.right.handle, orNew.right.listeners, id, {
                  completed: false
                })), core.uninterruptibleMask(restore => core.flatMap(core.exit(restore(core.deferredAwait(orNew.right.handle))), exit => {
                  orNew.right.listeners.decrement();
                  return exit;
                })));
              }
          }
        }));
      }
      const listeners = new Listeners();
      listeners.increment();
      return core.flatMap(core.deferredMake(), ref => core.blocked(BlockedRequests.single(ds, BlockedRequests.makeEntry(proxy, ref, listeners, id, {
        completed: false
      })), ensuring(core.deferredAwait(ref), core.sync(() => listeners.decrement()))));
    });
  })).traced(trace);
});
/** @internal */
export const cacheRequest = /*#__PURE__*/Debug.methodWithTrace(trace => (request, result) => {
  return core.fiberRefGetWith(currentCacheEnabled, cacheEnabled => {
    if (cacheEnabled) {
      return core.fiberRefGetWith(currentCache, cache => core.flatMap(cache.getEither(request), orNew => {
        switch (orNew._tag) {
          case "Left":
            {
              return core.unit();
            }
          case "Right":
            {
              return core.deferredComplete(orNew.right.handle, result);
            }
        }
      }));
    }
    return core.unit();
  }).traced(trace);
});
/** @internal */
export const withRequestBatching = /*#__PURE__*/Debug.dualWithTrace(2, trace => (self, strategy) => core.fiberRefGetWith(currentRequestBatchingEnabled, enabled => {
  switch (strategy) {
    case "off":
      return enabled ? core.fiberRefLocally(self, currentRequestBatchingEnabled, false) : self;
    case "on":
      return enabled ? self : core.fiberRefLocally(self, currentRequestBatchingEnabled, true);
  }
}).traced(trace));
/** @internal */
export const withRequestCaching = /*#__PURE__*/Debug.dualWithTrace(2, trace => (self, strategy) => core.fiberRefGetWith(currentCacheEnabled, enabled => {
  switch (strategy) {
    case "off":
      return enabled ? core.fiberRefLocally(self, currentCacheEnabled, false) : self;
    case "on":
      return enabled ? self : core.fiberRefLocally(self, currentCacheEnabled, true);
  }
}).traced(trace));
/** @internal */
export const withRequestCache = /*#__PURE__*/Debug.dualWithTrace(2,
// @ts-expect-error
trace => (self, cache) => core.fiberRefLocally(self, currentCache, cache).traced(trace));
//# sourceMappingURL=query.mjs.map