import { z } from "zod";
import type { ZapierSdk } from "../sdk";
export interface FormattedItem {
    title: string;
    id?: string;
    key?: string;
    keys?: string[];
    description?: string;
    data?: unknown;
    details: Array<{
        label?: string;
        text: string;
        style: "normal" | "dim" | "accent" | "warning" | "success";
    }>;
}
export interface FormatMetadata<TItem = unknown> {
    format: (item: TItem) => FormattedItem;
}
export interface OutputFormatter<TItem = unknown, TParams = Record<string, unknown>, TContext = unknown> {
    fetch?: (sdk: ZapierSdk, params: TParams, item: TItem, context: TContext | undefined) => Promise<TContext>;
    format: (item: TItem, context?: TContext) => FormattedItem;
}
export declare function withFormatter<T extends z.ZodType>(schema: T, formatMeta: FormatMetadata<z.infer<T>>): T;
export declare function getOutputSchema(inputSchema: z.ZodType): z.ZodType | undefined;
export declare function withOutputSchema<T extends z.ZodType>(inputSchema: T, outputSchema: z.ZodType): T & {
    _def: T["_def"] & {
        outputSchema: z.ZodType;
    };
};
export interface PromptConfig {
    type: "list" | "checkbox" | "confirm";
    name: string;
    message: string;
    choices?: Array<{
        name: string;
        value: unknown;
        /**
         * Optional secondary info shown after `name`. The CLI wraps it in
         * dimmed parens; an array is joined with ", ". Use for keys, ids, or
         * other context that's useful but shouldn't compete visually with
         * the primary label.
         */
        hint?: string | string[];
    }>;
    default?: unknown;
    filter?: (value: unknown) => unknown;
    /**
     * Return `true` for valid; a string for a custom invalid message; or
     * `false` for invalid with a generic fallback message ("X: invalid
     * value."). Prefer returning a string so users see something specific.
     */
    validate?: (value: unknown) => boolean | string;
}
/** A PromptConfig narrowed to single-select list mode. */
export type ListPromptConfig = PromptConfig & {
    type: "list";
};
export interface Resolver {
    type: string;
    depends?: readonly string[] | string[];
}
export interface StaticResolver extends Resolver {
    type: "static";
    inputType?: "text" | "password" | "email";
    placeholder?: string;
}
/**
 * A resolver that always resolves to a fixed value, never prompts. Use to
 * pin an implicit parameter that downstream resolvers or SDK calls require
 * but the user shouldn't have to provide. Triggers, for example, are always
 * `actionType: "read"` from the SDK's perspective; createTriggerInbox
 * declares `actionType: { type: "constant", value: "read" }` so the
 * standard `actionKeyResolver` and `inputsResolver` (which depend on
 * `actionType`) work without any pinned variants.
 *
 * Constants attached to keys that aren't in the schema are seeded into
 * `resolvedParams` upfront, so dependent resolvers find them in context
 * without the key appearing in the user-facing surface (TS option type,
 * CLI flags, generated docs).
 */
export interface ConstantResolver extends Resolver {
    type: "constant";
    value: unknown;
}
/**
 * Fields shared by both variants of {@link DynamicResolver}.
 */
interface DynamicResolverBase<TItem, TParams> extends Resolver {
    type: "dynamic";
    prompt: (items: TItem[], params: TParams) => PromptConfig;
    /** Capabilities that expand results. The parameter resolver shows a hint for any that aren't enabled. */
    requireCapabilities?: string[];
    /**
     * Optional hook called before fetch/prompt. If it returns a non-null object,
     * resolvedValue is used directly and fetch/prompt are skipped entirely. Return
     * null to fall through to the normal resolution flow. Implementations should
     * catch their own errors and return null on failure rather than throwing, so
     * that a transient API error does not block the CLI entirely.
     */
    tryResolveWithoutPrompt?: (sdk: ZapierSdk, params: TParams) => Promise<{
        resolvedValue: unknown;
    } | null>;
}
/**
 * The classic dynamic-resolver variant: `fetch` returns a list of items
 * that the CLI renders as a search-filterable dropdown. The user picks one.
 */
