import { IsNever } from "../helpers/types.js";
import { StepOptionsOrId } from "../types.js";

//#region src/components/InngestGroupTools.d.ts

/**
 * Options for the `group.parallel()` helper.
 */
interface ParallelOptions {
  /**
   * The parallel mode to apply to all steps created within the callback.
   *
   * - `"race"`: Steps will be executed with race semantics, meaning the first
   *   step to complete will "win" and remaining steps may be cancelled.
   */
  mode?: "race";
}
/**
 * Configuration for how the experiment selects a variant.
 */
interface ExperimentStrategyConfig {
  strategy: string;
  weights?: Record<string, number>;
  nullishBucket?: boolean;
}
/**
 * A callable selection function that also carries strategy metadata.
 */
interface ExperimentSelectFn {
  (variantNames?: string[]): Promise<string> | string;
  __experimentConfig: ExperimentStrategyConfig;
}
/**
 * Options for `group.experiment()`.
 */
interface ExperimentOptions<TVariants extends Record<string, () => unknown>> {
  /**
   * A map of variant names to callbacks. The selected variant's callback will
   * be executed at the top level so that any `step.*` calls inside it go
   * through normal step discovery.
   */
  variants: TVariants;
  /**
   * A selection function that returns the name of the variant to execute.
   * The result is memoized via a step so the same variant is used on retries.
   */
  select: ExperimentSelectFn;
}
/**
 * Options for `group.experiment()` when `withVariant` is true, which causes
 * the return type to include both the result and the selected variant name.
 */
interface ExperimentOptionsWithVariant<TVariants extends Record<string, () => unknown>> extends ExperimentOptions<TVariants> {
  /**
   * When true, the return value includes the variant name alongside the result.
   */
  withVariant: true;
}
/**
 * Computes the return type of an experiment based on variant callbacks.
 *
 * When `TConstraint` is `never`, the return type is inferred as the union of
 * all variant callback return types. Otherwise `TConstraint` is used directly.
 */
type VariantResult<TConstraint, TVariants extends Record<string, () => unknown>> = IsNever<TConstraint> extends true ? Awaited<ReturnType<TVariants[keyof TVariants]>> : TConstraint;
/**
 * Overloaded interface for `group.experiment()`.
 */
interface GroupExperiment {
  /**
   * Run an A/B experiment that selects and executes a variant. Returns both
   * the result and the selected variant name.
   */
  <TVariants extends Record<string, () => unknown>>(idOrOptions: StepOptionsOrId, options: ExperimentOptionsWithVariant<TVariants>): Promise<{
    result: VariantResult<never, TVariants>;
    variant: string;
  }>;
  /**
   * Run an A/B experiment that selects and executes a variant. Returns only
   * the variant callback's result.
   */
  <TVariants extends Record<string, () => unknown>>(idOrOptions: StepOptionsOrId, options: ExperimentOptions<TVariants>): Promise<VariantResult<never, TVariants>>;
}
/**
 * Tools for grouping and coordinating steps.
 *
 * @public
 */
interface GroupTools {
  /**
   * Run a callback where all steps automatically receive a `parallelMode`
   * option, removing the need to tag each step individually. Defaults to
   * `"race"` mode.
   *
   * @example
   * ```ts
   * // Defaults to "race" mode
   * const winner = await group.parallel(async () => {
   *   return Promise.race([
   *     step.run("a", () => "a"),
   *     step.run("b", () => "b"),
   *     step.run("c", () => "c"),
   *   ]);
   * });
   *
   * // Or explicitly specify the mode
   * const winner = await group.parallel({ mode: "race" }, async () => {
   *   return Promise.race([
   *     step.run("a", () => "a"),
   *     step.run("b", () => "b"),
   *   ]);
   * });
   * ```
   */
  parallel: <T>(optionsOrCallback: ParallelOptions | (() => Promise<T>), maybeCallback?: () => Promise<T>) => Promise<T>;
  /**
   * Run an A/B experiment within a function. Selects a variant via a memoized
   * step, then executes the selected variant's callback at the top level so
   * its `step.*` calls go through normal step discovery.
   *
   * @example
   * ```ts
   * const result = await group.experiment("checkout-flow", {
   *   variants: {
   *     control: () => step.run("control-checkout", () => oldCheckout()),
   *     new_flow: () => step.run("new-checkout", () => newCheckout()),
   *   },
   *   select: Object.assign(() => "control", {
   *     __experimentConfig: { strategy: "weighted", weights: { control: 80, new_flow: 20 } },
   *   }),
   * });
   * ```
   */
  experiment: GroupExperiment;
}
/**
 * Dependencies injected into `createGroupTools` from the execution engine.
 */
interface GroupToolsDeps {
  /**
   * A `step.run` variant with `opts.type = "group.experiment"`, extracted from
   * step tools via the experiment symbol. Undefined when not available.
   */
  experimentStepRun?: (...args: any[]) => Promise<any>;
}
/**
 * Create the `group` tools object provided on the function execution context.
 *
 * @public
 */
declare const createGroupTools: (deps?: GroupToolsDeps) => GroupTools;
//#endregion
export { ExperimentSelectFn, GroupTools, GroupToolsDeps, createGroupTools };
//# sourceMappingURL=InngestGroupTools.d.ts.map