/**
 * @since 4.0.0
 */
import * as Arr from "../../Array.js";
import * as Cause from "../../Cause.js";
import * as Context from "../../Context.js";
import * as Effect from "../../Effect.js";
import * as Encoding from "../../Encoding.js";
import * as Exit from "../../Exit.js";
import * as Filter from "../../Filter.js";
import { dual } from "../../Function.js";
import * as Option from "../../Option.js";
import * as Schema from "../../Schema.js";
import * as Getter from "../../SchemaGetter.js";
import * as Workflow from "./Workflow.js";
const TypeId = "~effect/workflow/DurableDeferred";
/**
 * @since 4.0.0
 * @category Constructors
 */
export const make = (name, options) => {
  const successSchema = options?.success ?? Schema.Void;
  const errorSchema = options?.error ?? Schema.Never;
  return {
    [TypeId]: TypeId,
    name,
    successSchema,
    errorSchema,
    exitSchema: Schema.Exit(Schema.toCodecJson(successSchema), Schema.toCodecJson(errorSchema), Schema.toCodecJson(Schema.Defect)),
    withActivityAttempt: Effect.gen(function* () {
      const attempt = yield* CurrentAttempt;
      return make(`${name}/${attempt}`, {
        success: successSchema,
        error: errorSchema
      });
    })
  };
};
const EngineTag = /*#__PURE__*/Context.Service("effect/workflow/WorkflowEngine");
const InstanceTag = /*#__PURE__*/Context.Service("effect/workflow/WorkflowEngine/WorkflowInstance");
const CurrentAttempt = /*#__PURE__*/Context.Reference("effect/workflow/Activity/CurrentAttempt", {
  defaultValue: () => 1
});
const await_ = /*#__PURE__*/Effect.fnUntraced(function* (self) {
  const engine = yield* EngineTag;
  const instance = yield* InstanceTag;
  const exit = yield* Workflow.wrapActivityResult(engine.deferredResult(self), Option.isNone);
  if (Option.isNone(exit)) {
    return yield* Workflow.suspend(instance);
  }
  return yield* exit.value;
});
export {
/**
 * @since 4.0.0
 * @category Combinators
 */
await_ as await };
/**
 * @since 4.0.0
 * @category Combinators
 */
export const into = /*#__PURE__*/dual(2, (effect, self) => Effect.contextWith(context => {
  const engine = Context.get(context, EngineTag);
  const parentInstance = Context.get(context, InstanceTag);
  const instance = {
    ...parentInstance
  };
  return Effect.onExit(Effect.provideService(effect, InstanceTag, instance), Effect.fnUntraced(function* (exit) {
    if (Exit.isFailure(exit)) {
      const [reasons, interrupts] = Arr.partition(exit.cause.reasons, Filter.fromPredicate(Cause.isInterruptReason));
      const hasInterruptsOnly = interrupts.length === exit.cause.reasons.length;
      if (hasInterruptsOnly && instance.suspended) {
        parentInstance.suspended = true;
        return;
      } else if (interrupts.length > 0) {
        exit = Exit.failCause(Cause.fromReasons(reasons));
      }
    }
    yield* engine.deferredDone(self, {
      workflowName: instance.workflow.name,
      executionId: instance.executionId,
      deferredName: self.name,
      exit
    });
  }));
}));
/**
 * @since 4.0.0
 * @category Racing
 */
export const raceAll = options => {
  const deferred = make(`raceAll/${options.name}`, {
    success: options.success,
    error: options.error
  });
  return Effect.gen(function* () {
    const engine = yield* EngineTag;
    const exit = yield* engine.deferredResult(deferred);
    if (Option.isSome(exit)) {
      return yield* Effect.flatten(exit.value);
    }
    return yield* into(Effect.raceAll(options.effects), deferred);
  });
};
/**
 * @since 4.0.0
 */
export const TokenTypeId = "~effect/workflow/DurableDeferred/Token";
/**
 * @since 4.0.0
 * @category Token
 */
export const Token = /*#__PURE__*/Schema.String.pipe(/*#__PURE__*/Schema.brand(TokenTypeId));
/**
 * @since 4.0.0
 * @category Token
 */
export class TokenParsed extends /*#__PURE__*/Schema.Class("effect/workflow/DurableDeferred/TokenParsed")({
  workflowName: Schema.String,
  executionId: Schema.String,
  deferredName: Schema.String
}) {
  /**
   * @since 4.0.0
   */
  get asToken() {
    return Encoding.encodeBase64Url(JSON.stringify([this.workflowName, this.executionId, this.deferredName]));
  }
  /**
   * @since 4.0.0
   */
  static FromString = /*#__PURE__*/Schema.String.pipe(/*#__PURE__*/Schema.decodeTo(/*#__PURE__*/Schema.fromJsonString(/*#__PURE__*/Schema.Tuple([Schema.String, Schema.String, Schema.String])), {
    decode: /*#__PURE__*/Getter.decodeBase64UrlString(),
    encode: /*#__PURE__*/Getter.encodeBase64Url()
  }), /*#__PURE__*/Schema.decodeTo(TokenParsed, {
    decode: /*#__PURE__*/Getter.transform(([workflowName, executionId, deferredName]) => new TokenParsed({
      workflowName,
      executionId,
      deferredName
    })),
    encode: /*#__PURE__*/Getter.transform(parsed => [parsed.workflowName, parsed.executionId, parsed.deferredName])
  }));
  /**
   * @since 4.0.0
   */
  static fromString = /*#__PURE__*/Schema.decodeSync(TokenParsed.FromString);
  /**
   * @since 4.0.0
   */
  static encode = /*#__PURE__*/Schema.encodeSync(TokenParsed.FromString);
}
/**
 * @since 4.0.0
 * @category Token
 */
export const token = /*#__PURE__*/Effect.fnUntraced(function* (self) {
  const instance = yield* InstanceTag;
  return tokenFromExecutionId(self, instance);
});
/**
 * @since 4.0.0
 * @category Token
 */
export const tokenFromExecutionId = /*#__PURE__*/dual(2, (self, options) => new TokenParsed({
  workflowName: options.workflow.name,
  executionId: options.executionId,
  deferredName: self.name
}).asToken);
/**
 * @since 4.0.0
 * @category Token
 */
export const tokenFromPayload = /*#__PURE__*/dual(2, (self, options) => Effect.map(options.workflow.executionId(options.payload), executionId => tokenFromExecutionId(self, {
  workflow: options.workflow,
  executionId
})));
/**
 * @since 4.0.0
 * @category Combinators
 */
export const done = /*#__PURE__*/dual(2, /*#__PURE__*/Effect.fnUntraced(function* (self, options) {
  const engine = yield* EngineTag;
  const token = TokenParsed.fromString(options.token);
  yield* engine.deferredDone(self, {
    workflowName: token.workflowName,
    executionId: token.executionId,
    deferredName: token.deferredName,
    exit: options.exit
  });
}));
/**
 * @since 4.0.0
 * @category Combinators
 */
export const succeed = /*#__PURE__*/dual(2, (self, options) => done(self, {
  token: options.token,
  exit: Exit.succeed(options.value)
}));
/**
 * @since 4.0.0
 * @category Combinators
 */
export const fail = /*#__PURE__*/dual(2, (self, options) => done(self, {
  token: options.token,
  exit: Exit.fail(options.error)
}));
/**
 * @since 4.0.0
 * @category Combinators
 */
export const failCause = /*#__PURE__*/dual(2, (self, options) => done(self, {
  token: options.token,
  exit: Exit.failCause(options.cause)
}));
//# sourceMappingURL=DurableDeferred.js.map