import { AsTuple } from "../../helpers/types.js";
import { createGroupTools } from "../InngestGroupTools.js";
import { EventType, EventTypeWithAnySchema } from "./triggers.js";
import { DeferFn } from "../../types.js";
import { StandardSchemaV1 } from "@standard-schema/spec";

//#region src/components/triggers/typeHelpers.d.ts
type BasicDataUnknown = Record<string, unknown>;
type BasicDataAny = Record<string, any>;
type InvokeEventName = "inngest/function.invoked";
type CronEventName = "inngest/scheduled.timer";
type CronEventData = {
  cron: string;
};
/**
 * Detects if a string type contains a wildcard character (*).
 */
type ContainsWildcard<T extends string> = T extends `${string}*${string}` ? true : false;
/**
 * Converts wildcard event names to `unknown`, preserving literal names.
 */
type WildcardToUnknown<T extends string> = ContainsWildcard<T> extends true ? unknown : T;
/**
 * Represents the structure of an event as received by function handlers.
 *
 * This is the runtime event shape that your function receives when triggered.
 *
 * @template TName - The event name as a string literal type
 * @template TData - The event data object type
 */
type ReceivedEvent<TName, TData extends BasicDataUnknown> = {
  data: TData;
  id: string;
  name: TName;
  ts: number;
  v: string;
};
/**
 * Recursively checks if a trigger array contains an invoke trigger.
 *
 * This type is used to determine whether to add "inngest/function.invoked"
 * event to the received events tuple.
 *
 * @template T - Array of trigger definitions to check
 * @returns `true` if array contains an invoke trigger, `false` otherwise
 */
type HasInvokeTrigger<T extends readonly any[]> = T extends readonly [infer First, ...infer Rest] ? First extends EventTypeWithAnySchema<InvokeEventName> ? true : HasInvokeTrigger<Rest> : false;
/**
 * Converts an EventType instance to a ReceivedEvent type.
 *
 * Extracts the event name and schema from EventType and transforms it into
 * the ReceivedEvent shape that function handlers receive.
 *
 * @template TEventType - The EventType instance to convert
 * @returns ReceivedEvent type with extracted name and data
 */
type EventTypeToEvent<TEventType> = TEventType extends EventType<infer TName, infer TSchema> ? TSchema extends StandardSchemaV1<infer TData extends BasicDataUnknown> ? ReceivedEvent<WildcardToUnknown<TName>, TData> : ReceivedEvent<WildcardToUnknown<TName>, BasicDataAny> : never;
/**
 * Converts a plain event object trigger to a ReceivedEvent type.
 *
 * Handles triggers like `{ event: "my-event", schema?: z.object(...) }`.
 *
 * @template TName - Event name
 * @template TSchema - Optional schema type
 * @returns ReceivedEvent with typed data from schema, or Record<string, any> if no schema
 */
type PlainEventToReceivedEvent<TName extends string, TSchema> = TSchema extends StandardSchemaV1<infer TData extends BasicDataUnknown> ? ReceivedEvent<WildcardToUnknown<TName>, TData> : ReceivedEvent<WildcardToUnknown<TName>, BasicDataAny>;
/**
 * Processes a single trigger and converts it to ReceivedEvent(s).
 *
 * @template TTrigger - The trigger to process
 * @template TSeenCron - Whether we've already seen a cron trigger
 * @returns Tuple of ReceivedEvent(s), or empty array if trigger should be skipped
 */
