import type { ReactNode } from "react";
import type { MetaDescriptor, MetaMatch as _MetaMatch } from "../dom/ssr/routeModules";
import type { LinkDescriptor } from "../dom/ssr/links";
import type { AppLoadContext } from "../server-runtime/data";
import type { Location } from "./history";
import type { UIMatch } from "./utils";
type MaybePromise<T> = T | Promise<T>;
type Pretty<T> = {
    [K in keyof T]: T[K];
} & {};
type Serializable = undefined | null | boolean | string | symbol | number | Array<Serializable> | {
    [key: PropertyKey]: Serializable;
} | bigint | Date | URL | RegExp | Error | Map<Serializable, Serializable> | Set<Serializable> | Promise<Serializable>;
type Data = MaybePromise<Exclude<Serializable, undefined | Promise<Serializable>>>;
export type ResponseStub = {
    status: number | undefined;
    headers: Headers;
};
type LoaderArgs<Param extends string> = {
    context: AppLoadContext;
    request: Request;
    params: Params<Param>;
    response: ResponseStub;
};
type ActionArgs<Param extends string> = {
    context: AppLoadContext;
    request: Request;
    params: Params<Param>;
    response: ResponseStub;
};
type Params<Param extends string> = Pretty<{
    [key: string]: string | undefined;
} & {
    [K in Param as K extends `${string}?` ? never : K]: string;
} & {
    [K in Param as K extends `${infer P}?` ? P : never]?: string;
}>;
type IsDefined<T> = Equal<T, undefined> extends true ? false : true;
type _LoaderData<ServerLoaderData, ClientLoaderData, ClientLoaderHydrate extends boolean, HydrateFallback> = Awaited<[
    undefined extends HydrateFallback ? false : true,
    ClientLoaderHydrate
] extends [true, true] ? IsDefined<ClientLoaderData> extends true ? ClientLoaderData : undefined : [
    IsDefined<ClientLoaderData>,
    IsDefined<ServerLoaderData>
] extends [true, true] ? ServerLoaderData | ClientLoaderData : IsDefined<ClientLoaderData> extends true ? ClientLoaderHydrate extends true ? ClientLoaderData : ClientLoaderData | undefined : IsDefined<ServerLoaderData> extends true ? ServerLoaderData : undefined>;
type LoaderData<ServerLoaderData, ClientLoaderData, ClientLoaderHydrate extends boolean, HydrateFallback> = _LoaderData<Awaited<ServerLoaderData>, Awaited<ClientLoaderData>, ClientLoaderHydrate, HydrateFallback>;
type ActionData<ServerActionData, ClientActionData> = Awaited<[
    IsDefined<ServerActionData>,
    IsDefined<ClientActionData>
] extends [true, true] ? ServerActionData | ClientActionData : IsDefined<ClientActionData> extends true ? ClientActionData : IsDefined<ServerActionData> extends true ? ServerActionData : undefined>;
type HydrateFallbackComponent<Param extends string> = (args: {
    params: Params<Param>;
}) => ReactNode;
type Route<Param extends string, ClientLoaderHydrate extends boolean, HydrateFallback extends HydrateFallbackComponent<Param> | undefined, ServerLoaderData extends Data | undefined, ClientLoaderData, ServerActionData extends Data | undefined, ClientActionData> = {
    params?: Param[];
    links?: (args: {
        params: Params<Param>;
    }) => LinkDescriptor[];
    HydrateFallback?: HydrateFallback;
    serverLoader?: (args: LoaderArgs<Param>) => ServerLoaderData;
    clientLoader?: (args: LoaderArgs<Param> & {
        serverLoader: IsDefined<ServerLoaderData> extends true ? () => Promise<Awaited<ServerLoaderData>> : undefined;
    }) => ClientLoaderData;
    clientLoaderHydrate?: ClientLoaderHydrate;
    serverAction?: (args: ActionArgs<Param>) => ServerActionData;
    clientAction?: (args: ActionArgs<Param> & {
        serverAction: IsDefined<ServerActionData> extends true ? () => Promise<Awaited<ServerActionData>> : undefined;
    }) => ClientActionData;
    meta?: (args: {
        params: Params<Param>;
        location: Location;
        error: unknown;
        loaderData?: LoaderData<ServerLoaderData, ClientLoaderData, ClientLoaderHydrate, HydrateFallback>;
        matches?: Array<_MetaMatch>;
    }) => MetaDescriptor[];
    Component?: (args: {
        params: Params<Param>;
        loaderData: LoaderData<ServerLoaderData, ClientLoaderData, ClientLoaderHydrate, HydrateFallback>;
        actionData?: ActionData<ServerActionData, ClientActionData>;
    }) => ReactNode;
    ErrorBoundary?: (args: {
        params: Params<Param>;
        error: unknown;
        loaderData?: LoaderData<ServerLoaderData, ClientLoaderData, ClientLoaderHydrate, HydrateFallback>;
        actionData?: ActionData<ServerActionData, ClientActionData>;
    }) => ReactNode;
    handle?: unknown;
};
export declare function defineRoute<T, const Param extends string, ClientLoaderHydrate extends boolean, HydrateFallback extends HydrateFallbackComponent<Param> | undefined, ServerLoaderData extends Data | undefined = undefined, ClientLoaderData = undefined, ServerActionData extends Data | undefined = undefined, ClientActionData = undefined>(route: T & Route<Param, ClientLoaderHydrate, HydrateFallback, ServerLoaderData, ClientLoaderData, ServerActionData, ClientActionData>): T;
export declare function defineRootRoute<T, const Param extends string, ClientLoaderHydrate extends boolean, HydrateFallback extends HydrateFallbackComponent<Param> | undefined, ServerLoaderData extends Data | undefined = undefined, ClientLoaderData = undefined, ServerActionData extends Data | undefined = undefined, ClientActionData = undefined>(route: T & Route<Param, ClientLoaderHydrate, HydrateFallback, ServerLoaderData, ClientLoaderData, ServerActionData, ClientActionData> & {
    Layout: (args: {
        params: Params<Param>;
        error: unknown;
        loaderData?: LoaderData<ServerLoaderData, ClientLoaderData, ClientLoaderHydrate, HydrateFallback>;
        actionData?: ActionData<ServerActionData, ClientActionData>;
    }) => ReactNode;
}): T;
type LoaderDataFromRoute<R> = R extends Route<any, infer ClientLoaderHydrate, infer HydrateFallback, infer ServerLoaderData, infer ClientLoaderData, any, any> ? LoaderData<ServerLoaderData, ClientLoaderData, ClientLoaderHydrate, HydrateFallback> : never;
export type MetaMatch<R extends Route<any, any, any, any, any, any, any>> = _MetaMatch<string, LoaderDataFromRoute<R>>;
export type Match<R extends Route<any, any, any, any, any, any, any>> = Pretty<UIMatch<LoaderDataFromRoute<R>>>;
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2) ? true : false;
export {};
