/**
 * External dependencies
 */
import type { combineReducers as reduxCombineReducers, Store as ReduxStore } from 'redux';
/**
 * Internal dependencies
 */
import type { DataEmitter } from './utils/emitter';
import type { MetadataSelectors, MetadataActions } from './redux-store/metadata/types';
type MapOf<T> = {
    [name: string]: T;
};
export type ActionCreator = (...args: any[]) => any | Generator;
export type Resolver = Function | Generator;
export type Selector = Function;
export type AnyConfig = ReduxStoreConfig<any, any, any>;
export interface StoreInstance<Config extends AnyConfig> {
    getSelectors: () => SelectorsOf<Config>;
    getActions: () => ActionCreatorsOf<Config>;
    subscribe: (listener: () => void) => () => void;
}
export interface StoreDescriptor<Config extends AnyConfig = AnyConfig> {
    /**
     * Store Name
     */
    name: string;
    /**
     * Creates a store instance
     */
    instantiate: (registry: DataRegistry) => StoreInstance<Config>;
}
export interface ReduxStoreConfig<State, ActionCreators, Selectors> {
    initialState?: State;
    reducer: (state: any, action: any) => any;
    actions?: ActionCreators;
    resolvers?: MapOf<Resolver>;
    selectors?: Selectors;
    controls?: MapOf<Function>;
}
export type UseSelectReturn<F extends MapSelect | StoreDescriptor<any>> = F extends MapSelect ? ReturnType<F> : F extends StoreDescriptor<any> ? CurriedSelectorsOf<F> : never;
export type UseDispatchReturn<StoreNameOrDescriptor> = StoreNameOrDescriptor extends StoreDescriptor<any> ? ActionCreatorsOf<StoreNameOrDescriptor> : StoreNameOrDescriptor extends undefined ? DispatchFunction : any;
export type DispatchFunction = <StoreNameOrDescriptor>(store: StoreNameOrDescriptor) => DispatchReturn<StoreNameOrDescriptor>;
export type DispatchReturn<StoreNameOrDescriptor> = StoreNameOrDescriptor extends StoreDescriptor<any> ? ActionCreatorsOf<StoreNameOrDescriptor> : unknown;
export type MapSelect = (select: SelectFunction, registry: DataRegistry) => any;
export type SelectFunction = <S>(store: S) => CurriedSelectorsOf<S>;
/**
 * Callback for store's `subscribe()` method that
 * runs when the store data has changed.
 */
export type ListenerFunction = () => void;
export type CurriedSelectorsOf<S> = S extends StoreDescriptor<ReduxStoreConfig<any, any, infer Selectors>> ? {
    [key in keyof Selectors]: CurriedState<Selectors[key]>;
} & MetadataSelectors<S> : never;
/**
 * Like CurriedState but wraps the return type in a Promise.
 * Used for resolveSelect where selectors return promises.
 *
 * For generic selectors that define PromiseCurriedSignature, that signature
 * is used directly to preserve generic type parameters (which would otherwise
 * be lost when using `infer`).
 */
type CurriedStateWithPromise<F> = F extends SelectorWithCustomCurrySignature & {
    PromiseCurriedSignature: infer S;
} ? S : F extends SelectorWithCustomCurrySignature & {
    CurriedSignature: (...args: infer P) => infer R;
} ? (...args: P) => Promise<R> : F extends (state: any, ...args: infer P) => infer R ? (...args: P) => Promise<R> : F;
/**
 * Like CurriedSelectorsOf but each selector returns a Promise.
 * Used for resolveSelect.
 */
export type CurriedSelectorsResolveOf<S> = S extends StoreDescriptor<ReduxStoreConfig<any, any, infer Selectors>> ? {
    [key in keyof Selectors]: CurriedStateWithPromise<Selectors[key]>;
} : never;
/**
 * Removes the first argument from a function.
 *
 * By default, it removes the `state` parameter from
 * registered selectors since that argument is supplied
 * by the editor when calling `select(…)`.
 *
 * For functions with no arguments, which some selectors
 * are free to define, returns the original function.
 *
 * It is possible to manually provide a custom curried signature
 * and avoid the automatic inference. When the
 * F generic argument passed to this helper extends the
 * SelectorWithCustomCurrySignature type, the F['CurriedSignature']
 * property is used verbatim.
 *
 * This is useful because TypeScript does not correctly remove
 * arguments from complex function signatures constrained by
 * interdependent generic parameters.
 * For more context, see https://github.com/WordPress/gutenberg/pull/41578
 */
