import { RouteObject, HydrationState, createMemoryRouter } from 'react-router';
import React from 'react';

/**
 * SetDifference (same as Exclude)
 * @desc Set difference of given union types `A` and `B`
 * @example
 *   // Expect: "1"
 *   SetDifference<'1' | '2' | '3', '2' | '3' | '4'>;
 *
 *   // Expect: string | number
 *   SetDifference<string | number | (() => void), Function>;
 */
declare type SetDifference<A, B> = A extends B ? never : A;
/**
 * Intersection
 * @desc From `T` pick properties that exist in `U`
 * @example
 *   type Props = { name: string; age: number; visible: boolean };
 *   type DefaultProps = { age: number };
 *
 *   // Expect: { age: number; }
 *   type DuplicateProps = Intersection<Props, DefaultProps>;
 */
declare type Intersection<T extends object, U extends object> = Pick<T, Extract<keyof T, keyof U> & Extract<keyof U, keyof T>>;
/**
 * Diff
 * @desc From `T` remove properties that exist in `U`
 * @example
 *   type Props = { name: string; age: number; visible: boolean };
 *   type DefaultProps = { age: number };
 *
 *   // Expect: { name: string; visible: boolean; }
 *   type DiffProps = Diff<Props, DefaultProps>;
 */
declare type Diff<T extends object, U extends object> = Pick<T, SetDifference<keyof T, keyof U>>;
/**
 * Overwrite
 * @desc From `U` overwrite properties to `T`
 * @example
 *   type Props = { name: string; age: number; visible: boolean };
 *   type NewProps = { age: string; other: string };
 *
 *   // Expect: { name: string; age: string; visible: boolean; }
 *   type ReplacedProps = Overwrite<Props, NewProps>;
 */
declare type Overwrite<T extends object, U extends object, I = Diff<T, U> & Intersection<U, T>> = Pick<I, keyof I>;

type Merge<T, Deep = false> = {
    [K in keyof T]: Deep extends true ? (T extends object ? Merge<T[K], true> : T[K]) : T[K];
} & {};

type FutureConfigRouter = Exclude<Parameters<typeof createMemoryRouter>[1], undefined>['future'];
type RouterParameters = {
    hydrationData?: HydrationState;
    routing?: string | RouterRoute | [RouterRoute, ...RouterRoute[]];
    future?: Partial<NonNullable<FutureConfigRouter>>;
    fallback?: React.JSX.Element;
};
type LocationParameters<PathParams extends Record<string, string | number> = Record<string, string | number>> = {
    path?: string | ((inferredPath: string, pathParams: PathParams) => string | undefined);
    pathParams?: PathParams;
    searchParams?: ConstructorParameters<typeof URLSearchParams>[0];
    hash?: string;
    state?: unknown;
};
type NavigationHistoryEntry = LocationParameters & {
    isInitialLocation?: boolean;
};
type RouterRoute = Overwrite<RouteObject, {
    children?: RouterRoute[];
}> & StoryRouteIdentifier;
type RouteDefinition = React.ReactElement | RouteDefinitionObject;
type NonIndexRouteDefinition = React.ReactElement | NonIndexRouteDefinitionObject;
type RouteDefinitionObject = Merge<Omit<RouteObject, 'children'> & StoryRouteIdentifier>;
type NonIndexRouteDefinitionObject = RouteDefinitionObject & {
    index?: false;
};
type StoryRouteIdentifier = {
    useStoryElement?: boolean;
};
type RoutingHelper = (...args: never[]) => [RouterRoute, ...RouterRoute[]];

export type { LocationParameters as L, NavigationHistoryEntry as N, RouterRoute as R, RouterParameters as a, NonIndexRouteDefinitionObject as b, RouteDefinition as c, RouteDefinitionObject as d, NonIndexRouteDefinition as e, RoutingHelper as f };
