import { alamos } from '@synnaxlabs/alamos';
import { Sender, SenderHandler } from '@synnaxlabs/x';
import { z } from 'zod';
import { AetherMessage, MainMessage, MainUpdateMessage } from '../message';
import { state } from '../../state';
/**
 * A selected subset of the Map interface used for efficiently propagating context
 * updates through the tree.
 */
export interface ContextMap extends Pick<Map<string, unknown>, "get" | "forEach"> {
}
/**
 * An internal function alias that creates a new component with the specified
 * initial parent context
 */
interface CreateComponent {
    (initialParentCtxValues: ContextMap): Component;
}
export interface UpdateStateArgs extends Pick<MainUpdateMessage, "path" | "type" | "state"> {
    create: CreateComponent;
}
/**
 * A component in the Aether tree. Each component instance has a unique key identifying
 * it within the tree, and also has a type identifying it's class. Components
 * implementing different functionality should have different types, and these types
 * typically correlate to the corresponding name of the component in the react tree.
 */
export interface Component {
    /** The type of component. */
    type: string;
    /** A unique key identifying the component within the tree. */
    key: string;
    toString(): string;
    /**
     * Propagates a state update to the component at the given path. This is an internal
     * method, should not be called by subclasses outside of this file.
     *
     * @param path - The path of the component to update. The length of the path indicates
     * the depth of the component in the aether tree. This method should propagate the
     * state if the path has a length greater than 1.
     * @param type - the type of component being updated (or created).
     * @param state - The state to update the component with.
     * @param create - A function that creates a new component of the appropriate type if
     * it doesn't exist in the tree.
     */
    _updateState: (args: UpdateStateArgs) => void;
    /**
     * Propagates a context update to the children and all of its descendants.
     */
    _updateContext: (values: ContextMap) => void;
    /**
     * Propagates a delete to the internal tree of the component, calling the handleDelete
     * component on the component itself and any children as necessary. It is up to
     * the parent component to remove the child from its internal tree.
     *
     * @param path - The path of the component to delete.
     */
    _delete: (path: string[]) => void;
}
/** Constructor props that all aether components must accept. */
interface ComponentConstructorProps {
    /** The key of the component. */
    key: string;
    /** The type of the component. */
    type: string;
    /** A sender used to propagate messages back to the main thread. */
    sender: Sender<AetherMessage>;
    /** Instrumentation used for logging and tracing. */
    instrumentation: alamos.Instrumentation;
    /**
     * Initial parent context values for the component. These should be intentionally
     * set to null if no values exists.
     */
    parentCtxValues: ContextMap | null;
}
/** A constructor type for an AetherComponent. */
export interface ComponentConstructor {
    new (props: ComponentConstructorProps): Component;
}
/**
 * The Context interface allows for parent components to pass context values to
 * arbitrarily nested children.
 */
export interface Context {
    /**
     * Gets a context value, interpreting it as the given type, and returning it. This
     * method does no internal type checking - it is up to the caller to ensure that the
     * value exists for the given key and is of the correct type.
     * @throws a NotFoundError if the value does not exist for the given key.
     * @returns the context value interpreted as the given type.
     */
    get<P>(key: string): P;
    /**
     * Gets a context value, interpreting it as the given type, and returning it. This
     * method does no internal type checking - it is up to the caller to ensure that the
     * value is of the correct type.
     * @returns the context value, or null if no value exists for the given key.
     */
    getOptional<P>(key: string): P | null;
    /**
     * Checks if a parent context value exists for the given key. Note that this will
     * return false for all context values set by the component itself.
     * @returns true if a value exists for the given key, false otherwise.
     */
    has(key: string): boolean;
    /**
     * Sets a context value for the given key, making it available to all children of the
     * component, but NOT to the component itself. This detail is crucial, as it means
     * the component can override the value of an existing parent key and propagate it
     * to its children, while still being able to access the original parent value.
     *
     * @param key - The key of the context value to set.
     * @param value - The value to set for the given key.
     * @param trigger - If true, the component will be notified of the change.
     */
    set(key: string, value: unknown, trigger?: boolean): void;
    /**
     * Checks if the component has previously set a context value for the given key. This
     * is an alternative to {@link has} that checks whether the component has set the value
     * itself, as opposed to whether it has been set by a parent.
     * @returns true if the component has set the value itself, false otherwise.
     */
    wasSetPreviously(key: string): boolean;
}
/**
 * Implements an AetherComponent that does not have any children, and servers as the base
 * class for the AetherComposite type. The corresponding react component should NOT have
 * any children that use Aether functionality; for those cases, use AetherComposite instead.
 */
