import { ObjNode, ArrNode, BinNode, ConNode, VecNode, ValNode, StrNode, RootNode } from '../../nodes';
import { NodeEvents } from './NodeEvents';
import { FanOut, type FanOutUnsubscribe } from 'thingies/lib/fanout';
import { PatchBuilder } from '../../../json-crdt-patch/PatchBuilder';
import { MergeFanOut, MicrotaskBufferFanOut } from './fanout';
import { ExtNode } from '../../extensions/ExtNode';
import { ChangeEvent } from './events';
import { type ITimestampStruct } from '../../../json-crdt-patch/clock';
import { type JsonNodeToProxyPathNode } from './proxy';
import type { Extension } from '../../extensions/Extension';
import type { ExtApi } from '../../extensions/types';
import type * as types from './proxy';
import type { Printable } from 'tree-dump/lib/types';
import type { ApiOperation, ApiPath, JsonNodeApi } from './types';
import type { VecNodeExtensionData } from '../../schema/types';
import type { Patch } from '../../../json-crdt-patch';
import type { SyncStore } from '../../../util/events/sync-store';
import type { Model } from '../Model';
import type { JsonNode, JsonNodeView } from '../../nodes';
/**
 * A generic local changes API for a JSON CRDT node.
 *
 * @category Local API
 */
export declare class NodeApi<N extends JsonNode = JsonNode> implements Printable {
    node: N;
    readonly api: ModelApi<any>;
    constructor(node: N, api: ModelApi<any>);
    /**
     * Find a child node at the given path starting from this node.
     *
     * @param path Path to the child node to find.
     * @returns JSON CRDT node at the given path.
     */
    find(path?: ApiPath): JsonNode;
    /**
     * Find a child node at the given path starting from this node and wrap it in
     * a local changes API.
     *
     * @param path Path to the child node to find.
     * @returns Local changes API for the child node at the given path.
     */
    in(path?: ApiPath): ValApi<ValNode<any>>;
    asVal(): ValApi;
    asStr(): StrApi;
    asBin(): BinApi;
    asArr(): ArrApi;
    asVec(): VecApi;
    asObj(): ObjApi;
    asCon(): ConApi;
    /**
     * Returns the API object of the extension if the node is an extension node.
     * When the `ext` parameter is provided, it checks if the node is an instance
     * of the given extension and returns the object's TypeScript type. Otherwise,
     * it returns the API object of the extension, but without any type checking.
     *
     * @param ext Extension of the node
     * @returns API of the extension
     */
    asExt(): JsonNodeApi<VecNodeExtensionData<N>> | ExtApi<any> | undefined;
    asExt<EN extends ExtNode<any, any>, EApi extends ExtApi<EN>>(ext: Extension<any, any, EN, EApi, any, any>): EApi;
    val(path?: ApiPath): ValApi;
    str(path?: ApiPath): StrApi;
    bin(path?: ApiPath): BinApi;
    arr(path?: ApiPath): ArrApi;
    vec(path?: ApiPath): VecApi;
    obj(path?: ApiPath): ObjApi;
    con(path?: ApiPath): ConApi;
    view(): JsonNodeView<N>;
    select(path?: ApiPath, leaf?: boolean): NodeApi<JsonNode<unknown>> | undefined;
    read(path?: ApiPath): unknown;
    add(path: ApiPath, value: unknown): boolean;
    replace(path: ApiPath, value: unknown): boolean;
    remove(path: ApiPath, length?: number): boolean;
    diff(value: unknown): Patch | undefined;
    merge(value: unknown): Patch | undefined;
    op(operation: ApiOperation): boolean;
    get s(): types.ProxyNode<N>;
    get $(): JsonNodeToProxyPathNode<N>;
    /**
     * @ignore
     * @deprecated Use `onChange()` and other `on*()` methods.
     */
    private ev;
    /**
     * Event target for listening to node changes. You can subscribe to `"view"`
     * events, which are triggered every time the node's view changes.
     *
     * ```ts
     * node.events.on('view', () => {
     *   // do something...
     * });
     * ```
     *
     * @ignore
     * @deprecated Use `onNodeChange()` and other `on*()` methods.
     */
    get events(): NodeEvents<N>;
    /**
     * Attaches a listener which executes on every change that is executed
     * directly on this node. For example, if this is a "str" string node and
     * you insert or delete text, the listener will be executed. Or if
     * this is an "obj" object node and keys of this object are changed, this
     * listener will be executed.
     *
     * It does not trigger when child nodes are edit, to include those changes,
     * use `onSubtreeChange()` or `onChildChange()` methods.
     *
     * @see onChildChange()
     * @see onSubtreeChange()
     *
     * @param listener Callback called on every change that is executed directly
     *     on this node.
     * @param onReset Optional parameter, if set to `true`, the listener will also
     *     be called when the model is reset using the `.reset()` method.
     * @returns Returns an unsubscribe function to stop listening to the events.
     */
    onSelfChange(listener: (event: ChangeEvent) => void, onReset?: boolean): FanOutUnsubscribe;
    /**
     * Attaches a listener which executes on every change that is applied to this
     * node's children. Hence, this listener will trigger only for *container*
     * nodes - nodes that can have child nodes, such as "obj", "arr", "vec", and
     * "val" nodes. It will not execute on changes made directly to this node.
     *
     * If you want to listen to changes on this node as well as its children, use
     * `onSubtreeChange()` method. If you want to listen to changes on this node
     * only, use `onSelfChange()` method.
     *
     * @see onSelfChange()
     * @see onSubtreeChange()
     *
     * @param listener Callback called on every change that is applied to
     *     children of this node.
     * @param onReset Optional parameter, if set to `true`, the listener will also
     *     be called when the model is reset using the `.reset()` method.
     * @return Returns an unsubscribe function to stop listening to the events.
     */
    onChildChange(listener: (event: ChangeEvent) => void, onReset?: boolean): FanOutUnsubscribe;
    /**
     * Attaches a listener which executes on every change that is applied to this
     * node or any of its child nodes (recursively). This is equivalent to
     * combining both `onSelfChange()` and `onChildChange()` methods.
     *
     * @see onSelfChange()
     * @see onChildChange()
     *
     * @param listener Callback called on every change that is applied to this
     *     node or any of its child nodes.
     * @param onReset Optional parameter, if set to `true`, the listener will also
     *     be called when the model is reset using the `.reset()` method.
     * @return Returns an unsubscribe function to stop listening to the events.
     */
    onSubtreeChange(listener: (event: ChangeEvent) => void, onReset?: boolean): FanOutUnsubscribe;
    toString(tab?: string): string;
}
/**
 * Represents the local changes API for the `con` JSON CRDT node {@link ConNode}.
 *
 * @category Local API
 */
