import * as tsplus_module_1 from "@effect/core/stream/Channel/operations/pipeTo";
import * as tsplus_module_2 from "@effect/core/io/Clock/operations/currentTime";
import * as tsplus_module_3 from "@effect/core/stream/Channel/operations/fromEffect";
import * as tsplus_module_4 from "@effect/core/stream/Channel/operations/succeed";
import * as tsplus_module_5 from "@effect/core/stream/Channel/operations/zip";
import * as tsplus_module_6 from "@effect/core/stream/Channel/operations/flatMap";
import * as tsplus_module_7 from "@tsplus/stdlib/data/Duration";
import * as tsplus_module_8 from "@effect/core/io/Clock/operations/sleep";
import * as tsplus_module_9 from "@effect/core/stream/Channel/operations/write";
import * as tsplus_module_10 from "@effect/core/stream/Channel/operations/zipRight";
import * as tsplus_module_11 from "@effect/core/io/Effect/operations/zip";
import * as tsplus_module_12 from "@effect/core/io/Effect/operations/map";
import * as tsplus_module_13 from "@effect/core/stream/Channel/operations/unwrap";
import * as tsplus_module_14 from "@effect/core/stream/Channel/operations/fail";
import * as tsplus_module_15 from "@effect/core/stream/Channel/operations/unit";
import * as tsplus_module_16 from "@effect/core/stream/Channel/operations/readWith";
import { concreteStream, StreamInternal } from "@effect/core/stream/Stream/operations/_internal/StreamInternal";
/**
 * Delays the chunks of this stream according to the given bandwidth
 * parameters using the token bucket algorithm. Allows for burst in the
 * processing of elements by allowing the token bucket to accumulate tokens up
 * to a `units + burst` threshold. The weight of each chunk is determined by
 * the `costFn` effectful function.
 *
 * @tsplus fluent ets/Stream throttleShapeEffect
 */

export function throttleShapeEffect_(self, units, duration, costFn, burst = 0, __tsplusTrace) {
  void 0;
  return new StreamInternal(tsplus_module_6.flatMap_(tsplus_module_5.zip_(tsplus_module_4.succeed(duration), () => tsplus_module_3.fromEffect(() => tsplus_module_2.currentTime)), ({
    tuple: [duration, timestamp]
  }) => tsplus_module_1.pipeTo_(self.channel, () => loop(units, duration, costFn, burst, units, timestamp, __tsplusTrace))));
}
/**
 * Delays the chunks of this stream according to the given bandwidth
 * parameters using the token bucket algorithm. Allows for burst in the
 * processing of elements by allowing the token bucket to accumulate tokens up
 * to a `units + burst` threshold. The weight of each chunk is determined by
 * the `costFn` effectful function.
 *
 * @tsplus static ets/Stream/Aspects throttleShapeEffect
 */

export const throttleShapeEffect = (units, duration, costFn, burst = 0, __tsplusTrace) => self => throttleShapeEffect_(self, units, duration, costFn, burst, __tsplusTrace);

function loop(units, duration, costFn, burst, tokens, timestamp, __tsplusTrace) {
  return tsplus_module_16.readWith(input => tsplus_module_13.unwrap(() => tsplus_module_12.map_(tsplus_module_11.zip_(costFn(input), () => tsplus_module_2.currentTime, __tsplusTrace), ({
    tuple: [weight, current]
  }) => {
    const elapsed = current - timestamp;
    const cycles = elapsed / duration.millis;
    const sum = tokens + cycles * units;
    const max = units + burst < 0 ? Number.MAX_SAFE_INTEGER : units + burst;
    const available = sum < 0 ? max : Math.min(sum, max);
    const remaining = available - weight;
    const waitCycles = remaining >= 0 ? 0 : -remaining / units;
    const delay = new tsplus_module_7.Duration(Math.floor(waitCycles * duration.millis));
    return tsplus_module_7.greaterThen_(delay, tsplus_module_7.millis(0)) ? tsplus_module_10.zipRight_(tsplus_module_10.zipRight_(tsplus_module_3.fromEffect(() => tsplus_module_8.sleep(() => delay, __tsplusTrace)), () => tsplus_module_9.write(() => input)), () => loop(units, duration, costFn, burst, remaining, current, __tsplusTrace)) : tsplus_module_10.zipRight_(tsplus_module_9.write(() => input), () => loop(units, duration, costFn, burst, remaining, current, __tsplusTrace));
  }, __tsplusTrace)), err => tsplus_module_14.fail(() => err), () => tsplus_module_15.unit);
}
//# sourceMappingURL=throttleShapeEffect.mjs.map