export declare abstract class Leaf<StateSchema extends z.ZodType<state.State>, InternalState extends {} = {}> implements Component {
    readonly type: string;
    readonly key: string;
    private readonly sender;
    private readonly _internalState;
    private _state;
    private _prevState;
    private _deleted;
    protected readonly parentCtxValues: Map<string, any>;
    protected readonly childCtxValues: Map<string, any>;
    protected readonly childCtxChangedKeys: Set<string>;
    readonly instrumentation: alamos.Instrumentation;
    schema: StateSchema | undefined;
    constructor({ key, type, sender, instrumentation, parentCtxValues, }: ComponentConstructorProps);
    private get _schema();
    /**
     * Sets the state on the component, communicating the change to the corresponding
     * React component on the main thread.
     *
     * @param next - The new state to set on the component. This can be the state object
     * or a pure function that takes in the previous state and returns the next state.
     */
    setState(next: state.SetArg<z.infer<StateSchema>>): void;
    /** @returns the current state of the component. */
    get state(): z.infer<StateSchema>;
    get internal(): InternalState;
    /** @returns the previous state of the component. */
    get prevState(): z.infer<StateSchema>;
    get deleted(): boolean;
    private get ctx();
    toString(): string;
    /**
     * @implements AetherComponent, and should NOT be called by a subclass other than
     * AetherComposite.
     */
    _updateState({ path, state }: UpdateStateArgs): void;
    _updateContext(values: ContextMap): void;
    /**
     * @implements AetherComponent, and should NOT be called by a subclass other than
     * AetherComposite.
     */
    _delete(path: string[]): void;
    /**
     * afterUpdate is optionally defined by a subclass, allowing the component to
     * perform some action after the component is updated. At this point, the current
     * state, previous state, derived state, and current context are all available to
     * the component.
     */
    afterUpdate(_: Context): void;
    /**
     * Runs after the component has been spliced out of the tree. This is useful for
     * running cleanup code, such as unsubscribing from an event emitter. At this point,
     * the current state, previous state, derived state, and current context are all
     * available to the component, and this.deleted is true.
     */
    afterDelete(_: Context): void;
    private validatePath;
}
/**
 * AetherComposite is an implementation of AetherComponent that allows it to maintain
 * child components. It is the base class for all composite components, and should not
 * be used directly.
 */
export declare abstract class Composite<StateSchema extends z.ZodType<state.State>, InternalState extends {} = {}, ChildComponents extends Component = Component> extends Leaf<StateSchema, InternalState> implements Component {
    private readonly _children;
    /** @returns a readonly array of the children of the component. */
    get children(): readonly ChildComponents[];
    /**
     * Finds a child component with the given key.
     *
     * @param key - the key of the child component to find.
     * @returns the child component, or null if no child component with the given key
     */
    getChild<T extends ChildComponents = ChildComponents>(key: string): T | null;
    /**
     * Finds all children of the component with the given type
     *
     * @param types - the type of the children to find
     * @returns an array of all children of the component with the given type
     */
    childrenOfType<T extends ChildComponents = ChildComponents>(...types: Array<T["type"]>): readonly T[];
    _updateState(args: UpdateStateArgs): void;
    _updateContext(values: ContextMap): void;
    private childCtx;
    private updateChildContexts;
    _delete(path: string[]): void;
    private parsePath;
}
export type ComponentRegistry = Record<string, ComponentConstructor>;
declare const aetherRootState: z.ZodObject<{}, z.core.$strip>;
/**
 * The props for creating the root of the Aether tree.
 */
export interface RootProps {
    /** A communication mechanism for sending messages to the main thread. */
    comms: SenderHandler<AetherMessage, MainMessage>;
    /** A registry of available components that can be used to mirror those on the main thread. */
    registry: ComponentRegistry;
    /** Instrumentation used for logging and tracing. */
    instrumentation?: alamos.Instrumentation;
}
export declare class Root extends Composite<typeof aetherRootState> {
    /** Key of the root component. */
    private static readonly TYPE;
    /** Type of the root component. */
    private static readonly KEY;
    /** A communication mechanism for sending messages to the main thread. */
    private readonly comms;
    /** A registry used for creating new components in the tree. */
    private readonly registry;
    schema: z.ZodObject<{}, z.core.$strip>;
    constructor({ comms, instrumentation, registry, }: RootProps);
    /**
     * Creates a new aether tree with the provided props, and starts listing for state
     * updates on the provided comms.
     */
    static render(props: RootProps): Root;
    /**
     * Handles messages from the worker thread and applies them as updates in the
     * aether tree.
     */
    private handle;
    /** Creates a new component from the registry */
    private create;
}
/**
 * Creates a new aether tree with the provided props.
 *
 * @param props - The props for the root component.
 * @param props.comms - A communication mechanism for sending messages to the main thread.
 * Typically this is implemented by a web worker.
 * @param props.registry - A registry of available components that can be used to mirror
 * those on the main thread.
 */
export declare const render: typeof Root.render;
export {};
//# sourceMappingURL=aether.d.ts.map