type ProcessSingleTrigger<TTrigger, TSeenCron extends boolean> = TTrigger extends EventTypeWithAnySchema<InvokeEventName> ? [] : TTrigger extends EventTypeWithAnySchema<string> ? [EventTypeToEvent<TTrigger>] : TTrigger extends {
  cron: string;
} ? TSeenCron extends true ? [] : [ReceivedEvent<CronEventName, CronEventData>] : TTrigger extends {
  event: EventType<infer TName, infer TSchema>;
  if?: string;
} ? [TSchema extends StandardSchemaV1<infer TData extends BasicDataUnknown> ? ReceivedEvent<WildcardToUnknown<TName>, TData> : ReceivedEvent<WildcardToUnknown<TName>, BasicDataAny>] : TTrigger extends {
  event: infer TName extends string;
  schema?: infer TSchema;
} ? [PlainEventToReceivedEvent<TName, TSchema>] : [];
/**
 * Recursively processes trigger array, converting to event types while tracking
 * crons.
 *
 * This type iterates through a trigger array, converting each trigger to its
 * corresponding ReceivedEvent type. It handles:
 * - EventType instances → ReceivedEvent with typed data
 * - Cron triggers → "inngest/scheduled.timer" event (merged if multiple)
 * - Plain event objects → ReceivedEvent with typed or untyped data
 * - Invoke triggers → skipped (handled by ToReceivedEvent)
 *
 * @template T - Array of trigger definitions to process
 * @template SeenCron - Tracks whether we've already encountered a cron trigger
 *
 * @remarks
 * Multiple cron triggers are merged into a single "inngest/scheduled.timer" event.
 */
type TriggersToEventsWithCron<T extends readonly any[], SeenCron extends boolean = false> = T extends readonly [infer First, ...infer Rest] ? [...ProcessSingleTrigger<First, SeenCron>, ...TriggersToEventsWithCron<Rest, First extends {
  cron: string;
} ? true : SeenCron>] : [];
/**
 * Alias for TriggersToEventsWithCron that processes all non-invoke triggers.
 *
 * Despite the name "Filter", this type actually:
 * 1. Converts event triggers to ReceivedEvent types
 * 2. Converts cron triggers to "inngest/scheduled.timer" events
 * 3. Merges multiple cron triggers into one
 * 4. Preserves the order of non-invoke triggers
 *
 * @template T - Array of trigger definitions to process
 */
type FilterNonInvokeTriggers<T extends readonly any[]> = TriggersToEventsWithCron<T>;
/**
 * Extracts and builds a union of schema output types from invoke triggers.
 *
 * This recursively processes the trigger array and accumulates the output types
 * from all invoke trigger schemas (those with event: "inngest/function.invoked")
 * into a union type.
 *
 * @template T - Array of trigger definitions to process
 * @returns Union of all invoke trigger schema output types, or `never` if none found
 */
type ExtractInvokeSchemas<T extends readonly any[]> = T extends readonly [infer First, ...infer Rest] ? First extends EventType<InvokeEventName, infer TSchema> ? TSchema extends StandardSchemaV1<infer TData> ? TData | ExtractInvokeSchemas<Rest> : ExtractInvokeSchemas<Rest> : ExtractInvokeSchemas<Rest> : never;
/**
 * Extracts and builds a union of all data types from all trigger schemas.
 *
 * Unlike ExtractInvokeSchemas which only processes invoke triggers, this type
 * processes ALL triggers (event and invoke triggers) and builds a union of
 * their data types. For event triggers without schemas, it returns Record<string, any>.
 *
 * @template T - Array of trigger definitions to process
 * @returns Union of all trigger data types, or `never` if none found
 */
type ExtractAllSchemaOutputs<T extends readonly any[]> = T extends readonly [infer First, ...infer Rest] ? First extends EventType<string, infer TSchema> ? TSchema extends StandardSchemaV1<infer TData> ? TData | ExtractAllSchemaOutputs<Rest> : BasicDataAny | ExtractAllSchemaOutputs<Rest> : First extends {
  event: EventType<string, infer TSchema>;
} ? TSchema extends StandardSchemaV1<infer TData> ? TData | ExtractAllSchemaOutputs<Rest> : BasicDataAny | ExtractAllSchemaOutputs<Rest> : First extends {
  event: string;
  schema: StandardSchemaV1<infer TData>;
} ? TData | ExtractAllSchemaOutputs<Rest> : First extends {
  event: string;
} ? BasicDataAny | ExtractAllSchemaOutputs<Rest> : ExtractAllSchemaOutputs<Rest> : never;
/**
 * Converts `never` type to empty object `{}` for data types.
 *
 * This utility is used to ensure that when no schemas are found, the data type
 * becomes `{}` instead of `never`, which provides better TypeScript error
 * messages and autocomplete.
 *
 * @template T - Type to check and potentially convert
 * @returns `{}` if T is `never`, otherwise returns T unchanged
 */
