import { AbsolutePath, CancellablePromise, DisplayStatus, FormManager, Path, Schema, SealedFormManagerEvent, SealedLocatedValidationIssue, SealedValidationIssue, SealedValueEvent, StateEvent, ValidationStatus } from "@kform/core";
/**
 * Options available to the {@link useController} hook.
 */
export interface ControllerOptions<T = unknown, TState extends ControllerState<T> = ControllerState<T>> {
    /**
     * Required if no form context is in scope.
     *
     * If a form context is in scope and this value is also provided, then the
     * provided form manager will be used, in which case the current path of the
     * form context is ignored.
     */
    formManager?: FormManager;
    /**
     * Whether to enable the controller.
     *
     * @default true
     */
    enabled?: boolean;
    /**
     * Default extra state.
     * @internal
     */
    _defaultState?: Partial<TState>;
    /**
     * Function called once the controller has been initialised.
     *
     * @param info Controller's info.
     */
    onInitialized?: (state: TState & InitializedControllerState<T>) => void | PromiseLike<void>;
    /**
     * Function called whenever the controller is uninitialised.
     */
    onUninitialized?: (state: TState & UninitializedControllerState<T>) => void;
    /**
     * Function called whenever an event matching the controller's path is
     * emitted.
     *
     * @param event Form manager event.
     */
    onFormManagerEvent?: (event: SealedFormManagerEvent, state: TState & InitializedControllerState<T>) => void | PromiseLike<void>;
    onValueChange?: (event: SealedValueEvent, state: TState & InitializedControllerState<T>) => void | PromiseLike<void>;
    onValidationStatusChange?: (event: StateEvent.ValidationChange, state: TState & InitializedControllerState<T>) => void | PromiseLike<void>;
    onDisplayStatusChange?: (event: StateEvent.DisplayChange, state: TState & InitializedControllerState<T>) => void | PromiseLike<void>;
    onDirtyStatusChange?: (event: StateEvent.DirtyChange, state: TState & InitializedControllerState<T>) => void | PromiseLike<void>;
    onTouchedStatusChange?: (event: StateEvent.TouchedChange, state: TState & InitializedControllerState<T>) => void | PromiseLike<void>;
}
/**
 * Controller for a value of the form.
 */
export interface Controller<T = unknown, TState extends ControllerState<T> = ControllerState<T>> {
    /**
     * Returns the current state of the controller.
     */
    readonly getState: () => TState;
    /**
     * Sets the (non-private) state of the controller.
     * @param state State to set.
     * @internal
     */
    readonly _setState: (state: Partial<TState> | ((state: TState) => Partial<TState>)) => void;
    /**
     * Subscribes to changes in the controller's state.
     *
     * @param selector Selector used to select which part of the controller's
     * state to observe.
     * @param listener Function called whenever the selected state changes.
     * @param options Subscription options.
     * @returns Function which should be called to unsubscribe.
     */
    readonly subscribe: <TSelected = unknown>(selector: (state: TState) => TSelected, listener: (selectedState: TSelected, prevSelectedState: TSelected | undefined) => void, options?: ControllerSubscriptionOptions<TSelected>) => () => void;
    /**
     * Hook used to select part of the controller's state.
     *
     * A component using this hook is re-rendered whenever said part of the state
     * changes.
     * @param selector Selector used to select part of the controller's state.
     */
    readonly useState: (() => TState) & (<TResult = unknown>(selector: (state: TState) => TResult, options?: ControllerUseStateOptions<TResult>) => TResult);
    /**
     * Hook which returns the form manager being used by the controller.
     */
    readonly useFormManager: () => FormManager;
    /**
     * Hook which returns the schema of the value being controlled.
     */
    readonly useSchema: () => Schema<T>;
    /**
     * Hook which returns the path of the value being controlled by this
     * controller.
     *
     * This path will not contain any provided recursive wildcards.
     */
    readonly usePath: () => AbsolutePath;
    /**
     * Hook which returns the schema path of the value being controlled.
     */
    readonly useSchemaPath: () => AbsolutePath;
    /**
     * Hook which returns whether the controller is currently observing
     * descendants.
     */
    readonly useObservingDescendants: () => boolean;
    /**
     * Hook which returns whether the controller has been initialised.
     */
    readonly useInitialized: () => boolean;
    /**
     * Hook which returns whether a value exists at the path being controlled.
     *
     * Returns `undefined` when the controller is not initialised.
     */
    readonly useExists: () => boolean | undefined;
    /**
     * Hook which returns the form value being controlled.
     *
     * Note that, when observing descendants, this hook will cause a component to
     * rerender when a descendant is changed, even if the identity of the value
     * hasn't changed.
     *
     * Returns `undefined` when the controller is not initialised.
     */
    readonly useValue: () => T | undefined;
    /**
     * Hook which returns whether the value being controlled is dirty.
     *
     * Returns `undefined` when the controller is not initialised.
     */
    readonly useDirty: () => boolean | undefined;
    /**
     * Hook which returns whether the value being controlled is touched.
     *
     * Returns `undefined` when the controller is not initialised.
     */
    readonly useTouched: () => boolean | undefined;
    /**
     * Hook which returns the issues of the value being controlled.
     *
     * Returns `undefined` when the controller is not initialised.
     */
    readonly useIssues: () => SealedValidationIssue[] | undefined;
    /**
     * Hook which returns the validation status of the value being controlled.
     *
     * Returns `undefined` when the controller is not initialised.
     */
    readonly useValidationStatus: () => ValidationStatus | undefined;
    /**
     * Hook which returns the display status of the value being controlled.
     *
     * Returns `undefined` when the controller is not initialised.
     */
    readonly useDisplayStatus: () => DisplayStatus | undefined;
    readonly get: (<TValue = unknown, TResult = unknown>(path: Path | string, valueHandler: (value: TValue) => TResult | PromiseLike<TResult>) => CancellablePromise<TResult>) & (<TResult = unknown>(valueHandler: (value: T) => TResult | PromiseLike<TResult>) => CancellablePromise<TResult>);
    readonly getClone: (() => CancellablePromise<T>) & (<TValue = unknown>(path?: Path | string) => CancellablePromise<TValue>);
    readonly set: ((path: Path | string, toSet: unknown) => CancellablePromise<void>) & ((toSet: T) => CancellablePromise<void>);
    readonly reset: (path?: Path | string) => CancellablePromise<void>;
    readonly remove: (path?: Path | string) => CancellablePromise<void>;
    readonly validate: (path?: Path | string) => CancellablePromise<SealedLocatedValidationIssue[]>;
    readonly setDirty: (path?: Path | string) => CancellablePromise<void>;
    readonly setPristine: (path?: Path | string) => CancellablePromise<void>;
    readonly setTouched: (path?: Path | string) => CancellablePromise<void>;
    readonly setUntouched: (path?: Path | string) => CancellablePromise<void>;
}
/**
 * Options available to the controller's `useState` hook.
 */
