import type { StandardSchemaV1 } from "@standard-schema/spec";
import type { HttpContractConfig, InferOutput, Success2xxKeys } from "../contracts/index.js";
import type { ContractLike, ResolveContract } from "./contract-like.js";
import type { AddedCtxFromHooks, Handler, InferBody, InferHeaders, InferPath, InferQuery, RouteHook } from "./http.js";
/**
 * Structural shape of a finalized use case accepted by the route binder.
 *
 * This intentionally mirrors `UseCaseDef` from `@beignet/core/application`
 * without importing it, so the server runtime stays decoupled from the
 * application builder at runtime.
 */
export type AnyUseCaseLike = {
    /**
     * Stable use-case name, used in binder diagnostics.
     */
    name: string;
    /**
     * Input schema declared with `.input(...)`.
     */
    inputSchema: StandardSchemaV1;
    /**
     * Output schema declared with `.output(...)`.
     */
    outputSchema: StandardSchemaV1;
    /**
     * Execute the use case with application context and typed input.
     */
    run: (args: never) => Promise<unknown>;
};
type UseCaseRouteCtx<UC> = UC extends {
    run: (args: {
        ctx: infer Ctx;
        input: infer _Input;
    }) => Promise<infer _Out>;
} ? Ctx : never;
/**
 * Input type accepted by a bound use case's `run(...)`.
 */
export type UseCaseRouteInput<UC> = UC extends {
    run: (args: {
        ctx: infer _Ctx;
        input: infer Input;
    }) => Promise<infer _Out>;
} ? Input : never;
type UseCaseRouteOutput<UC> = UC extends {
    run: (args: {
        ctx: infer _Ctx;
        input: infer _Input;
    }) => Promise<infer Out>;
} ? Out : never;
type ResponseBodyForSchema<S> = S extends null ? // biome-ignore lint/suspicious/noConfusingVoidType: void accepts z.void() use case outputs for null response schemas
void | undefined : S extends StandardSchemaV1 ? InferOutput<S> : unknown;
type ResponseForStatus<TResponses, TStatus extends number> = TStatus extends keyof TResponses ? TResponses[TStatus] : `${TStatus}` extends keyof TResponses ? TResponses[`${TStatus}`] : never;
type SuccessBodyFromKeys<TResponses, K> = [K] extends [never] ? unknown : K extends number ? ResponseBodyForSchema<ResponseForStatus<TResponses, K>> : unknown;
type UnionToIntersection<T> = (T extends unknown ? (value: T) => void : never) extends (value: infer I) => void ? I : never;
type BinderStatusFromKeys<K> = [K] extends [never] ? {
    /**
     * Success status for the use case result. Required because the contract
     * does not declare exactly one 2xx response.
     */
    status: number;
} : [K] extends [UnionToIntersection<K>] ? {
    /**
     * Success status for the use case result. Optional because the
     * contract declares exactly one 2xx response.
     */
    status?: K;
} : {
    /**
     * Success status for the use case result. Required because the
     * contract declares multiple 2xx responses.
     */
    status: K;
};
/**
 * `status` option for a binder route.
 *
 * Optional and typed to the sole declared 2xx status when the contract
 * declares exactly one, required (typed to the union of declared 2xx
 * statuses) otherwise.
 */
export type BinderStatusOption<C extends HttpContractConfig> = BinderStatusFromKeys<Success2xxKeys<C["responses"]>>;
/**
 * Parsed request parts passed to a binder route's `input` mapper.
 */
