import type { Constructable, IfEquals, IfReadonly, StringKey } from "./lang-utils";
import { AsyncSourceKey } from "./metadata";
import { EventEmitter, FactoryProvider, Injector, Type } from "@angular/core";
import { Observable, Subject, Subscription } from "rxjs";
import { CommonMetadata } from "./metadata";
declare const COMPONENT_STATE_IDENTITY: unique symbol;
export type ComponentState<ComponentT> = ComponentState.Of<ComponentT>;
type ComponentClassProvider<ComponentT> = Type<ComponentT> | Type<unknown>;
export type ManagedComponent = Constructable<any, any> & {
    [CommonMetadata.MANAGED_ONDESTROY_KEY]: Observable<void>;
};
export declare class ComponentStateRef<ComponentT> extends Promise<ComponentState<ComponentT>> {
    componentInstance: ComponentT & ManagedComponent;
    /**
     * @description Resolves the `ComponentState` instance for this reference.
     * @returns An `Observable` that emits the `ComponentState` instance for this reference.
     */
    state(): Observable<ComponentState<ComponentT>>;
    /**
     * @description Returns an `Observable` that represents the current value of the given state property and emits whenever the value of the given state
     * property is changed.
     * @param stateProp - The state property to observe.
     * @returns An `Observable` that emits the value of the given state property and re-emits when the value is changed.
     */
    get<K extends StringKey<ComponentT>>(stateProp: ComponentState.ReadableKey<ComponentT, K>): Observable<ComponentT[K]>;
    /**
     * @description Returns an array of `Observable`s that represents the current value for each given state property. Each `Observable` emits whenever a
     * value of the corresponding given state property is changed.
     * @param stateProps - The state properties to observe.
     * @returns An array of `Observable`s that represents the current value for each given state property and re-emits when the corresponding value is
     * changed.
     */
    getAll<K extends Array<ComponentState.ReadableKey<ComponentT, StringKey<ComponentT>>>>(...stateProps: K): ComponentState.StateSelector<ComponentT, K>;
    /**
     * @description Returns an `EventEmitter` that emits whenever the value of the given state property is changed.
     * @param stateProp - The state property to observe.
     * @returns An `EventEmitter` instance that emits whenever the value of the given state property is changed.
     */
    emitter<K extends StringKey<ComponentT>>(stateProp: ComponentState.ReadableKey<ComponentT, K>): EventEmitter<ComponentT[K]>;
    /**
     * @description Updates the value of the given state property with the given value. Equivalent to assigning to the component state property directly.
     * @param stateProp - The state property to update. This property must not be readonly.
     * @param value - The new value to update to.
     * @returns An `Observable` that emits and completes when the value has been updated.
     */
    set<K extends StringKey<ComponentT>, V extends ComponentT[K]>(stateProp: ComponentState.WritableKey<ComponentT, K>, value: V): Observable<void>;
    /**
     * @description Subscribes the given state property to the given source `Observable`. If `managed` is set to true, the lifetime of the subscription will
     * be managed and cleaned up when the component is destroyed.
     * @param stateProp - The state property to receive source updates. This property must not be readonly.
     * @param source$ - The source `Observable` to subscribe to.
     * @param managed - Whether or not the subscription lifetime should be managed. Defaults to `true`.
     * @returns A `Subscription` representing the subscription to the source.
     */
    subscribeTo<K extends StringKey<ComponentT>, V extends ComponentT[K]>(stateProp: ComponentState.WritableKey<ComponentT, K>, source$: Observable<V>, managed?: boolean): Subscription;
    /**
     * @description Synchronizes the values of the given state properties such that any changes from one state property will be propagated to the
     * other state property. The initial value of the first given state property is used.
     * @param statePropA - The first state property to synchronize. This property must not be readonly.
     * @param statePropB - The second state property to synchronize. This property must not be readonly.
     */
    sync<K1 extends StringKey<ComponentT>, K2 extends StringKey<ComponentT>, V extends IfEquals<ComponentT[K1], ComponentT[K2]> extends true ? ComponentT[K1] & ComponentT[K2] : never>(statePropA: V extends never ? never : ComponentState.WritableKey<ComponentT, K1>, statePropB: V extends never ? never : ComponentState.WritableKey<ComponentT, K2>): void;
    /**
     * @description Synchronizes the values of the given state property and source `Subject` such that any changes from the state property will be
     * propagated to the source `Subject` and vice versa. The initial value of the source `Subject` is used.
     * @param stateProp - The state property to synchronize. This property must not be readonly.
     * @param source$ - The source `Subject` to synchronize with.
     */
    syncWith<K extends StringKey<ComponentT>>(stateProp: ComponentState.WritableKey<ComponentT, K>, source$: Subject<ComponentT[K]>): void;
    /**
     * @description Synchronizes the state of `stateProp` and `sourceProp`, a property from another `ComponentStateRef`, such that any changes from
     * `stateProp` will be propagated to `sourceProp` and vice versa. The initial state value of `sourceProp` is used.
     * @param stateProp - The state property to synchronize. This property must not be readonly.
     * @param sourceState - The source `ComponentStateRef` instance.
     * @param sourceProp - The source state property from `sourceState` to synchronize with. This property must not be readonly.
     */
    syncWith<ComponentT2, K1 extends StringKey<ComponentT>, K2 extends StringKey<ComponentT2>, V extends IfEquals<ComponentT[K1], ComponentT2[K2]> extends true ? ComponentT[K1] & ComponentT2[K2] : never>(stateProp: V extends never ? never : ComponentState.WritableKey<ComponentT, K1>, sourceState: ComponentStateRef<ComponentT2>, sourceProp: V extends never ? never : ComponentState.WritableKey<ComponentT2, K2>): void;
    private get resolvedState();
}
export declare namespace ComponentState {
    export interface CreateOptions {
        lazy?: boolean;
    }
    export type ReactiveStateKey<ComponentT, K extends keyof ComponentT = keyof ComponentT> = K extends string ? AsyncSourceKey<ComponentT, K> : never;
    type QualifiedStateKey<ComponentT, K extends keyof ComponentT = keyof ComponentT> = K extends `${infer _K}$` ? never : K;
    export type StateKey<ComponentT> = keyof {
        [K in keyof ComponentT as QualifiedStateKey<ComponentT, K>]: never;
    };
    export type Of<ComponentT> = {
        readonly [K in keyof ComponentT as ReactiveStateKey<ComponentT, QualifiedStateKey<ComponentT, K>>]-?: IfReadonly<ComponentT, K> extends true ? Observable<ComponentT[K]> : Subject<ComponentT[K]>;
    };
    export type ReadableKey<ComponentT, K extends keyof ComponentT = keyof ComponentT> = K extends StateKey<ComponentT> ? K : never;
    export type WritableKey<ComponentT, K extends keyof ComponentT = keyof ComponentT> = IfReadonly<ComponentT, K> extends true ? never : ReadableKey<ComponentT, K>;
    export type StateSelector<ComponentT, K extends Array<ReadableKey<ComponentT>>> = {
        [I in keyof K]: K[I] extends ReadableKey<ComponentT> ? Observable<ComponentT[K[I]]> : never;
    };
    export function create<ComponentT>($class: ComponentClassProvider<ComponentT>, options?: CreateOptions): FactoryProvider;
    export function createFactory<ComponentT>($class: ComponentClassProvider<ComponentT>, options?: CreateOptions): (injector: Injector) => ComponentStateRef<ComponentT>;
    export function tokenFor(provider: FactoryProvider): any;
    export function stateKey<ComponentT, K extends StringKey<ComponentT> = StringKey<ComponentT>>(key: K): ReactiveStateKey<ComponentT, K> & keyof Of<ComponentT>;
    export {};
}
export declare function createComponentState<ComponentT>($class: ComponentClassProvider<ComponentT>, options?: ComponentState.CreateOptions): FactoryProvider;
export declare function stateTokenFor(provider: FactoryProvider): any;
export declare function _requireComponentState<T extends {
    [COMPONENT_STATE_IDENTITY]?: Partial<ComponentState<T>>;
} & Record<any, any>>(instance: T, initValue?: Partial<ComponentState<T>>): Partial<ComponentState<T>>;
export {};
