// tracing: off
import * as L from "../../Collections/Immutable/List"
import { NoSuchElementException, PrematureGeneratorExit } from "../../GlobalExceptions"
import { isEither, isOption, isTag } from "../../Utils"
import * as T from "../_internal/effect"
import { _A, _E, _R } from "../_internal/effect"
import { chain_ } from "./chain"
import { Stream } from "./definitions"
import { fail } from "./fail"
import { fromEffect } from "./fromEffect"
import { succeed } from "./succeed"
import { suspend } from "./suspend"
export class GenStream {
  constructor(effect) {
    this.effect = effect
  }

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

const adapter = (_, __) => {
  return new GenStream(() => {
    const x = _()

    if (isOption(x)) {
      return x._tag === "None"
        ? fail(__ ? __() : new NoSuchElementException())
        : succeed(x.value)
    } else if (isEither(x)) {
      return fromEffect(T.fromEither(() => x))
    } else if (x instanceof Stream) {
      return x
    } else if (isTag(x)) {
      return fromEffect(T.service(x))
    }

    return fromEffect(x)
  })
}

export function gen(...args) {
  function gen_(f) {
    return suspend(() => {
      function run(replayStack) {
        const iterator = f(adapter)
        let state = iterator.next()

        for (const a of replayStack) {
          if (state.done) {
            return fromEffect(T.die(new PrematureGeneratorExit()))
          }

          state = iterator.next(a)
        }

        if (state.done) {
          return succeed(state.value)
        }

        return chain_(state.value["effect"](), (val) => {
          return run(L.append_(replayStack, val))
        })
      }

      return run(L.empty())
    })
  }

  if (args.length === 0) {
    return (f) => gen_(f)
  }

  return gen_(args[0])
}
//# sourceMappingURL=gen.js.map