export type UseCaseRouteInputParts<C extends HttpContractConfig> = {
    /**
     * Parsed path parameters.
     */
    path: InferPath<C>;
    /**
     * Parsed query parameters.
     */
    query: InferQuery<C>;
    /**
     * Parsed request headers.
     */
    headers: InferHeaders<C>;
    /**
     * Parsed request body.
     */
    body: InferBody<C>;
};
type SegmentPathParam<Segment extends string> = Segment extends `:${infer Name}` ? Name : Segment extends `[${infer Name}]` ? Name : never;
type PathParamNames<Path extends string> = string extends Path ? never : Path extends `${infer Segment}/${infer Rest}` ? SegmentPathParam<Segment> | PathParamNames<Rest> : SegmentPathParam<Path>;
type EmptyBinderInput = Record<never, never>;
declare const UNMERGEABLE_BINDER_INPUT: unique symbol;
type UnmergeableBinderInput = {
    readonly [UNMERGEABLE_BINDER_INPUT]: true;
};
type IsAny<T> = 0 extends 1 & T ? true : false;
type BinderObject<T> = IsAny<T> extends true ? UnmergeableBinderInput : [T] extends [object] ? [Extract<T, readonly unknown[]>] extends [never] ? T : UnmergeableBinderInput : UnmergeableBinderInput;
type MergeBinderObjects<LowerPrecedence, HigherPrecedence> = [
    BinderObject<LowerPrecedence>
] extends [UnmergeableBinderInput] ? UnmergeableBinderInput : [BinderObject<HigherPrecedence>] extends [UnmergeableBinderInput] ? UnmergeableBinderInput : Omit<BinderObject<LowerPrecedence>, keyof BinderObject<HigherPrecedence>> & BinderObject<HigherPrecedence>;
type InferredPathInput<C extends HttpContractConfig> = string extends C["path"] ? UnmergeableBinderInput : [PathParamNames<C["path"]>] extends [never] ? EmptyBinderInput : {
    [K in PathParamNames<C["path"]>]: string;
};
type BinderPathInput<C extends HttpContractConfig> = C["pathParams"] extends StandardSchemaV1 ? InferOutput<C["pathParams"]> : InferredPathInput<C>;
type BinderQueryInput<C extends HttpContractConfig> = C["query"] extends StandardSchemaV1 ? InferOutput<C["query"]> : EmptyBinderInput;
type BinderBodyInput<C extends HttpContractConfig> = C["body"] extends StandardSchemaV1 ? InferOutput<C["body"]> : EmptyBinderInput;
type HasPathSchema<C extends HttpContractConfig> = C["pathParams"] extends StandardSchemaV1 ? true : false;
type HasQuerySchema<C extends HttpContractConfig> = C["query"] extends StandardSchemaV1 ? true : false;
type HasBodySchema<C extends HttpContractConfig> = C["body"] extends StandardSchemaV1 ? true : false;
type HasInferredPathInput<C extends HttpContractConfig> = string extends C["path"] ? true : [PathParamNames<C["path"]>] extends [never] ? false : true;
type MergedBinderInput<C extends HttpContractConfig> = MergeBinderObjects<MergeBinderObjects<BinderQueryInput<C>, BinderBodyInput<C>>, BinderPathInput<C>>;
/**
 * Input produced when a binder route omits an explicit `input` mapper.
 *
 * A sole declared request schema passes through unchanged when the literal
 * path has no additional inferred parameters. Every other supported default
 * binding merges object inputs with path over body over query precedence.
 */
type DefaultBinderRouteInput<C extends HttpContractConfig> = HasPathSchema<C> extends true ? HasQuerySchema<C> extends true ? MergedBinderInput<C> : HasBodySchema<C> extends true ? MergedBinderInput<C> : BinderPathInput<C> : HasQuerySchema<C> extends true ? HasBodySchema<C> extends true ? MergedBinderInput<C> : HasInferredPathInput<C> extends true ? MergedBinderInput<C> : BinderQueryInput<C> : HasBodySchema<C> extends true ? HasInferredPathInput<C> extends true ? MergedBinderInput<C> : BinderBodyInput<C> : BinderPathInput<C>;
type UseCaseRouteInputMode = "default" | "mapped";
/**
 * Constraint that checks a use case against the route that binds it.
 *
 * Produces a readable branded mismatch object on the `useCase` property when
 * the use case requires a context the server does not provide, when its
 * output does not match the contract's declared success response schema, or
 * when the default binder input does not satisfy the use case input.
 */
