/**
 * @since 1.0.0
 */
import { globalValue } from "@effect/data/Global";
/**
 * @since 1.0.0
 * @category schedulers
 */
export class MixedScheduler {
  constructor(
  /**
   * @since 1.0.0
   */
  maxNextTickBeforeTimer) {
    this.maxNextTickBeforeTimer = maxNextTickBeforeTimer;
    /**
     * @since 1.0.0
     */
    this.running = false;
    /**
     * @since 1.0.0
     */
    this.tasks = [];
  }
  /**
   * @since 1.0.0
   */
  starveInternal(depth) {
    const toRun = this.tasks;
    this.tasks = [];
    for (let i = 0; i < toRun.length; i++) {
      toRun[i]();
    }
    if (this.tasks.length === 0) {
      this.running = false;
    } else {
      this.starve(depth);
    }
  }
  /**
   * @since 1.0.0
   */
  starve(depth = 0) {
    if (depth >= this.maxNextTickBeforeTimer) {
      setTimeout(() => this.starveInternal(0), 0);
    } else {
      Promise.resolve(void 0).then(() => this.starveInternal(depth + 1));
    }
  }
  /**
   * @since 1.0.0
   */
  scheduleTask(task) {
    this.tasks.push(task);
    if (!this.running) {
      this.running = true;
      this.starve();
    }
  }
}
/**
 * @since 1.0.0
 * @category schedulers
 */
export const defaultScheduler = /*#__PURE__*/globalValue( /*#__PURE__*/Symbol.for("@effect/io/Scheduler/defaultScheduler"), () => new MixedScheduler(2048));
/**
 * @since 1.0.0
 * @category schedulers
 */
export class SyncScheduler {
  constructor() {
    /**
     * @since 1.0.0
     */
    this.tasks = [];
    /**
     * @since 1.0.0
     */
    this.deferred = false;
  }
  /**
   * @since 1.0.0
   */
  scheduleTask(task) {
    if (this.deferred) {
      defaultScheduler.scheduleTask(task);
    } else {
      this.tasks.push(task);
    }
  }
  /**
   * @since 1.0.0
   */
  flush() {
    while (this.tasks.length > 0) {
      const toRun = this.tasks;
      this.tasks = [];
      for (let i = 0; i < toRun.length; i++) {
        toRun[i]();
      }
    }
    this.deferred = true;
  }
}
/**
 * @since 1.0.0
 * @category schedulers
 */
export class ControlledScheduler {
  constructor() {
    /**
     * @since 1.0.0
     */
    this.tasks = [];
    /**
     * @since 1.0.0
     */
    this.deferred = false;
  }
  /**
   * @since 1.0.0
   */
  scheduleTask(task) {
    if (this.deferred) {
      defaultScheduler.scheduleTask(task);
    } else {
      this.tasks.push(task);
    }
  }
  /**
   * @since 1.0.0
   */
  step() {
    const toRun = this.tasks;
    this.tasks = [];
    for (let i = 0; i < toRun.length; i++) {
      toRun[i]();
    }
  }
}
/**
 * @since 1.0.0
 * @category schedulers
 */
export const timeBased = {
  scheduleTask(task) {
    setTimeout(() => {
      task();
    }, 0);
  }
};
//# sourceMappingURL=Scheduler.mjs.map