import React from 'react';

/** The entry type for params each param is a tuple[string, type] where the string is the name of the param. */
type RouteParams_T = readonly (readonly [string, "int" | "float" | "boolean" | "string"])[];
type RouteParamsOutput_T<Params extends RouteParams_T> = {
    [K in Params[number][0]]: Extract<Params[number], readonly [K, any]>[1] extends "int" | "float" ? number : Extract<Params[number], readonly [K, any]>[1] extends "boolean" ? boolean : Extract<Params[number], readonly [K, any]>[1] extends "string" ? string : never;
};
type InnerRouteConfig_T<ParamsOutput extends RouteParamsOutput_T<any>> = {
    build: (params: ParamsOutput) => string;
    validators: Record<string, (param: string) => unknown>;
    Comp: React.ComponentType<ParamsOutput>;
    path: string;
};
type RouteConfig_T<ParamsOutput extends RouteParamsOutput_T<any>> = InnerRouteConfig_T<ParamsOutput> & {
    route: React.JSX.Element;
};

/** The producer of wouter <Switch /> components and all the routes, with a fallback and param coercion.
 * @param Comp404 The component to render when no routes match. This will be returned when a wouter path matched but coercion failed. Also given as a final route to be used when no other routes match.
 * @param routes An object of route configs, key is the rout name, value is the route() fn output.
 *
 * @returns an object containing the wouter <Switch /> component and all the routes, should be wrapped in a <Router />.
 * Render with `routes.switch`, build paths with `routes.paths.home.build({foo: "bar"})`, etc.
 */
declare const routes: <const T extends Record<string, InnerRouteConfig_T<any>>>({ Comp404, routes, }: {
    Comp404: React.ComponentType;
    routes: T;
}) => {
    switch: JSX.Element;
    paths: { [K in keyof T]: T[K] extends InnerRouteConfig_T<infer X extends RouteParamsOutput_T<any>> ? RouteConfig_T<X> : never; };
};

/** A path config holder.
 *
 * @param base The base path, e.g. "/user/".
 * @param params An array of [param_name, param_schema] tuples, e.g. [["user_id", number()]]. Where the second argument is "string"/"float"/"int"/"boolean". Coercion and type hinting for the params is handled internally.
 * @param Component The component to render when the path is matched.
 */
declare const route: <const Params extends RouteParams_T>({ base, params, Comp, }: {
    base: string;
    params: Params;
    Comp: React.ComponentType<RouteParamsOutput_T<Params>>;
}) => InnerRouteConfig_T<RouteParamsOutput_T<Params>>;

/** Simple type wrapper fn to make writing a params definition shorter.
 * @param params An array of tuples, first item is the param name, second is the param type as a string.
 *
 * Without this wrapper fn, to get correct type, `routeParams([["user_id", number()]])` would need to be written as:
 * `[["user_id", number()]] as const satisfies RouteParams_T`
 */
declare const routeParams: <const T extends RouteParams_T>(params: T) => T;

export { type RouteConfig_T, type RouteParamsOutput_T, route, routeParams, routes };