export declare class ConApi<N extends ConNode<any> = ConNode<any>> extends NodeApi<N> {
    /**
     * Returns a proxy object for this node.
     */
    get s(): types.ProxyNodeCon<N>;
}
/**
 * Local changes API for the `val` JSON CRDT node {@link ValNode}.
 *
 * @category Local API
 */
export declare class ValApi<N extends ValNode<any> = ValNode<any>> extends NodeApi<N> {
    /**
     * Get API instance of the inner node.
     * @returns Inner node API.
     */
    get(): JsonNodeApi<N extends ValNode<infer T> ? T : JsonNode>;
    /**
     * Sets the value of the node.
     *
     * @param json JSON/CBOR value or ID (logical timestamp) of the value to set.
     * @returns Reference to itself.
     */
    set(json: JsonNodeView<N>): void;
    /**
     * Returns a proxy object for this node. Allows to access the value of the
     * node by accessing the `.val` property.
     */
    get s(): types.ProxyNodeVal<N>;
}
type UnVecNode<N> = N extends VecNode<infer T> ? T : never;
/**
 * Local changes API for the `vec` JSON CRDT node {@link VecNode}.
 *
 * @category Local API
 */
export declare class VecApi<N extends VecNode<any> = VecNode<any>> extends NodeApi<N> {
    /**
     * Get API instance of a child node.
     *
     * @param key Object key to get.
     * @returns A specified child node API.
     */
    get<K extends keyof UnVecNode<N>>(key: K): JsonNodeApi<UnVecNode<N>[K]>;
    /**
     * Sets a list of elements to the given values.
     *
     * @param entries List of index-value pairs to set.
     * @returns Reference to itself.
     */
    set(entries: [index: number, value: unknown][]): void;
    push(...values: unknown[]): void;
    /**
     * Get the length of the vector without materializing it to a view.
     *
     * @returns Length of the vector.
     */
    length(): number;
    /**
     * Returns a proxy object for this node. Allows to access vector elements by
     * index.
     */
    get s(): types.ProxyNodeVec<N>;
}
type UnObjNode<N> = N extends ObjNode<infer T> ? T : never;
/**
 * Local changes API for the `obj` JSON CRDT node {@link ObjNode}.
 *
 * @category Local API
 */