type NeverToEmpty<T> = [T] extends [never] ? {} : T;
/**
 * Converts a trigger array to a tuple of ReceivedEvent types.
 *
 * This type transforms trigger definitions into the event types that a function
 * handler will receive. It always includes an invoke event type because
 * functions can be invoked directly regardless of their declared triggers.
 *
 * When invoke triggers are present, it uses their schemas for the invoke event
 * data. Otherwise, it derives the invoke event data type from all trigger
 * schemas.
 *
 * @template T - Array of trigger definitions to process
 */
type ToReceivedEvent<T extends readonly any[]> = HasInvokeTrigger<T> extends true ? [...FilterNonInvokeTriggers<T>, ReceivedEvent<InvokeEventName, NeverToEmpty<ExtractInvokeSchemas<T>>>] : [...TriggersToEventsWithCron<T>, ReceivedEvent<InvokeEventName, NeverToEmpty<ExtractAllSchemaOutputs<T>>>];
/**
 * Converts a tuple of ReceivedEvent types to a union.
 * @internal
 */
type ReceivedEventTupleToUnion<T extends readonly any[]> = T[number];
/**
 * Base context object for handlers using the new trigger-based event typing.
 * This uses ToReceivedEvent to derive event types directly from triggers
 * rather than looking up from the client's event registry.
 *
 * @template TStepTools - The step tools type for this context
 * @template TTriggers - Array of trigger definitions
 * @internal
 */
type BaseContextWithTriggers<TStepTools, TTriggers extends readonly any[]> = {
  defer: DeferFn;
  /**
   * The event data present in the payload.
   */
  event: ReceivedEventTupleToUnion<ToReceivedEvent<TTriggers>>;
  events: AsTuple<ReceivedEventTupleToUnion<ToReceivedEvent<TTriggers>>>;
  /**
   * The run ID for the current function execution
   */
  runId: string;
  /**
   * The request ID for this individual outbound SDK invocation, if provided by
   * the executor.
   */
  requestId?: string;
  /**
   * The stable job ID for this invocation, if provided by the executor.
   */
  jobId?: string;
  step: TStepTools;
  /**
   * Tools for grouping and coordinating steps.
   */
  group: ReturnType<typeof createGroupTools>;
  /**
   * The current zero-indexed attempt number for this function execution.
   */
  attempt: number;
  /**
   * The maximum number of attempts allowed for this function.
   */
  maxAttempts?: number;
};
/**
 * Context object for handlers using trigger-based event typing with middleware overrides.
 *
 * @template TStepTools - The step tools type for this context
 * @template TTriggers - Array of trigger definitions
 * @template TOverrides - Properties to override from middleware
 * @internal
 */
type ContextWithTriggers<TStepTools, TTriggers extends readonly any[], TOverrides extends BasicDataUnknown = Record<never, never>> = Omit<BaseContextWithTriggers<TStepTools, TTriggers>, keyof TOverrides> & TOverrides;
/**
 * A handler type that computes its event type from a trigger array using ToReceivedEvent.
 * This provides proper typing for EventType instances and schema-bearing triggers.
 *
 * @template TStepTools - The step tools type for this context
 * @template TTriggers - Array of trigger definitions
 * @template TOverrides - Properties to override from middleware
 * @internal
 */
type HandlerWithTriggers<TStepTools, TTriggers extends readonly any[], TOverrides extends BasicDataUnknown = Record<never, never>> = (
/**
 * The context argument provides access to all data and tooling available to
 * the function.
 */
ctx: ContextWithTriggers<TStepTools, TTriggers, TOverrides>) => unknown;
//#endregion
export { HandlerWithTriggers };
//# sourceMappingURL=typeHelpers.d.ts.map