import { Ref } from '@lifi/compose-spec';
import { ParseAbiItem } from 'abitype';
import { AbiTypeToOutputKind, TypedGuard } from '../types.js';
import { AnyBindable, CallArgs } from './FlowBuilderCore.js';
import { Bindable, OutputHandle } from './handles.js';

/**
 * Type-level extraction of named bind keys from a function signature string.
 * When `TSig` is a string literal matching a Solidity function signature,
 * resolves to a record whose keys are the parameter names and values are
 * `Bindable<kind>` where the kind is derived from each parameter's Solidity
 * type via `AbiTypeToOutputKind`. For recognised `SolType` parameters
 * (e.g. `uint256`, `address`, `uint128`) the bind slot is precisely typed;
 * for other Solidity types (e.g. tuples) the slot accepts any scalar handle.
 * Falls back to `Record<string, AnyBindable>` for non-literal strings.
 */
type SignatureBind<TSig extends string> = string extends TSig ? Record<string, AnyBindable> : ParseAbiItem<TSig> extends {
    type: 'function';
    inputs: infer I extends readonly {
        name: string;
        type: string;
    }[];
} ? {
    readonly [P in I[number] as P['name']]: Bindable<AbiTypeToOutputKind<P['type']>>;
} : Record<string, AnyBindable>;
/**
 * Describes the output type(s) of a parsed function signature as a
 * human-readable string for inclusion in type-level error messages.
 */
type DescribeOutputs<O extends readonly {
    type: string;
}[]> = O extends readonly [{
    type: infer T extends string;
}] ? T : 'multiple values';
/**
 * A string-literal type that surfaces a clear error when the user provides a
 * function signature whose return type is not supported by core.call.
 * The message is visible in IDE tooltips and compiler diagnostics.
 */
type UnsupportedReturnTypeError<TLabel extends string, TSig extends string> = ParseAbiItem<TSig> extends {
    type: 'function';
    outputs: infer O extends readonly {
        type: string;
    }[];
} ? `[TypeError] ${TLabel}: return type '${DescribeOutputs<O>}' is not supported — only 'uint256' or void signatures are allowed` : `[TypeError] ${TLabel}: unable to parse return type from signature`;
/**
 * Conditional output type for `core.call` based on the function signature's
 * return type:
 *
 * - `returns (uint256)` → `{ result: OutputHandle }`
 * - No returns clause   → `{ result: undefined }`
 * - Anything else        → `{ result: "[TypeError] ..." }` (compile-time error)
 *
 * When `TSig` is a non-literal `string` (e.g. a variable, not a string
 * constant), the type falls back to `{ result: OutputHandle | undefined }`
 * so that both void and uint256 call sites remain assignable.
 */
type CoreCallResult<TSig extends string> = string extends TSig ? {
    readonly result: OutputHandle<'uint256'> | undefined;
} : ParseAbiItem<TSig> extends {
    type: 'function';
    outputs: readonly [];
} ? {
    readonly result: undefined;
} : ParseAbiItem<TSig> extends {
    type: 'function';
    outputs: readonly [{
        type: 'uint256';
    }];
} ? {
    readonly result: OutputHandle<'uint256'>;
} : {
    readonly result: UnsupportedReturnTypeError<'core.call', TSig>;
};
/**
 * Conditional output type for `core.staticCall`. staticCall always reads a
 * value, so void signatures are also rejected:
 *
 * - `returns (uint256)` → `{ result: OutputHandle }`
 * - No returns / other  → `{ result: "[TypeError] ..." }` (compile-time error)
 */
type StaticCallResult<TSig extends string> = string extends TSig ? {
    readonly result: OutputHandle<'uint256'>;
} : ParseAbiItem<TSig> extends {
    type: 'function';
    outputs: readonly [{
        type: 'uint256';
    }];
} ? {
    readonly result: OutputHandle<'uint256'>;
} : ParseAbiItem<TSig> extends {
    type: 'function';
    outputs: readonly [];
} ? {
    readonly result: `[TypeError] core.staticCall: function has no return value — staticCall requires a 'returns (uint256)' signature`;
} : {
    readonly result: UnsupportedReturnTypeError<'core.staticCall', TSig>;
};
/**
 * Parses a Solidity function signature and returns parameter names in order.
 * Delegates to abitype's runtime `parseAbiItem` — the same parser that powers
 * the compile-time `ParseAbiItem<TSig>` type — so runtime and type-level
 * parsing can never diverge.
 *
 * @throws if the signature is not a valid function signature or a parameter is unnamed
 */
declare const parseFunctionParams: (functionSignature: string) => string[];
/**
 * Converts any `AnyBindable` to a `Ref` (`{ $ref: string }`).
 * Handles carry a `_tag` property and are converted via `handleToRef`;
 * `Ref` objects pass through as-is.
 */
declare const toBindRef: (bindable: AnyBindable) => Ref;
interface BuildCallWireFormatInput {
    readonly resource?: AnyBindable;
    readonly bind: Record<string, AnyBindable>;
    readonly config: Record<string, unknown>;
    readonly guards?: readonly TypedGuard[];
}
interface CallWireResult {
    readonly op: 'core.call' | 'core.invoke';
    readonly bind: Record<string, Ref>;
    readonly config: Record<string, unknown>;
    readonly guards?: readonly TypedGuard[];
}
/**
 * Transforms the user-facing `resource` + named `bind` API into the wire
 * format that the backend expects:
 * - With resource: `core.call` with `bind: { input: <resourceRef> }`
 * - Without resource: `core.invoke` with `bind: {}`
 * - `config: { ...userConfig, args: [positional refs...] }`
 */
declare const buildCallWireFormat: (args: BuildCallWireFormatInput) => CallWireResult;
interface BuildStaticCallWireFormatInput {
    readonly bind: Record<string, AnyBindable>;
    readonly config: Record<string, unknown>;
    readonly guards?: readonly TypedGuard[];
}
/**
 * Transforms the user-facing named `bind` API into the wire format that the
 * backend expects for `core.staticCall`. Same as `buildCallWireFormat` but
 * with no `resource` field — staticCall has no resource inputs.
 */
declare const buildStaticCallWireFormat: (args: BuildStaticCallWireFormatInput) => CallArgs;

export { type BuildCallWireFormatInput, type BuildStaticCallWireFormatInput, type CallWireResult, type CoreCallResult, type SignatureBind, type StaticCallResult, buildCallWireFormat, buildStaticCallWireFormat, parseFunctionParams, toBindRef };