type CurriedState<F> = F extends SelectorWithCustomCurrySignature ? F['CurriedSignature'] : F extends (state: any, ...args: infer P) => infer R ? (...args: P) => R : F;
/**
 * Utility to manually specify curried selector signatures.
 *
 * It comes handy when TypeScript can't automatically produce the
 * correct curried function signature. For example:
 *
 * ```ts
 * type BadlyInferredSignature = CurriedState<
 *     <K extends string | number>(
 *         state: any,
 *         kind: K,
 *         key: K extends string ? 'one value' : false
 *     ) => K
 * >
 * // BadlyInferredSignature evaluates to:
 * // (kind: string number, key: false "one value") => string number
 * ```
 *
 * With SelectorWithCustomCurrySignature, we can provide a custom
 * signature and avoid relying on TypeScript inference:
 * ```ts
 * interface MySelectorSignature extends SelectorWithCustomCurrySignature {
 *     <K extends string | number>(
 *         state: any,
 *         kind: K,
 *         key: K extends string ? 'one value' : false
 *     ): K;
 *
 *     CurriedSignature: <K extends string | number>(
 *         kind: K,
 *         key: K extends string ? 'one value' : false
 *     ): K;
 * }
 * type CorrectlyInferredSignature = CurriedState<MySelectorSignature>
 * // <K extends string | number>(kind: K, key: K extends string ? 'one value' : false): K;
 *
 * For even more context, see https://github.com/WordPress/gutenberg/pull/41578
 * ```
 */
export interface SelectorWithCustomCurrySignature {
    CurriedSignature: Function;
    PromiseCurriedSignature?: Function;
}
/**
 * A store name or store descriptor, used throughout the API.
 */
export type StoreNameOrDescriptor = string | StoreDescriptor;
/**
 * An isolated orchestrator of store registrations.
 *
 * Returned by `createRegistry`. Provides methods to register stores,
 * select data, dispatch actions, and subscribe to changes.
 */
export interface DataRegistry {
    batch: (callback: () => void) => void;
    stores: Record<string, InternalStoreInstance>;
    namespaces: Record<string, InternalStoreInstance>;
    subscribe: (listener: ListenerFunction, storeNameOrDescriptor?: StoreNameOrDescriptor) => () => void;
    select: {
        <S extends StoreDescriptor<any>>(store: S): CurriedSelectorsOf<S>;
        (store: StoreNameOrDescriptor): Record<string, (...args: any[]) => any>;
    };
    resolveSelect: {
        <S extends StoreDescriptor<any>>(store: S): CurriedSelectorsResolveOf<S>;
        (store: StoreNameOrDescriptor): Record<string, (...args: any[]) => Promise<any>>;
    };
    suspendSelect: {
        <S extends StoreDescriptor<any>>(store: S): CurriedSelectorsOf<S>;
        (store: StoreNameOrDescriptor): Record<string, (...args: any[]) => any>;
    };
    dispatch: {
        <S extends StoreDescriptor<any>>(store: S): ActionCreatorsOf<S>;
        (store: StoreNameOrDescriptor): Record<string, (...args: any[]) => any>;
    };
    use: (plugin: DataPlugin, options?: Record<string, unknown>) => DataRegistry;
    register: (store: StoreDescriptor<any>) => void;
    registerGenericStore: (name: string, store: StoreInstance<AnyConfig>) => void;
    registerStore: (storeName: string, options: ReduxStoreConfig<any, any, any>) => ReduxStore;
    __unstableMarkListeningStores: <T>(callback: () => T, ref: {
        current: string[] | null;
    }) => T;
}
/**
 * The plugin function signature.
 */
export type DataPlugin = (registry: DataRegistry, options?: Record<string, unknown>) => Partial<DataRegistry>;
/**
 * Status of a selector resolution.
 */
export type ResolutionStatus = 'resolving' | 'finished' | 'error';
/**
 * State value for a single resolution.
 */
export type ResolutionState = {
    status: 'resolving';
} | {
    status: 'finished';
} | {
    status: 'error';
    error: Error | unknown;
};
/**
 * A normalized resolver with a `fulfill` method and optional `isFulfilled`.
 */
export interface NormalizedResolver {
    /**
     * The function to call to fulfill the resolver.
     */
    fulfill: (...args: any[]) => any;
    /**
     * Optional function to check if the resolver is already fulfilled.
     */
    isFulfilled?: (state: any, ...args: any[]) => boolean;
    /**
     * Optional function to check if the resolver should be invalidated.
     */
    shouldInvalidate?: (action: any, ...args: any[]) => boolean;
}
/**
 * A bound selector with optional resolver metadata.
 */
