import { TRPCError } from '../error/TRPCError';
import type { Simplify } from '../types';
import type { AnyRootConfig, RootConfig } from './internals/config';
import type { ParseFn } from './internals/getParseFn';
import type { ProcedureBuilderMiddleware } from './internals/procedureBuilder';
import type { DefaultValue, MiddlewareMarker, Overwrite, UnsetMarker } from './internals/utils';
import type { ProcedureParams } from './procedure';
import type { ProcedureType } from './types';
/**
 * @internal
 */
interface MiddlewareResultBase {
    /**
     * All middlewares should pass through their `next()`'s output.
     * Requiring this marker makes sure that can't be forgotten at compile-time.
     */
    readonly marker: MiddlewareMarker;
}
/**
 * @internal
 */
interface MiddlewareOKResult<_TParams extends ProcedureParams> extends MiddlewareResultBase {
    ok: true;
    data: unknown;
}
/**
 * @internal
 */
interface MiddlewareErrorResult<_TParams extends ProcedureParams> extends MiddlewareResultBase {
    ok: false;
    error: TRPCError;
}
/**
 * @internal
 */
export type MiddlewareResult<TParams extends ProcedureParams> = MiddlewareErrorResult<TParams> | MiddlewareOKResult<TParams>;
/**
 * @internal
 */
export interface MiddlewareBuilder<TRoot extends ProcedureParams, TNewParams extends ProcedureParams> {
    /**
     * Create a new builder based on the current middleware builder
     */
    unstable_pipe<$Params extends ProcedureParams>(fn: {
        _config: TRoot['_config'];
        _meta: TRoot['_meta'];
        _ctx_out: Overwrite<TRoot['_ctx_out'], TNewParams['_ctx_out']>;
        _input_in: DefaultValue<TRoot['_input_in'], TNewParams['_input_in']>;
        _input_out: DefaultValue<TRoot['_input_out'], TNewParams['_input_out']>;
        _output_in: DefaultValue<TRoot['_output_in'], TNewParams['_output_in']>;
        _output_out: DefaultValue<TRoot['_output_out'], TNewParams['_output_out']>;
    } extends infer OParams extends ProcedureParams ? MiddlewareBuilder<OParams, $Params> | MiddlewareFunction<OParams, $Params> : never): CreateMiddlewareReturnInput<TRoot, TNewParams, Overwrite<TNewParams, $Params>>;
    /**
     * List of middlewares within this middleware builder
     */
    _middlewares: MiddlewareFunction<TRoot, TNewParams>[];
}
/**
 * @internal
 * FIXME: there must be a nicer way of doing this, it's hard to maintain when we have several structures like this
 */
type CreateMiddlewareReturnInput<TRoot extends ProcedureParams, TPrev extends ProcedureParams, TNext extends ProcedureParams> = MiddlewareBuilder<TRoot, {
    _config: TPrev['_config'];
    _meta: TPrev['_meta'];
    _ctx_out: Overwrite<TPrev['_ctx_out'], TNext['_ctx_out']>;
    _input_in: DefaultValue<TNext['_input_in'], TPrev['_input_in']>;
    _input_out: DefaultValue<TNext['_input_out'], TPrev['_input_out']>;
    _output_in: DefaultValue<TNext['_output_in'], TPrev['_output_in']>;
    _output_out: DefaultValue<TNext['_output_out'], TPrev['_output_out']>;
}>;
/**
 * @internal
 */
type deriveParamsFromConfig<TConfig extends AnyRootConfig, TInputIn = unknown> = {
    _config: TConfig;
    _ctx_out: {};
    _input_out: UnsetMarker;
    _input_in: TInputIn;
    _output_in: unknown;
    _output_out: unknown;
    _meta: TConfig['$types']['meta'];
};
/**
 * @internal
 */
export type MiddlewareFunction<TParams extends ProcedureParams, TParamsAfter extends ProcedureParams> = {
    (opts: {
        ctx: Simplify<Overwrite<TParams['_config']['$types']['ctx'], TParams['_ctx_out']>>;
        type: ProcedureType;
        path: string;
        input: TParams['_input_in'];
        rawInput: unknown;
        meta: TParams['_meta'] | undefined;
        next: {
            (): Promise<MiddlewareResult<TParams>>;
            <$Context>(opts: {
                ctx: $Context;
            }): Promise<MiddlewareResult<{
                _config: TParams['_config'];
                _ctx_out: $Context;
                _input_in: TParams['_input_in'];
                _input_out: TParams['_input_out'];
                _output_in: TParams['_output_in'];
                _output_out: TParams['_output_out'];
                _meta: TParams['_meta'];
            }>>;
            (opts: {
                rawInput: unknown;
            }): Promise<MiddlewareResult<TParams>>;
        };
    }): Promise<MiddlewareResult<TParamsAfter>>;
    _type?: string | undefined;
};
/**
 * @internal
 */
export declare function createMiddlewareFactory<TConfig extends AnyRootConfig, TInputIn = unknown>(): <TNewParams extends ProcedureParams<AnyRootConfig, unknown, unknown, unknown, unknown, unknown, unknown>>(fn: MiddlewareFunction<deriveParamsFromConfig<TConfig, TInputIn>, TNewParams>) => MiddlewareBuilder<deriveParamsFromConfig<TConfig, TInputIn>, TNewParams>;
export declare const experimental_standaloneMiddleware: <TCtx extends {
    ctx?: object | undefined;
    meta?: object | undefined;
    input?: unknown;
}>() => {
    create: <TNewParams extends ProcedureParams<AnyRootConfig, unknown, unknown, unknown, unknown, unknown, unknown>>(fn: MiddlewareFunction<deriveParamsFromConfig<RootConfig<{
        ctx: TCtx extends {
            ctx: infer T extends object;
        } ? T : object;
        meta: TCtx extends {
            meta: infer T_1 extends object;
        } ? T_1 : object;
        errorShape: object;
        transformer: object;
    }>, TCtx extends {
        input: infer T_2;
    } ? T_2 : unknown>, TNewParams>) => MiddlewareBuilder<deriveParamsFromConfig<RootConfig<{
        ctx: TCtx extends {
            ctx: infer T extends object;
        } ? T : object;
        meta: TCtx extends {
            meta: infer T_1 extends object;
        } ? T_1 : object;
        errorShape: object;
        transformer: object;
    }>, TCtx extends {
        input: infer T_2;
    } ? T_2 : unknown>, TNewParams>;
};
/**
 * @internal
 * Please note, `trpc-openapi` uses this function.
 */
export declare function createInputMiddleware<TInput>(parse: ParseFn<TInput>): ProcedureBuilderMiddleware;
/**
 * @internal
 */
export declare function createOutputMiddleware<TOutput>(parse: ParseFn<TOutput>): ProcedureBuilderMiddleware;
export {};
//# sourceMappingURL=middleware.d.ts.map