export declare class ObjApi<N extends ObjNode<any> = ObjNode<any>> extends NodeApi<N> {
    /**
     * Get API instance of a child node.
     *
     * @param key Object key to get.
     * @returns A specified child node API.
     */
    get<K extends keyof UnObjNode<N>>(key: K): JsonNodeApi<UnObjNode<N>[K]>;
    /**
     * Sets a list of keys to the given values.
     *
     * @param entries List of key-value pairs to set.
     * @returns Reference to itself.
     */
    set(entries: Partial<JsonNodeView<N>>): void;
    /**
     * Deletes a list of keys from the object.
     *
     * @param keys List of keys to delete.
     * @returns Reference to itself.
     */
    del(keys: string[]): void;
    /**
     * Checks if a key exists in the object.
     *
     * @param key Key to check.
     * @returns True if the key exists, false otherwise.
     */
    has(key: string): boolean;
    /** Diffs only keys present in `dst` object. */
    diffKeys(dst: Record<string, unknown>): Patch | undefined;
    /** Merges only keys present in `dst` object. */
    mergeKeys(dst: Record<string, unknown>): Patch | undefined;
    /**
     * Returns a proxy object for this node. Allows to access object properties
     * by key.
     */
    get s(): types.ProxyNodeObj<N>;
}
/**
 * Local changes API for the `str` JSON CRDT node {@link StrNode}. This API
 * allows to insert and delete bytes in the UTF-16 string by referencing its
 * local character positions.
 *
 * @category Local API
 */
export declare class StrApi extends NodeApi<StrNode> {
    /**
     * Inserts text at a given position.
     *
     * @param index Position at which to insert text.
     * @param text Text to insert.
     * @returns Reference to itself.
     */
    ins(index: number, text: string): void;
    /**
     * Deletes a range of text at a given position.
     *
     * @param index Position at which to delete text.
     * @param length Number of UTF-16 code units to delete.
     * @returns Reference to itself.
     */
    del(index: number, length: number): void;
    /**
     * Given a character index in local coordinates, find the ID of the character
     * in the global coordinates.
     *
     * @param index Index of the character or `-1` for before the first character.
     * @returns ID of the character after which the given position is located.
     */
    findId(index: number | -1): ITimestampStruct;
    /**
     * Given a position in global coordinates, find the position in local
     * coordinates.
     *
     * @param id ID of the character.
     * @returns Index of the character in local coordinates. Returns -1 if the
     *          the position refers to the beginning of the string.
     */
    findPos(id: ITimestampStruct): number | -1;
    /**
     * Get the length of the string without materializing it to a view.
     *
     * @returns Length of the string.
     */
    length(): number;
    /**
     * Returns a proxy object for this node.
     */
    get s(): types.ProxyNodeStr;
}
/**
 * Local changes API for the `bin` JSON CRDT node {@link BinNode}. This API
 * allows to insert and delete bytes in the binary string by referencing their
 * local index.
 *
 * @category Local API
 */
export declare class BinApi extends NodeApi<BinNode> {
    /**
     * Inserts octets at a given position.
     *
     * @param index Position at which to insert octets.
     * @param data Octets to insert.
     * @returns Reference to itself.
     */
    ins(index: number, data: Uint8Array): void;
    /**
     * Deletes a range of octets at a given position.
     *
     * @param index Position at which to delete octets.
     * @param length Number of octets to delete.
     * @returns Reference to itself.
     */
    del(index: number, length: number): void;
    /**
     * Get the length of the binary blob without materializing it to a view.
     *
     * @returns Length of the binary blob.
     */
    length(): number;
    /**
     * Returns a proxy object for this node.
     */
    get s(): types.ProxyNodeBin;
}
type UnArrNode<N> = N extends ArrNode<infer T> ? T : never;
/**
 * Local changes API for the `arr` JSON CRDT node {@link ArrNode}. This API
 * allows to insert and delete elements in the array by referencing their local
 * index.
 *
 * @category Local API
 */
export declare class ArrApi<N extends ArrNode<any> = ArrNode<any>> extends NodeApi<N> {
    /**
     * Get API instance of a child node.
     *
     * @param index Index of the element to get.
     * @returns Child node API for the element at the given index.
     */
    get(index: number): JsonNodeApi<UnArrNode<N>>;
    /**
     * Inserts elements at a given position.
     *
     * @param index Position at which to insert elements.
     * @param values Values or schema of the elements to insert.
     */
    ins(index: number, values: Array<JsonNodeView<N>[number]>): void;
    /**
     * Inserts elements at the end of the array.
     *
     * @param values Values or schema of the elements to insert at the end of the array.
     */
    push(...values: JsonNodeView<N>[number][]): void;
    /**
     * Updates (overwrites) an element at a given position.
     *
     * @param index Position at which to update the element.
     * @param value Value or schema of the element to replace with.
     */
    upd(index: number, value: JsonNodeView<N>[number]): void;
    /**
     * Deletes a range of elements at a given position.
     *
     * @param index Position at which to delete elements.
     * @param length Number of elements to delete.
     * @returns Reference to itself.
     */
    del(index: number, length: number): void;
    /**
     * Get the length of the array without materializing it to a view.
     *
     * @returns Length of the array.
     */
    length(): number;
    /**
     * Returns a proxy object that allows to access array elements by index.
     *
     * @returns Proxy object that allows to access array elements by index.
     */
    get s(): types.ProxyNodeArr<N>;
}
/**
 * Local changes API for a JSON CRDT model. This class is the main entry point
 * for executing local user actions on a JSON CRDT document.
 *
 * @category Local API
 */
