import * as clock from '../../json-crdt-patch/clock';
import { ModelApi } from './api';
import { RootNode } from '../nodes';
import { ConNode } from '../nodes/const/ConNode';
import { Extensions } from '../extensions/Extensions';
import { NodeBuilder, type nodes } from '../../json-crdt-patch';
import type { SchemaToJsonNode } from '../schema/types';
import type { JsonCrdtPatchOperation, Patch } from '../../json-crdt-patch/Patch';
import type { JsonNode, JsonNodeView } from '../nodes/types';
import type { Printable } from 'tree-dump/lib/types';
export declare const UNDEFINED: ConNode<undefined>;
/**
 * In instance of Model class represents the underlying data structure,
 * i.e. model, of the JSON CRDT document.
 */
export declare class Model<N extends JsonNode = JsonNode<any>> implements Printable {
    /**
     * Generates a random session ID. Use this method to generate a session ID
     * for a new user. Store the session ID in the user's browser or device once
     * and reuse it for all editing sessions of that user.
     *
     * Generating a new session ID for each editing session will work, however,
     * that is not recommended. If a user generates a new session ID for each
     * editing session, the session clock table will grow indefinitely.
     */
    static readonly sid: () => number;
    /**
     * Use this method to generate a random session ID for an existing document.
     * It checks for the uniqueness of the session ID given the current peers in
     * the document. This reduces the chance of collision substantially.
     *
     * @returns A random session ID that is not used by any peer in the current
     *     document.
     */
    rndSid(): number;
    /**
     * Create a new JSON CRDT model. If a schema is provided, the model is
     * strictly typed and the default value of the model is set to the default
     * value of the schema.
     *
     * By default, the model is created with a random session ID and is using
     * a logical clock. It is also possible to create a model which uses a server
     * clock by providing the session ID `SESSION.SERVER` (1).
     *
     * ### Examples
     *
     * Create a basic model, without schema and default value:
     *
     * ```ts
     * const model = Model.create();
     * ```
     *
     * Create a strictly typed model with a schema and default value:
     *
     * ```ts
     * const schema = s.obj({
     *   ticker: s.con<string>('BODEN'),
     *   name: s.str('Jeo Boden'),
     *   tags: s.arr(
     *     s.str('token'),
     *   ),
     * });
     * const model = Model.create(schema);
     * const patch = model.api.flush();
     * ```
     *
     * Create a model with a custom session ID for your logical clock:
     *
     * ```ts
     * const schema = s.str('');
     * const sid = 123456789;
     * const model = Model.create(schema, sid);
     * const patch = model.api.flush();
     * ```
     *
     * The session ID must be at least 65,536 or higher, [see JSON CRDT Patch
     * specification][json-crdt-patch].
     *
     * [json-crdt-patch]: https://jsonjoy.com/specs/json-crdt-patch/patch-document/logical-clock
     *
     * To create a model with a server clock, use the `SESSION.SERVER`, which is
     * equal to 1:
     *
     * ```ts
     * const model = Model.create(undefined, SESSION.SERVER);
     * // or
     * const model = Model.create(undefined, 1);
     * ```
     *
     * Finally, you can create a model with your clock vector:
     *
     * ```ts
     * const clock = new ClockVector(123456789, 1);
     * const model = Model.create(undefined, clock);
     * ```
     *
     * @param schema The schema (typing and default value) to set for this model.
     *     When a schema is provided, the model is strictly typed and the default
     *     value of the model is set to the value of the schema. Also, you MUST
     *     call `model.api.flush()` immediately after creating the model to clear
     *     the change buffer of the patch that was created during the initialization
     *     of the model.
     * @param sidOrClock Session ID to use for local operations. Defaults to a random
     *        session ID generated by {@link Model.sid}.
     * @returns A strictly typed model.
     */
    static readonly create: <S extends NodeBuilder | unknown>(schema?: S, sidOrClock?: clock.ClockVector | number) => Model<undefined extends S ? JsonNode<unknown> : S extends NodeBuilder ? SchemaToJsonNode<S> : SchemaToJsonNode<nodes.json<S>>>;
    /**
     * Create a CRDT model which uses server clock. In this model a central server
     * timestamps each operation with a sequence number. Each timestamp consists
     * simply of a sequence number, which was assigned by a server. In this model
     * all operations are approved, persisted and re-distributed to all clients by
     * a central server. The session ID part of the clock is the same for all
     * clients, i.e. {@link SESSION.SERVER}.
     *
     * @param time Latest known server sequence number.
     * @returns CRDT model.
     */
    static readonly withServerClock: <S extends NodeBuilder>(schema?: S, time?: number) => Model<undefined extends S ? JsonNode<unknown> : S extends NodeBuilder ? SchemaToJsonNode<S> : SchemaToJsonNode<nodes.json<S>>>;
    /**
     * Decodes a model from a "binary" structural encoding.
     *
     * Use {@link Model.load} instead, if you want to set the session ID of the
     * model and the right schema for the model, during the de-serialization.
     *
     * @param data Binary blob of a model encoded using "binary" structural
     *        encoding.
     * @returns An instance of a model.
     */
    static readonly fromBinary: <N_1 extends JsonNode = JsonNode<any>>(data: Uint8Array) => Model<N_1>;
    /**
     * Un-serializes a model from "binary" structural encoding. The session ID of
     * the model is set to the provided session ID `sid`, or the default session
     * ID of the un-serialized model is used.
     *
     * @param data Binary blob of a model encoded using "binary" structural
     *        encoding.
     * @param sid Session ID to set for the model.
     * @returns An instance of a model.
     */
    static readonly load: <S extends NodeBuilder>(data: Uint8Array, sid?: number, schema?: S) => Model<SchemaToJsonNode<S>>;
    /**
     * Instantiates a model from a collection of patches. The patches are applied
     * to the model in the order they are provided. The session ID of the model is
     * set to the session ID of the first patch.
     *
     * @param patches A collection of initial patches to apply to the model.
     * @returns A model with the patches applied.
     */
    static fromPatches(patches: Patch[]): Model;
    /**
     * Root of the JSON document is implemented as Last Write Wins Register,
     * so that the JSON document does not necessarily need to be an object. The
     * JSON document can be any JSON value.
     */
    root: RootNode<N>;
    /**
     * Clock that keeps track of logical timestamps of the current editing session
     * and logical clocks of all known peers.
     */
    clock: clock.IClockVector;
    /**
     * Index of all known node objects (objects, array, strings, values)
     * in this document.
     *
     * @ignore
     */
    index: {
        min: import("sonic-forest/lib/types").ITreeNode<clock.ITimestampStruct, JsonNode<unknown>> | undefined;
        root: import("sonic-forest/lib/types").ITreeNode<clock.ITimestampStruct, JsonNode<unknown>> | undefined;
        max: import("sonic-forest/lib/types").ITreeNode<clock.ITimestampStruct, JsonNode<unknown>> | undefined;
        readonly comparator: import("sonic-forest/lib/types").Comparator<clock.ITimestampStruct>;
        set(k: clock.ITimestampStruct, v: JsonNode<unknown>): import("sonic-forest/lib/types").SonicNodePublicReference<import("sonic-forest/lib/types").ITreeNode<clock.ITimestampStruct, JsonNode<unknown>>>;
        find(k: clock.ITimestampStruct): import("sonic-forest/lib/types").SonicNodePublicReference<import("sonic-forest/lib/types").ITreeNode<clock.ITimestampStruct, JsonNode<unknown>>> | undefined;
        get(k: clock.ITimestampStruct): JsonNode<unknown> | undefined;
        del(k: clock.ITimestampStruct): boolean;
        clear(): void;
        has(k: clock.ITimestampStruct): boolean;
        _size: number;
        size(): number;
        isEmpty(): boolean;
        getOrNextLower(k: clock.ITimestampStruct): import("sonic-forest/lib/types").ITreeNode<clock.ITimestampStruct, JsonNode<unknown>> | undefined;
        forEach(fn: (node: import("sonic-forest/lib/types").ITreeNode<clock.ITimestampStruct, JsonNode<unknown>>) => void): void;
        first(): import("sonic-forest/lib/types").ITreeNode<clock.ITimestampStruct, JsonNode<unknown>> | undefined;
        last(): import("sonic-forest/lib/types").ITreeNode<clock.ITimestampStruct, JsonNode<unknown>> | undefined;
        readonly next: <N_1 extends import("sonic-forest/lib/types").HeadlessNode>(curr: N_1) => N_1 | undefined;
        iterator0(): () => import("sonic-forest/lib/types").ITreeNode<clock.ITimestampStruct, JsonNode<unknown>> | undefined;
        iterator(): Iterator<import("sonic-forest/lib/types").ITreeNode<clock.ITimestampStruct, JsonNode<unknown>>, any, undefined>;
        entries(): IterableIterator<import("sonic-forest/lib/types").ITreeNode<clock.ITimestampStruct, JsonNode<unknown>>>;
        toString(tab: string): string;
    };
    /**
     * Extensions to the JSON CRDT protocol. Extensions are used to implement
     * custom data types on top of the JSON CRDT protocol.
     *
     * @ignore
     * @todo Allow this to be `undefined`.
     */
    ext: Extensions;
    constructor(clockVector: clock.IClockVector);
    /** @ignore */
    private _api?;
    /**
     * API for applying local changes to the current document.
     */
    get api(): ModelApi<N>;
    /**
     * Experimental node retrieval API using proxy objects. Returns a strictly
     * typed proxy wrapper around the value of the root node.
     */
    get s(): import("./api/proxy").JsonNodeToProxyNode<N>;
    /**
     * Experimental strictly typed node retrieval API using proxy objects.
     * Automatically resolves nested "val" nodes.
     */
    get $(): import("./api/proxy").JsonNodeToProxyPathNode<N>;
    /**
     * Tracks number of times the `applyPatch` was called.
     *
     * @ignore
     */
    tick: number;
    /**
     * Applies a batch of patches to the document.
     *
     * @param patches A batch, i.e. an array of patches.
     */
    applyBatch(patches: Patch[]): void;
    /**
     * Callback called before every `applyPatch` call.
     */
    onbeforepatch?: (patch: Patch) => void;
    /**
     * Callback called after every `applyPatch` call.
     */
    onpatch?: (patch: Patch) => void;
    /**
     * Works like `applyPatch`, but is intended to be used by the local client
     * for locally generated patches. It checks if the model clock is ahead of
     * the patch clock and rebases the patch if necessary.
     *
     * @param patch A patch to apply to the document.
     */
    applyLocalPatch(patch: Patch): void;
    /**
     * Applies a single patch to the document. All mutations to the model must go
     * through this method. (With the only exception of local changes through API,
     * which have an alternative path.)
     *
     * @param patch A patch to apply to the document.
     */
    applyPatch(patch: Patch): void;
    /**
     * Applies a single operation to the model. All mutations to the model must go
     * through this method.
     *
     * For advanced use only, better use `applyPatch` instead. You MUST increment
     * the `tick` property and call the necessary event emitters manually.
     *
     * @param op Any JSON CRDT Patch operation
     * @ignore
     * @internal
     */
    applyOperation(op: JsonCrdtPatchOperation): void;
    /**
     * Recursively deletes a tree of nodes. Used when root node is overwritten or
     * when object contents of container node (object or array) is removed.
     *
     * @ignore
     */
    protected _gcTree(value: clock.ITimestampStruct): void;
    /**
     * Creates a copy of this model with a new session ID. If the session ID is
     * not provided, a random session ID is generated.
     *
     * @param sessionId Session ID to use for the new model.
     * @returns A copy of this model with a new session ID.
     */
    fork(sessionId?: number): Model<N>;
    /**
     * Creates a copy of this model with the same session ID.
     *
     * @returns A copy of this model with the same session ID.
     */
    clone(): Model<N>;
    /**
     * Callback called before model isi reset using the `.reset()` method.
     */
    onbeforereset?: () => void;
    /**
     * Callback called after model has been reset using the `.reset()` method.
     */
    onreset?: () => void;
    /**
     * Resets the model to equivalent state of another model.
     */
    reset(to: Model<N>): void;
    /**
     * Returns the view of the model.
     *
     * @returns JSON/CBOR of the model.
     */
    view(): Readonly<JsonNodeView<N>>;
    /**
     * Serialize this model using "binary" structural encoding.
     *
     * @returns This model encoded in octets.
     */
    toBinary(): Uint8Array;
    /**
     * Strictly types the model and sets the default value of the model, if
     * the document is empty.
     *
     * @param schema The schema to set for this model.
     * @param sid Session ID to use for setting the default value of the document.
     *            Defaults to `SESSION.GLOBAL` (2), which is the default session ID
     *            for all operations operations that are not attributed to a specific
     *            session.
     * @returns Strictly typed model.
     */
    setSchema<S extends NodeBuilder>(schema: S, useGlobalSession?: boolean): Model<SchemaToJsonNode<S>>;
    /**
     * Changes the session ID of the model. By modifying the attached clock vector
     * of the model. Be careful when changing the session ID of the model, as this
     * is an advanced operation.
     *
     * Use the {@link Model.load} method to load a model with the the right session
     * ID, instead of changing the session ID of the model. When in doubt, use the
     * {@link Model.fork} method to create a new model with the right session ID.
     *
     * @param sid The new session ID to set for the model.
     */
    setSid(sid: number): void;
    toString(tab?: string): string;
}
