// ets_tracing: off

/**
 * inspired by https://github.com/tusharmath/qio/pull/22 (revised)
 */
import * as Tp from "../Collections/Immutable/Tuple";
import { ManagedImpl } from "../Managed/managed";
import { makeReleaseMap } from "../Managed/ReleaseMap/makeReleaseMap";
import { releaseAll } from "../Managed/ReleaseMap/releaseAll";
import * as Utils from "../Utils";
import { bracketExit_ } from "./bracketExit";
import { _A, _E, _R } from "./commons";
import { chain_, succeed, suspend, unit } from "./core";
import { sequential } from "./ExecutionStrategy";
import { fail } from "./fail";
import { fromEither } from "./fromEither";
import { getOrFail } from "./getOrFail";
import { service } from "./has";
import { map_ } from "./map";
import { provideSome_ } from "./provideSome";
export class GenEffect {
  constructor(effect, trace) {
    this.effect = effect;
    this.trace = trace;
  }

  *[Symbol.iterator]() {
    return yield this;
  }

}

function adapter(_, __, ___) {
  if (Utils.isEither(_)) {
    return new GenEffect(fromEither(() => _), __);
  }

  if (Utils.isOption(_)) {
    if (__ && typeof __ === "function") {
      return new GenEffect(_._tag === "None" ? fail(__()) : succeed(_.value), ___);
    }

    return new GenEffect(getOrFail(_), __);
  }

  if (Utils.isTag(_)) {
    return new GenEffect(service(_), __);
  }

  return new GenEffect(_, __);
}

export function genM(f, __trace) {
  return suspend(() => {
    const iterator = f(adapter);
    const state = iterator.next();

    function run(rm, state) {
      if (state.done) {
        return succeed(state.value);
      }

      return chain_(suspend(() => state.value.trace ? state.value["effect"] instanceof ManagedImpl ? map_(provideSome_(state.value["effect"]["effect"], r0 => Tp.tuple(r0, rm)), _ => _.get(1)) : state.value["effect"] : state.value["effect"] instanceof ManagedImpl ? map_(provideSome_(state.value["effect"]["effect"], r0 => Tp.tuple(r0, rm)), _ => _.get(1)) : state.value["effect"], state.value.trace), val => {
        const next = iterator.next(val);
        return run(rm, next);
      });
    }

    return chain_(makeReleaseMap, rm => bracketExit_(unit, () => run(rm, state), (_, e) => releaseAll(e, sequential)(rm)));
  }, __trace);
}
export function gen(f, __trace) {
  return suspend(() => {
    const iterator = f(adapter);
    const state = iterator.next();

    function run(state) {
      if (state.done) {
        return succeed(state.value);
      }

      return chain_(suspend(() => state.value["effect"], state.value.trace), val => run(iterator.next(val)));
    }

    return run(state);
  }, __trace);
}
//# sourceMappingURL=gen.js.map