export interface DynamicListResolver<TItem, TParams> extends DynamicResolverBase<TItem, TParams> {
    /** Explicitly absent on the list variant — set `inputType: "search"` to opt into the search variant. */
    inputType?: never;
    /** Only meaningful for the search variant; set to `never` here so TS catches misuse. */
    placeholder?: never;
    fetch: (sdk: ZapierSdk, resolvedParams: TParams) => PromiseLike<TItem[] | {
        data: TItem[];
        nextCursor?: string;
    } | AsyncIterable<{
        data: TItem[];
        nextCursor?: string;
    }>>;
}
/**
 * The search-input variant: the CLI prompts the user for free-form text
 * first, then calls `fetch` with `{ ...resolvedParams, search }`.
 *
 * `fetch` can short-circuit by returning a primitive (`string | number`),
 * which the CLI treats as an exact match — no dropdown is rendered. Any
 * other return (array, page, async iterable) is rendered as the normal
 * search-filterable dropdown.
 *
 * The `search` key is injected by the CLI at call time; it isn't part of
 * `TParams` because callers that invoke `fetch` directly (outside the CLI)
 * are responsible for passing it themselves. Search-mode resolvers should
 * type `TParams` as `{ search?: string; ...otherDeps }` to make this
 * explicit.
 */
export interface DynamicSearchResolver<TItem, TParams> extends Omit<DynamicResolverBase<TItem, TParams>, "prompt"> {
    inputType: "search";
    /**
     * Hint text appended to the search prompt's message. NOT used as
     * inquirer's `default` value, because inquirer prefills `default` as
     * editable text that the user has to delete before typing.
     */
    placeholder?: string;
    /**
     * Search-mode always renders a single-select @inquirer/search dropdown,
     * so `prompt` must return a list-typed PromptConfig. Checkbox/confirm
     * configs would be silently ignored at runtime; the type narrows so
     * misuse fails at compile time.
     *
     * Note: a primitive return from `fetch` (string | number) is treated
     * as an exact match and short-circuits without running this prompt or
     * the resolver's validate/filter. Canonicalize inside `fetch` if the
     * exact-match path needs normalization.
     */
    prompt: (items: TItem[], params: TParams) => ListPromptConfig;
    fetch: (sdk: ZapierSdk, resolvedParams: TParams) => PromiseLike<string | number | TItem[] | {
        data: TItem[];
        nextCursor?: string;
    } | AsyncIterable<{
        data: TItem[];
        nextCursor?: string;
    }>>;
}
/**
 * A dynamic resolver — either a classic list (`inputType` absent) or a
 * search-input variant (`inputType: "search"`). The discriminator is the
 * `inputType` field; TS narrows to the right variant when you check it.
 */
export type DynamicResolver<TItem = unknown, TParams = Record<string, unknown>> = DynamicListResolver<TItem, TParams> | DynamicSearchResolver<TItem, TParams>;
export interface ResolverFieldItem {
    type: string;
    key: string;
    title?: string;
    is_required?: boolean;
    value_type?: string;
    choices?: Array<{
        label: string;
        value: string;
    }>;
    fields?: ResolverFieldItem[];
    resolver?: ResolverMetadata<any, any>;
}
export interface FieldsResolver<TParams = Record<string, unknown>, TResult = Record<string, unknown>> extends Resolver {
    type: "fields";
    fetch: (sdk: ZapierSdk, resolvedParams: TParams) => Promise<ResolverFieldItem[]>;
    transform?: (value: Record<string, unknown>) => TResult;
}
export interface ArrayResolver<TParams = Record<string, unknown>> extends Resolver {
    type: "array";
    fetch: (sdk: ZapierSdk, resolvedParams: TParams) => Promise<ResolverMetadata<unknown, TParams>>;
    minItems?: number;
    maxItems?: number;
}
export type ResolverMetadata<TItem = unknown, TParams = Record<string, unknown>> = StaticResolver | ConstantResolver | DynamicResolver<TItem, TParams> | FieldsResolver<TParams> | ArrayResolver<TParams>;
export interface ResolverConfig<TItem = unknown, TParams = Record<string, unknown>> {
    resolver: ResolverMetadata<TItem, TParams>;
}
export declare function withResolver<T extends z.ZodType, TItem = unknown, TParams = Record<string, unknown>>(schema: T, config: ResolverConfig<TItem, TParams>): T;
export declare function getSchemaDescription(schema: z.ZodSchema): string | undefined;
export declare function getFieldDescriptions(schema: z.ZodObject<z.ZodRawShape>): Record<string, string>;
export interface PositionalMetadata {
    positionalMeta: {
        positional: true;
    };
}
export declare function withPositional<T extends z.ZodType>(schema: T): T & {
    _def: T["_def"] & PositionalMetadata;
};
export declare function isPositional(schema: z.ZodType): boolean;
export {};
//# sourceMappingURL=schema-utils.d.ts.map