import type { O } from "ts-toolbelt";
import { creationDataTypeSymbol, dataTypeSymbol, ModelClass } from "../modelShared/BaseModelShared";
import type { SnapshotInOfModel, SnapshotInOfObject, SnapshotOutOfModel } from "../snapshot/SnapshotOf";
import type { TypeCheckError } from "../typeChecking/TypeCheckError";
import { modelIdKey, modelTypeKey } from "./metadata";
/**
 * @ignore
 */
export declare const modelIdPropertyNameSymbol: unique symbol;
/**
 * Base abstract class for models. Use `Model` instead when extending.
 *
 * Never override the constructor, use `onInit` or `onAttachedToRootStore` instead.
 *
 * @typeparam Data Data type.
 * @typeparam CreationData Creation data type.
 * @typeparam ModelIdPropertyName Model id property name.
 */
export declare abstract class BaseModel<Data extends {
    [k: string]: any;
}, CreationData extends {
    [k: string]: any;
}, ModelIdPropertyName extends string = typeof modelIdKey> {
    [dataTypeSymbol]: Data;
    [creationDataTypeSymbol]: CreationData;
    [modelIdPropertyNameSymbol]: ModelIdPropertyName;
    /**
     * Model type name.
     */
    readonly [modelTypeKey]: string;
    /**
     * Model internal id. Can be modified inside a model action.
     */
    get [modelIdKey](): string;
    set [modelIdKey](newId: string);
    /**
     * Can be overriden to offer a reference id to be used in reference resolution.
     * By default it will use the model id property (usually `$modelId` unless overridden).
     */
    getRefId(): string;
    /**
     * Called after the model has been created.
     */
    protected onInit?(): void;
    /**
     * Data part of the model, which is observable and will be serialized in snapshots.
     * Use it if one of the data properties matches one of the model properties/functions.
     */
    readonly $: Data;
    /**
     * Optional hook that will run once this model instance is attached to the tree of a model marked as
     * root store via `registerRootStore`.
     * Basically this is the place where you know the full root store is complete and where things such as
     * middlewares, effects (reactions, etc), and other side effects should be registered, since it means
     * that the model is now part of the active application state.
     *
     * It can return a disposer that will be run once this model instance is detached from such root store tree.
     *
     * @param rootStore
     * @returns
     */
    protected onAttachedToRootStore?(rootStore: object): (() => void) | void;
    /**
     * Optional transformation that will be run when converting from a snapshot to the data part of the model.
     * Useful for example to do versioning and keep the data part up to date with the latest version of the model.
     *
     * @param snapshot The custom input snapshot.
     * @returns An input snapshot that must match the current model input snapshot.
     */
    fromSnapshot?(snapshot: {
        [k: string]: any;
    }): SnapshotInOfObject<CreationData> & {
        [modelTypeKey]?: string;
    };
    /**
     * Performs a type check over the model instance.
     * For this to work a data type has to be declared as part of the model properties.
     *
     * @returns A `TypeCheckError` or `null` if there is no error.
     */
    typeCheck(): TypeCheckError | null;
    /**
     * Creates an instance of a model.
     */
    constructor(data: CreationData);
    toString(options?: {
        withData?: boolean;
    }): string;
}
/**
 * @ignore
 */
export declare type BaseModelKeys = keyof AnyModel | "onInit" | "onAttachedToRootStore";
/**
 * Any kind of model instance.
 */
export interface AnyModel extends BaseModel<any, any, any> {
}
/**
 * @deprecated Should not be needed anymore.
 *
 * Tricks Typescript into accepting abstract classes as a parameter for `ExtendedModel`.
 * Does nothing in runtime.
 *
 * @typeparam T Abstract model class type.
 * @param type Abstract model class.
 * @returns
 */
export declare function abstractModelClass<T>(type: T): T & Object;
/**
 * The model id property name.
 */
export declare type ModelIdPropertyName<M extends AnyModel> = M[typeof modelIdPropertyNameSymbol];
/**
 * Add missing model metadata to a model creation snapshot to generate a proper model snapshot.
 * Usually used alongside `fromSnapshot`.
 *
 * @typeparam M Model type.
 * @param modelClass Model class.
 * @param snapshot Model creation snapshot without metadata.
 * @param [internalId] Model internal ID, or `undefined` to generate a new one.
 * @returns The model snapshot (including metadata).
 */
export declare function modelSnapshotInWithMetadata<M extends AnyModel>(modelClass: ModelClass<M>, snapshot: O.Omit<SnapshotInOfModel<M>, ModelIdPropertyName<M> | typeof modelTypeKey>, internalId?: string): SnapshotInOfModel<M>;
/**
 * Add missing model metadata to a model output snapshot to generate a proper model snapshot.
 * Usually used alongside `applySnapshot`.
 *
 * @typeparam M Model type.
 * @param modelClass Model class.
 * @param snapshot Model output snapshot without metadata.
 * @param [internalId] Model internal ID, or `undefined` to generate a new one.
 * @returns The model snapshot (including metadata).
 */
export declare function modelSnapshotOutWithMetadata<M extends AnyModel>(modelClass: ModelClass<M>, snapshot: O.Omit<SnapshotOutOfModel<M>, ModelIdPropertyName<M> | typeof modelTypeKey>, internalId?: string): SnapshotOutOfModel<M>;
/**
 * A model class declaration, made of a base model and the model interface.
 */
export declare type ModelClassDeclaration<BaseModelClass, ModelInterface> = BaseModelClass & {
    new (...args: any[]): ModelInterface;
};