export type UseCaseFitsRoute<Ctx, C extends HttpContractConfig, UC, InputMode extends UseCaseRouteInputMode = "default"> = [Ctx] extends [UseCaseRouteCtx<UC>] ? [UseCaseRouteOutput<UC>] extends [
    SuccessBodyFromKeys<C["responses"], Success2xxKeys<C["responses"]>>
] ? InputMode extends "mapped" ? unknown : [DefaultBinderRouteInput<C>] extends [UseCaseRouteInput<UC>] ? unknown : {
    "~beignetError": "default binder input does not match the use case input; add an input mapper";
} : {
    "~beignetError": "useCase output does not match the contract's success response schema";
} : {
    "~beignetError": "useCase requires a context this server does not provide";
};
type UseCaseRouteShape<HandlerCtx, CLike extends ContractLike, C extends HttpContractConfig, UC extends AnyUseCaseLike, Hooks> = {
    /**
     * Contract builder or plain contract config for this route.
     */
    contract: CLike;
    /**
     * Route-scoped hooks that run after group hooks and before the use case.
     */
    hooks?: Hooks;
    handle?: never;
} & ({
    /**
     * Use case bound directly to the contract. The default binder input
     * must satisfy the use case input type.
     */
    useCase: UC & UseCaseFitsRoute<HandlerCtx, C, UC>;
    input?: never;
} | {
    /**
     * Use case bound directly to the contract through an explicit input
     * mapper.
     */
    useCase: UC & UseCaseFitsRoute<HandlerCtx, C, UC, "mapped">;
    /**
     * Map parsed request parts to the use case input.
     *
     * A sole declared path, query, or body schema is passed through
     * unchanged when no additional path, query, or object body values are
     * present. Otherwise `defaultBinderInput` merges query, body, and path
     * objects (path wins collisions) and never merges headers.
     */
    input: (parts: UseCaseRouteInputParts<C>) => UseCaseRouteInput<UC>;
}) & BinderStatusOption<C>;
/**
 * Route registration that binds a contract directly to a use case.
 *
 * The server synthesizes the handler: it maps parsed request parts to the use
 * case input, runs the use case, and returns its output as the success
 * response body. Use a full `handle` route for headers, streaming, native
 * `Response` values, or multi-status handling.
 */
export type UseCaseRouteDef<Ctx, CLike extends ContractLike, UC extends AnyUseCaseLike, Hooks extends readonly RouteHook<Ctx, object>[] = readonly []> = UseCaseRouteShape<Ctx & AddedCtxFromHooks<Hooks>, CLike, ResolveContract<CLike>, UC, Hooks>;
/**
 * Structural check that a use case accepts the context this route provides.
 *
 * Enforced through `run` parameter contravariance so it applies even at loose
 * collection boundaries where contract types are erased.
 */
export type UseCaseAcceptsCtx<Ctx> = {
    run: (args: {
        ctx: Ctx;
        input: never;
    }) => Promise<unknown>;
};
/**
 * Loosely typed binder route used at collection boundaries where contract and
 * use case types are erased. The use case's context requirement is still
 * checked against the server context.
 */
export type AnyUseCaseRouteDef<Ctx, CLike extends ContractLike = ContractLike, Hooks extends readonly RouteHook<Ctx, object>[] = readonly RouteHook<Ctx, object>[]> = {
    contract: CLike;
    hooks?: Hooks;
    useCase: AnyUseCaseLike & UseCaseAcceptsCtx<Ctx & AddedCtxFromHooks<Hooks>>;
    input?: (parts: any) => unknown;
    status?: number;
    handle?: never;
};
type HooksOf<E> = E extends {
    hooks: infer H extends readonly unknown[];
} ? H : readonly [];
/**
 * Per-element binder validation applied where route tuples are inferred, such
 * as an app-bound `defineRouteGroup({ ... })`, so contract/use-case mismatches are
 * reported on the individual route literal.
 */