export interface BoundSelector {
    (...args: any[]): any;
    /**
     * Whether this selector has a resolver attached.
     */
    hasResolver: boolean;
    /**
     * Optional function to normalize the arguments.
     */
    __unstableNormalizeArgs?: (args: any[]) => any[];
    /**
     * Whether this selector is a registry selector.
     */
    isRegistrySelector?: boolean;
    /**
     * The registry instance this selector is bound to.
     */
    registry?: DataRegistry;
}
/**
 * The shape of a store instance as seen internally by the registry.
 * Extends the public StoreInstance with additional internal properties.
 */
export interface InternalStoreInstance<Config extends AnyConfig = AnyConfig> extends StoreInstance<Config> {
    /**
     * The Redux store instance (only for Redux-based stores).
     */
    store?: ReduxStore;
    /**
     * The internal emitter for pause/resume batching.
     */
    emitter: DataEmitter;
    /**
     * The combined reducer.
     */
    reducer?: (state: any, action: any) => any;
    /**
     * Bound actions object.
     */
    actions?: Record<string, ActionCreator>;
    /**
     * Bound selectors object.
     */
    selectors?: Record<string, Selector>;
    /**
     * Resolver definitions.
     */
    resolvers?: Record<string, NormalizedResolver>;
    /**
     * Returns resolve-wrapped selectors.
     */
    getResolveSelectors?: () => Record<string, (...args: any[]) => Promise<any>>;
    /**
     * Returns suspense-wrapped selectors.
     */
    getSuspendSelectors?: () => Record<string, (...args: any[]) => any>;
}
/**
 * Control descriptor for the controls system.
 */
export interface ControlDescriptor {
    /**
     * The type of the control action.
     */
    type: string;
    /**
     * The store key to target.
     */
    storeKey: string;
    /**
     * The name of the selector (for select/resolveSelect controls).
     */
    selectorName?: string;
    /**
     * The name of the action (for dispatch controls).
     */
    actionName?: string;
    /**
     * Arguments for the selector or action.
     */
    args: any[];
}
/**
 * Storage interface (Web Storage API subset).
 */
export interface StorageInterface {
    getItem: (key: string) => string | null;
    setItem: (key: string, value: string) => void;
    removeItem?: (key: string) => void;
    clear?: VoidFunction;
}
export type ConfigOf<S> = S extends StoreDescriptor<infer C> ? C : never;
export type ActionCreatorsOf<T> = T extends StoreDescriptor<ReduxStoreConfig<any, infer ActionCreators, any>> ? PromisifiedActionCreators<ActionCreators> & MetadataActions<T> : T extends ReduxStoreConfig<any, infer ActionCreators, any> ? PromisifiedActionCreators<ActionCreators> : never;
export type PromisifiedActionCreators<ActionCreators> = {
    [Action in keyof ActionCreators]: ActionCreators[Action] extends ActionCreator ? PromisifyActionCreator<ActionCreators[Action]> : ActionCreators[Action];
};
export type PromisifyActionCreator<Action extends ActionCreator> = (...args: Parameters<Action>) => Promise<ReturnType<Action> extends (..._args: any[]) => any ? ThunkReturnType<Action> : ReturnType<Action> extends Generator<any, infer TReturn, any> ? TReturn : ReturnType<Action>>;
export type ThunkReturnType<Action extends ActionCreator> = Awaited<ReturnType<ReturnType<Action>>>;
type SelectorsOf<Config extends AnyConfig> = Config extends ReduxStoreConfig<any, any, infer Selectors> ? {
    [name in keyof Selectors]: Function;
} : never;
/**
 * The argument object passed to every thunk function. When parameterized with
 * a store descriptor, `dispatch`, `select`, and `resolveSelect` are fully
 * typed against that store's actions and selectors.
 *
 * @example
 * ```ts
 * const myAction =
 *     ( id: number ) =>
 *     async ( { dispatch, select }: ThunkArgs< typeof myStore > ) => {
 *         const record = select.getRecord( id );
 *         dispatch.setLoading( true );
 *     };
 * ```
 */
export interface ThunkArgs<S extends StoreDescriptor = StoreDescriptor, PrivateSelectors extends Record<string, Function> = {}, PrivateActions extends Record<string, ActionCreator> = {}> {
    dispatch: ActionCreatorsOf<S> & PromisifiedActionCreators<PrivateActions> & {
        <R>(thunk: (...args: any[]) => R): R;
        (action: Record<string, unknown>): unknown;
    };
    select: CurriedSelectorsOf<S> & {
        [key in keyof PrivateSelectors]: CurriedState<PrivateSelectors[key]>;
    };
    resolveSelect: CurriedSelectorsResolveOf<S>;
    registry: DataRegistry;
}
export type combineReducers = typeof reduxCombineReducers;
export {};
//# sourceMappingURL=types.d.ts.map