export declare class ModelApi<N extends JsonNode = JsonNode> extends ValApi<RootNode<N>> implements SyncStore<JsonNodeView<N>> {
    readonly model: Model<N>;
    /**
     * Patch builder for the local changes.
     */
    builder: PatchBuilder;
    /**
     * Index of the next operation in builder's patch to be committed locally.
     *
     * @ignore
     */
    next: number;
    /** Emitted before the model is reset, using the `.reset()` method. */
    readonly onBeforeReset: FanOut<void>;
    /** Emitted after the model is reset, using the `.reset()` method. */
    readonly onReset: FanOut<Set<JsonNode<unknown>>>;
    /** Emitted before a patch is applied using `model.applyPatch()`. */
    readonly onBeforePatch: FanOut<Patch>;
    /** Emitted after a patch is applied using `model.applyPatch()`. */
    readonly onPatch: FanOut<Patch>;
    /** Emitted before local changes through `model.api` are applied. */
    readonly onBeforeLocalChange: FanOut<number>;
    /** Emitted after local changes through `model.api` are applied. */
    readonly onLocalChange: FanOut<number>;
    /**
     * Emitted after local changes through `model.api` are applied. Same as
     * `.onLocalChange`, but this event buffered withing a microtask.
     */
    readonly onLocalChanges: MicrotaskBufferFanOut<number>;
    /** Emitted before a transaction is started. */
    readonly onBeforeTransaction: FanOut<void>;
    /** Emitted after transaction completes. */
    readonly onTransaction: FanOut<void>;
    /** Emitted when the model changes. Combines `onReset`, `onPatch` and `onLocalChange`. */
    readonly onChange: MergeFanOut<ChangeEvent>;
    /** Emitted when the model changes. Same as `.onChange`, but this event is emitted once per microtask. */
    readonly onChanges: MicrotaskBufferFanOut<unknown>;
    /** Emitted when the `model.api` builder change buffer is flushed. */
    readonly onFlush: FanOut<Patch>;
    /**
     * @param model Model instance on which the API operates.
     */
    constructor(model: Model<N>);
    /**
     * Returns a local change API for the given node. If an instance already
     * exists, returns the existing instance.
     */
    wrap(node: ValNode): ValApi;
    wrap(node: StrNode<any>): StrApi;
    wrap(node: BinNode): BinApi;
    wrap(node: ArrNode): ArrApi;
    wrap(node: ObjNode): ObjApi;
    wrap(node: ConNode): ConApi;
    wrap(node: VecNode): VecApi;
    wrap(node: JsonNode): NodeApi;
    wrap(node: ExtNode<any, any>): NodeApi;
    /**
     * Given a JSON/CBOR value, constructs CRDT nodes recursively out of it and
     * sets the root node of the model to the constructed nodes.
     *
     * @param json JSON/CBOR value to set as the view of the model.
     * @returns Reference to itself.
     *
     * @deprecated Use `.set()` instead.
     */
    root(json: unknown): this;
    set(json: unknown): this;
    /**
     * Apply locally any operations from the `.builder`, which haven't been
     * applied yet.
     */
    apply(): void;
    /**
     * Advance patch pointer to the end without applying the operations. With the
     * idea that they have already been applied locally.
     *
     * You need to manually call `this.onBeforeLocalChange.emit(this.next)` before
     * calling this method.
     *
     * @ignore
     */
    advance(): void;
    private inTx;
    transaction(callback: () => void): void;
    /**
     * Flushes the builder and returns a patch.
     *
     * @returns A JSON CRDT patch.
     * @todo Make this return undefined if there are no operations in the builder.
     */
    flush(): Patch;
    stopAutoFlush?: () => void;
    /**
     * Begins to automatically flush buffered operations into patches, grouping
     * operations by microtasks or by transactions. To capture the patch, listen
     * to the `.onFlush` event.
     *
     * @returns Callback to stop auto flushing.
     */
    autoFlush(drainNow?: boolean): () => void;
    readonly subscribe: (callback: () => void) => FanOutUnsubscribe;
    readonly getSnapshot: () => JsonNodeView<N>;
}
export {};