export type ValidatedRouteInput<Ctx, E> = E extends {
    contract: infer CL extends ContractLike;
    useCase: infer UC extends AnyUseCaseLike;
} ? ResolveContract<CL> extends infer C extends HttpContractConfig ? {
    contract: CL;
    hooks?: HooksOf<E>;
    handle?: never;
} & ({
    useCase: UC & UseCaseFitsRoute<Ctx & AddedCtxFromHooks<HooksOf<E>>, C, UC>;
    input?: never;
} | {
    useCase: UC & UseCaseFitsRoute<Ctx & AddedCtxFromHooks<HooksOf<E>>, C, UC, "mapped">;
    input: (parts: UseCaseRouteInputParts<C>) => UseCaseRouteInput<UC>;
}) & BinderStatusOption<C> : unknown : unknown;
/**
 * Element-wise binder validation for a route input list.
 */
export type ValidatedRouteInputs<Ctx, R extends readonly unknown[]> = {
    [K in keyof R]: ValidatedRouteInput<Ctx, R[K]>;
};
/**
 * Trusted run key shared with `@beignet/core/application` via the global
 * symbol registry, so the binder never imports the application builder at
 * runtime.
 */
declare const USE_CASE_TRUSTED_RUN_KEY: unique symbol;
declare const USE_CASE_OUTPUT_VALIDATED_KEY: unique symbol;
type RuntimeUseCase = AnyUseCaseLike & {
    run: (args: {
        ctx: unknown;
        input: unknown;
    }) => Promise<unknown>;
    [USE_CASE_TRUSTED_RUN_KEY]?: (args: {
        ctx: unknown;
        input: unknown;
    }) => Promise<unknown>;
    [USE_CASE_OUTPUT_VALIDATED_KEY]?: boolean;
};
/**
 * Loosely typed binder route definition consumed by route registration.
 */
export type RuntimeUseCaseRouteDef = {
    useCase: RuntimeUseCase;
    input?: (parts: {
        path: unknown;
        query: unknown;
        headers: unknown;
        body: unknown;
    }) => unknown;
    status?: number;
};
type UseCaseInputValidationFailure = Error & {
    name: "UseCaseValidationError";
    phase: "input";
    useCaseName: string;
};
/**
 * Internal framework error raised when a type-erased binder route produces an
 * input that the bound use case rejects.
 */
export declare class UseCaseRouteInputValidationError extends Error {
    readonly code = "USE_CASE_INPUT_VALIDATION_ERROR";
    readonly contractName: string;
    readonly useCaseName: string;
    constructor(args: {
        contractName: string;
        useCaseName: string;
        cause: UseCaseInputValidationFailure;
    });
}
/**
 * Default input mapping for binder routes.
 *
 * Merges parsed query, body, and path objects into one input object. Path
 * keys win all collisions, then body keys, then query keys. Headers are never
 * merged: parsed headers include every raw request header, so merging them
 * would poison the use case input. The route binder passes a sole declared
 * input schema through unchanged when no other object input contains values;
 * this merge handles every other default mapping. Routes that combine a
 * non-object body with another source declare an explicit `input` mapper.
 */
export declare function defaultBinderInput(parts: {
    path: unknown;
    query: unknown;
    body: unknown;
}): Record<string, unknown>;
/**
 * Whether a route definition is a binder route.
 */
export declare function isUseCaseRouteDef(route: {
    handle?: unknown;
    useCase?: unknown;
}): route is RuntimeUseCaseRouteDef;
/**
 * Synthesize the route handler for a binder route at registration time.
 *
 * Resolves the success status, decides whether the validated request parts can
 * skip the use case's input parse, and computes whether server-side response
 * validation is redundant for the success status.
 */
export declare function createUseCaseRouteHandler<Ctx, C extends HttpContractConfig>(contract: C, def: RuntimeUseCaseRouteDef): {
    handler: Handler<Ctx, C>;
    responseValidationExemptStatus?: number;
};
export {};
//# sourceMappingURL=use-case-route.d.ts.map