export interface ControllerUseStateOptions<T = unknown> {
    /**
     * Function used to specify when two selections are considered equal to each
     * other.
     * @param v1 First selection.
     * @param v2 Second selection.
     * @returns Whether the two selections are considered equal.
     */
    equalityFn?: (v1: T, v2: T) => boolean;
}
/**
 * Options available when subscribing to the state of the controller.
 */
export interface ControllerSubscriptionOptions<T = unknown> {
    /**
     * Function used to specify when two selections are considered equal to each
     * other.
     * @param v1 First selection.
     * @param v2 Second selection.
     * @returns Whether the two selections are considered equal.
     */
    equalityFn?: (v1: T, v2: T) => boolean;
    /**
     * Whether the subscription's listener should be invoked immediately.
     */
    fireImmediately?: boolean;
}
/**
 * Controller's state.
 */
export type ControllerState<T = unknown> = UninitializedControllerState<T> | InitializedControllerState<T>;
/**
 * Base controller's state.
 */
export interface BaseControllerState<T = unknown> {
    /**
     * Form manager being used by the controller.
     */
    readonly formManager: FormManager;
    /**
     * Schema of the form value being controlled.
     */
    readonly schema: Schema<T>;
    /**
     * Path of the form value being controlled.
     */
    readonly path: AbsolutePath;
    /**
     * Schema path of the form value being controller.
     */
    readonly schemaPath: AbsolutePath;
    /**
     * Whether the controller is observing descendants.
     *
     * This will be `true` when the path provided to the controller ends in a
     * recursive wildcard.
     */
    readonly observingDescendants: boolean;
    /**
     * Whether the controller has been initialised.
     */
    readonly initialized: boolean;
    /**
     * Whether the form value being controlled exists.
     */
    readonly exists: boolean | undefined;
    /**
     * Form value.
     */
    readonly value: T | undefined;
    /**
     * Whether the form value being controlled is dirty.
     */
    readonly dirty: boolean | undefined;
    /**
     * Whether the form value being controlled has been touched.
     */
    readonly touched: boolean | undefined;
    /**
     * Validation issues associated with the form value being controlled.
     */
    readonly issues: SealedValidationIssue[] | undefined;
    /**
     * Validation status of the form value being controlled.
     */
    readonly validationStatus: ValidationStatus | undefined;
    /**
     * Display status of the form value being controlled.
     */
    readonly displayStatus: DisplayStatus | undefined;
}
/**
 * Uninitialised controller's state.
 */
export interface UninitializedControllerState<T = unknown> extends BaseControllerState<T> {
    readonly initialized: false;
    readonly exists: undefined;
    readonly value: undefined;
    readonly dirty: undefined;
    readonly touched: undefined;
    readonly issues: undefined;
    readonly validationStatus: undefined;
    readonly displayStatus: undefined;
}
/**
 * Initialized controller's state.
 */
export type InitializedControllerState<T = unknown> = NonexistentValueControllerState<T> | ExistingValueControllerState<T>;
/**
 * Controller state of a nonexistent form value.
 */
export interface NonexistentValueControllerState<T = unknown> extends BaseControllerState<T> {
    readonly initialized: true;
    readonly exists: false;
    readonly value: undefined;
    readonly dirty: undefined;
    readonly touched: undefined;
    readonly issues: undefined;
    readonly validationStatus: undefined;
    readonly displayStatus: undefined;
}
/**
 * Controller state of an existing form value.
 */
export interface ExistingValueControllerState<T = unknown> extends BaseControllerState<T> {
    readonly initialized: true;
    readonly exists: true;
    readonly value: T;
    readonly dirty: boolean;
    readonly touched: boolean;
    readonly issues: SealedValidationIssue[];
    readonly validationStatus: ValidationStatus;
    readonly displayStatus: DisplayStatus;
}
/**
 * Hook providing access to a controller used to read and control a value of
 * the form.
 * @param path Path of the form value to control, relative to the current path.
 *
 * The path must consist of only identifiers, except for the last fragment,
 * which may be a recursive wildcard to indicate that descendants should also be
 * observed.
 * @param options Available options.
 * @throws {Error} When {@link path} is invalid or contains fragments other than
 * ids.
 * @returns A controller used to read and control the form value.
 */
export declare function useController<T = unknown>(path?: Path | string, options?: undefined): Controller<T>;
export declare function useController<T = unknown, TState extends ControllerState<T> = ControllerState<T>>(path: Path | string | undefined, options: ControllerOptions<T, TState>): Controller<T, TState>;
