import { PathnameType, SearchType, StateType, HashType } from "../types/index.js";
type Route<TSpec extends RouteSpec = RouteSpec, TChildren = {}> = RouteApi<TSpec> & RouteChildren<TSpec, TChildren> & {
    $: RouteChildren<OmitPath<TSpec>, TChildren>;
};
type RouteChildren<TSpec extends RouteSpec, TChildren> = {
    [TKey in keyof TChildren]: TChildren[TKey] extends Route<infer TChildOptions, infer TChildChildren> ? Route<MergeRouteSpecList<[TSpec, TChildOptions], "inherit">, TChildChildren> : TChildren[TKey];
};
type PathPattern<TPath extends PathConstraint> = {
    <TRelative extends boolean = false>(opts?: {
        relative?: TRelative;
    }): TRelative extends true ? PathWithoutIntermediateStars<TPath> : AbsolutePath<TPath>;
};
interface RouteApi<TSpec extends RouteSpec = RouteSpec> {
    $path: PathPattern<TSpec["path"]>;
    $buildPath: (opts: BuildPathOptions<TSpec>) => string;
    $buildPathname: (opts: BuildPathnameOptions<TSpec>) => string;
    $buildSearch: (opts: BuildSearchOptions<TSpec>) => string;
    $buildHash: (opts: BuildHashOptions<TSpec>) => string;
    $buildState: (opts: BuildStateOptions<TSpec>) => PlainState<TSpec["state"]>;
    $serializeParams: (opts: SerializePathnameParamsOptions<TSpec>) => PathnameParams;
    $serializeSearchParams: (opts: BuildSearchOptions<TSpec>) => URLSearchParams;
    $deserializeParams: (params: PathnameParams) => OutPathnameParams<TSpec>;
    $deserializeSearchParams: (searchParams: URLSearchParams) => OutSearchParams<TSpec>;
    $deserializeHash: (hash: string) => OutHash<TSpec>;
    $deserializeState: (state: unknown) => OutState<TSpec>;
    $spec: TSpec;
}
type PathnameParams = Record<string, string | undefined>;
type BuildPathOptions<TSpec extends RouteSpec> = Readable<InPathParams<TSpec> & PathnameBuilderOptions & SearchBuilderOptions>;
type BuildPathnameOptions<TSpec extends RouteSpec> = Readable<SerializePathnameParamsOptions<TSpec> & PathnameBuilderOptions>;
type SerializePathnameParamsOptions<TSpec extends RouteSpec> = {
    params: InPathnameParams<TSpec>;
};
type BuildSearchOptions<TSpec extends RouteSpec> = Readable<{
    searchParams: InSearchParams<TSpec>;
} & SearchBuilderOptions>;
type BuildHashOptions<TSpec extends RouteSpec> = Readable<{
    hash: InHash<TSpec>;
}>;
type BuildStateOptions<TSpec extends RouteSpec> = Readable<{
    state: InState<TSpec>;
} & StateBuilderOptions>;
interface PathnameBuilderOptions {
    relative?: boolean;
}
interface SearchBuilderOptions {
    untypedSearchParams?: URLSearchParams | undefined;
}
interface StateBuilderOptions {
    untypedState?: unknown;
}
type PlainState<TState extends StateConstraint> = TState extends StateObjectConstraint ? Record<string, unknown> : unknown;
type InPathParams<TSpec extends RouteSpec> = Readable<(PathnameParamsRequired<InPathnameParams<TSpec>> extends true ? {
    params: InPathnameParams<TSpec>;
} : {
    params?: InPathnameParams<TSpec>;
}) & {
    searchParams?: InSearchParams<TSpec>;
    hash?: InHash<TSpec>;
}>;
type PathnameParamsRequired<T> = Partial<T> extends T ? (IsAny<T> extends true ? true : false) : true;
type InPathnameParams<TSpec extends RouteSpec> = Merge<InferredPathnameParams<TSpec["path"]>, TSpec["params"]> extends infer TResolvedPathnameParams ? TResolvedPathnameParams extends PathnameParamsConstraint ? IsAny<TResolvedPathnameParams> extends true ? any : Merge<Pick<RawParams<TResolvedPathnameParams, "in">, PathParam<TSpec["path"], "all", "in">>, PartialWithUndefined<Pick<RawParams<TResolvedPathnameParams, "in">, PathParam<TSpec["path"], "optional", "in">>>> : never : never;
type OutPathnameParams<TSpec extends RouteSpec> = Merge<InferredPathnameParams<TSpec["path"]>, TSpec["params"]> extends infer TResolvedPathnameParams ? TResolvedPathnameParams extends PathnameParamsConstraint ? Readable<UndefinedToPartial<undefined extends TSpec["path"] ? RawParams<TResolvedPathnameParams, "out"> : Pick<RawParams<TResolvedPathnameParams, "out">, PathParam<TSpec["path"]>>>> : never : never;
type InSearchParams<TSpec extends RouteSpec> = IsAny<TSpec["searchParams"]> extends true ? any : Readable<PartialWithUndefined<RawSearchParams<TSpec["searchParams"], "in">>>;
type OutSearchParams<TSpec extends RouteSpec> = Readable<UndefinedToPartial<RawSearchParams<TSpec["searchParams"], "out">>>;
type InHash<TSpec extends RouteSpec> = RawHash<TSpec["hash"], "in">;
type OutHash<TSpec extends RouteSpec> = RawHash<TSpec["hash"], "out">;
type InState<TSpec extends RouteSpec> = IsAny<TSpec["state"]> extends true ? any : TSpec["state"] extends StateObjectConstraint ? Readable<PartialWithUndefined<RawStateParams<TSpec["state"], "in">>> : TSpec["state"] extends StateUnknownConstraint ? RawState<TSpec["state"], "in"> : never;
type OutState<TSpec extends RouteSpec> = TSpec["state"] extends StateObjectConstraint ? Readable<UndefinedToPartial<RawStateParams<TSpec["state"], "out">>> : TSpec["state"] extends StateUnknownConstraint ? RawState<TSpec["state"], "out"> : never;
type InferredPathnameParams<TPath extends PathConstraint> = Merge<Record<PathParam<TPath>, PathnameType<string>>, Record<PathParam<TPath, "optional">, PathnameType<string | undefined>>>;
type RawParams<TPathnameParams extends PathnameParamsConstraint, TMode extends "in" | "out"> = {
    [TKey in keyof TPathnameParams]: TPathnameParams[TKey] extends PathnameType<infer TOut, infer TIn> ? TMode extends "in" ? Exclude<TIn, undefined> : TOut : never;
};
type RawSearchParams<TSearchParams extends SearchParamsConstraint, TMode extends "in" | "out"> = {
    [TKey in keyof TSearchParams]: TSearchParams[TKey] extends SearchType<infer TOut, infer TIn> ? TMode extends "in" ? Exclude<TIn, undefined> : TOut : never;
};
type RawState<TState extends StateUnknownConstraint, TMode extends "in" | "out"> = TState extends StateType<infer TOut, infer TIn> ? TMode extends "in" ? Exclude<TIn, undefined> : TOut : never;
type RawHash<THash, TMode extends "in" | "out"> = THash extends string[] ? TMode extends "in" ? [THash[number]] extends [never] ? undefined : THash[number] : THash[number] | undefined : THash extends HashType<infer TOut, infer TIn> ? TMode extends "in" ? Exclude<TIn, undefined> : TOut : undefined;
type RawStateParams<TState extends StateObjectConstraint, TMode extends "in" | "out"> = {
    [TKey in keyof TState]: TState[TKey] extends StateType<infer TOut, infer TIn> ? TMode extends "in" ? Exclude<TIn, undefined> : TOut : never;
};
type AbsolutePath<T extends PathConstraint> = T extends string ? `/${T}` : T;
type PathWithoutIntermediateStars<T extends PathConstraint> = T extends `${infer TStart}*?/${infer TEnd}` ? PathWithoutIntermediateStars<`${TStart}${TEnd}`> : T extends `${infer TStart}*/${infer TEnd}` ? PathWithoutIntermediateStars<`${TStart}${TEnd}`> : T;
type SanitizePath<T> = T extends `/${string}` ? ErrorMessage<"Leading slashes are forbidden"> : T extends `${string}/` ? ErrorMessage<"Trailing slashes are forbidden"> : T extends `${string}*?${string}` ? ErrorMessage<"Splats can't be optional"> : T;
type SanitizeRouteChildren<T> = Readable<{
    [TKey in keyof T]: TKey extends Omit$<TKey> ? T[TKey] extends RouteApi ? T[TKey] : RouteApi : ErrorMessage<"Name can't start with $">;
}>;
type SanitizePathnameTypes<TPath extends PathConstraint, TPathnameParams> = {
    [TKey in keyof TPathnameParams]: TKey extends PathParam<TPath> ? TPathnameParams[TKey] extends undefined ? PathnameType<any> : TPathnameParams[TKey] : ErrorMessage<"There is no such param in path">;
};
type Omit$<T> = T extends `$${infer TValid}` ? TValid : T;
type PathParam<TPath extends PathConstraint, TKind extends "all" | "optional" = "all", TMode extends "in" | "out" = "out"> = string extends TPath ? never : TPath extends `${infer TBefore}*${infer TAfter}` ? ExtractPathParam<"*", TKind, TMode, TAfter extends "" ? true : false> | PathParam<TBefore, TKind, TMode> | PathParam<TAfter, TKind, TMode> : TPath extends `${infer _TStart}:${infer TParam}/${infer TRest}` ? ExtractPathParam<TParam, TKind, TMode> | PathParam<TRest, TKind, TMode> : TPath extends `${infer _TStart}:${infer TParam}` ? ExtractPathParam<TParam, TKind, TMode> : never;
type ExtractPathParam<TRawParam extends string, TKind extends "all" | "optional" = "all", TMode extends "in" | "out" = "out", TEnd extends boolean = false> = TRawParam extends `${infer TParam}?` ? OmitIllegalStar<TParam, TMode, TEnd> : TKind extends "optional" ? TRawParam extends "*" ? TMode extends "in" ? OmitIllegalStar<TRawParam, TMode, TEnd> : never : never : OmitIllegalStar<TRawParam, TMode, TEnd>;
type OmitIllegalStar<TParam extends string, TMode extends "in" | "out" = "out", TEnd extends boolean = false> = TParam extends "*" ? (TMode extends "in" ? (TEnd extends false ? never : TParam) : TParam) : TParam;
type RouteOptions<TPath extends PathConstraint = undefined, TPathnameParams extends Partial<Record<PathParam<TPath>, PathnameType<any>>> = Partial<Record<PathParam<TPath>, PathnameType<any>>>, TSearchParams extends SearchParamsConstraint = {}, THashString extends string = string, THash extends HashConstraint<THashString> = [], TState extends StateConstraint = {}, TComposedRoutes extends [...RouteApi<RouteSpec<undefined>>[]] = [], TChildren = {}> = {
    /**
     * A path pattern, just like in React Router. The only difference is that leading and trailing slashes are
     * forbidden.
     */
    path?: SanitizePath<TPath>;
    /**
     * Pathname params. Use a record of types to override params
     * inferred from `path`, partially or completely:
     *
     * ```ts
     * params: { id: number() }
     * ```
     *
     * If there is no `path`, you can specify any params.
     *
     * */
    params?: TPath extends undefined ? PathnameParamsConstraint : SanitizePathnameTypes<TPath, TPathnameParams>;
    /**
     * Search params. Use a record of types to define them:
     *
     * ```ts
     * searchParams: { page: number() }
     * ```
     * */
    searchParams?: TSearchParams;
    /**
     * Hash. Use a type to define it:
     *
     * ```ts
     * hash: union(["info", "stats"])
     * ```
     *
     * If you want to extend it in a child route, specify it as an array of string values instead:
     *
     * ```ts
     * hash: ["info", "stats"]
     * ```
     */
    hash?: THash;
    /**
     * State. Use a record of types to define it:
     *
     * ```ts
     * state: { expired: boolean() }
     * ```
     *
     * As an escape hatch, you can use a single type (not recommended):
     *
     * ```ts
     * state: boolean()
     * ```
     */
    state?: TState;
    /** An array of pathless routes whose params will be composed into the route. */
    compose?: [...TComposedRoutes];
    /** Child routes that will inherit all params. */
    children?: SanitizeRouteChildren<TChildren>;
};
interface RouteSpec<TPath extends PathConstraint = PathConstraint, TPathnameParams extends PathnameParamsConstraint = any, TSearchParams extends SearchParamsConstraint = any, THash extends HashConstraint = HashConstraint, TState extends StateConstraint = any> {
    path: TPath;
    params: TPathnameParams;
    searchParams: TSearchParams;
    hash: THash;
    state: TState;
}
type PathConstraint = string | undefined;
type PathnameParamsConstraint = Record<string, PathnameType<any>>;
type SearchParamsConstraint = Record<string, SearchType<any>>;
type StateConstraint = StateObjectConstraint | StateUnknownConstraint;
type StateObjectConstraint = Record<string, StateType<any>>;
type StateUnknownConstraint = StateType<any>;
type HashConstraint<T extends string = string> = T[] | HashType<any>;
type ExtractRouteSpecList<TTuple extends [...RouteApi[]]> = {
    [TIndex in keyof TTuple]: TTuple[TIndex]["$spec"];
};
type MergeRouteSpecList<T extends RouteSpec[], TMode extends "inherit" | "compose"> = T extends [
    infer TFirst,
    infer TSecond,
    ...infer TRest
] ? TRest extends RouteSpec[] ? MergeRouteSpecList<[MergeRouteSpecPair<TFirst, TSecond, TMode>, ...TRest], TMode> : never : T extends [infer TFirst] ? TFirst extends RouteSpec ? TFirst : never : never;
type MergeRouteSpecPair<T, U, TMode extends "inherit" | "compose"> = T extends RouteSpec<infer TPath, infer TPathnameParams, infer TSearchParams, infer THash, infer TState> ? U extends RouteSpec<infer TChildPath, infer TChildPathnameParams, infer TChildSearchParams, infer TChildHash, infer TChildState> ? RouteSpec<TMode extends "inherit" ? StringPath<TPath> extends "" ? TChildPath : StringPath<TChildPath> extends "" ? TPath : `${TPath}/${TChildPath}` : TChildPath, Merge<TPathnameParams, TChildPathnameParams>, Merge<TSearchParams, TChildSearchParams>, TChildHash extends string[] ? (THash extends string[] ? [...THash, ...TChildHash] : THash) : TChildHash, TChildState extends StateObjectConstraint ? TState extends StateObjectConstraint ? Merge<TState, TChildState> : TState : TChildState> : never : never;
type StringPath<T extends PathConstraint> = T extends undefined ? "" : T;
type OmitPath<T extends RouteSpec> = T extends RouteSpec<infer _TPath, infer TPathnameParams, infer TSearchParams, infer THash, infer TState> ? RouteSpec<"", TPathnameParams, TSearchParams, THash, TState> : never;
type Merge<T, U> = Readable<Omit<T, keyof U> & U>;
type Readable<T> = T extends object ? (T extends infer O ? {
    [K in keyof O]: O[K];
} : never) : T;
type ErrorMessage<T extends string> = T & {
    [brand]: ErrorMessage<T>;
};
declare const brand: unique symbol;
type IsAny<T> = 0 extends 1 & T ? true : false;
type UndefinedToPartial<T> = Merge<T, Undefined<T>>;
type Undefined<T> = {
    [K in keyof T as undefined extends T[K] ? K : never]?: Exclude<T[K], undefined>;
};
type PartialWithUndefined<T> = {
    [K in keyof T]?: T[K] | undefined;
};
type NormalizePathnameParams<TPathnameParams, TPath extends PathConstraint> = Partial<Record<PathParam<TPath>, PathnameType<any>>> extends TPathnameParams ? {} : Readable<RequiredWithoutUndefined<TPathnameParams>>;
type RequiredWithoutUndefined<T> = {
    [P in keyof T]-?: Exclude<T[P], undefined>;
};
declare function route<TPath extends PathConstraint = undefined, TPathnameParams extends Partial<Record<PathParam<TPath>, PathnameType<any>>> = Partial<Record<PathParam<TPath>, PathnameType<any>>>, TSearchParams extends SearchParamsConstraint = {}, THashString extends string = string, THash extends HashConstraint<THashString> = [], TState extends StateConstraint = {}, TComposedRoutes extends [...RouteApi<RouteSpec<undefined>>[]] = [], TChildren = {}>(opts: RouteOptions<TPath, TPathnameParams, TSearchParams, THashString, THash, TState, TComposedRoutes, TChildren>): Route<MergeRouteSpecList<[
    ...ExtractRouteSpecList<TComposedRoutes>,
    RouteSpec<TPath, NormalizePathnameParams<TPathnameParams, TPath>, TSearchParams, THash, TState>
], "compose">, SanitizeRouteChildren<TChildren>>;
export { route, RouteOptions, Route, RouteApi, RouteChildren, RouteSpec, MergeRouteSpecList, PathParam, SanitizePath, SanitizeRouteChildren, InPathParams, InPathnameParams, OutPathnameParams, InSearchParams, OutSearchParams, InHash, OutHash, InState, OutState, ErrorMessage, };
