import { binding } from "./binding";
import { type CanonicalObjectSchema, type Constructor, type DefaultObject } from "./schema";
import type { ClassHelpers } from "./ClassHelpers";
import { type ObjectChangeCallback } from "./ObjectListeners";
import type { OmittedRealmTypes, Unmanaged } from "./Unmanaged";
import type { Realm } from "./Realm";
import type { Results } from "./Results";
import { OBJECT_HELPERS, OBJECT_INTERNAL, OBJECT_REALM } from "./symbols";
/**
 * The update mode to use when creating an object that already exists,
 * which is determined by a matching primary key.
 */
export declare enum UpdateMode {
    /**
     * Objects are only created. If an existing object exists (determined by a
     * matching primary key), an exception is thrown.
     */
    Never = "never",
    /**
     * If an existing object exists (determined by a matching primary key), only
     * properties where the value has actually changed will be updated. This improves
     * notifications and server side performance but also have implications for how
     * changes across devices are merged. For most use cases, the behavior will match
     * the intuitive behavior of how changes should be merged, but if updating an
     * entire object is considered an atomic operation, this mode should not be used.
     */
    Modified = "modified",
    /**
     * If an existing object exists (determined by a matching primary key), all
     * properties provided will be updated, any other properties will remain unchanged.
     */
    All = "all"
}
/** @internal */
export type ObjCreator = () => [binding.Obj, boolean];
type CreationContext = {
    helpers: ClassHelpers;
    createObj?: ObjCreator;
};
export type AnyRealmObject = RealmObject<any>;
export declare const KEY_ARRAY: unique symbol;
export declare const KEY_SET: unique symbol;
declare const INTERNAL_LISTENERS: unique symbol;
/**
 * Base class for a Realm Object.
 * @example
 * To define a class `Person` with required `name` and `age`
 * properties, define a `static schema`:
 * ```
 * class Person extends Realm.Object<Person> {
 *   _id!: Realm.BSON.ObjectId;
 *   name!: string;
 *   age!: number;
 *   static schema: Realm.ObjectSchema = {
 *     name: "Person",
 *     primaryKey: "_id",
 *     properties: {
 *       _id: "objectId",
 *       name: "string",
 *       age: "int",
 *     },
 *   };
 * }
 * ```
 * @example
 * If using the [@realm/babel-plugin](https://www.npmjs.com/package/@realm/babel-plugin):
 * To define a class `Person` with required `name` and `age` properties, they would
 * need to be specified in the type argument when it is being constructed to allow
 * Typescript-only model definitions:
 * ```
 * class Person extends Realm.Object<Person, "name" | "age"> {
 *   _id = new Realm.Types.ObjectId();
 *   name: Realm.Types.String;
 *   age: Realm.Types.Int;
 *   static primaryKey = "_id";
 * }
 * ```
 * @see {@link ObjectSchema}
 * @typeParam `T` - The type of this class (e.g. if your class is `Person`,
 * `T` should also be `Person` - this duplication is required due to how
 * TypeScript works)
 * @typeParam `RequiredProperties` - The names of any properties of this
 * class which are required when an instance is constructed with `new`. Any
 * properties not specified will be optional, and will default to a sensible
 * null value if no default is specified elsewhere.
 */
export declare class RealmObject<T = DefaultObject, RequiredProperties extends keyof OmittedRealmTypes<T> = never> {
    /**
     * This property is stored on the per class prototype when transforming the schema.
     * @internal
     */
    static [OBJECT_HELPERS]: ClassHelpers;
    static allowValuesArrays: boolean;
    /**
     * Optionally specify the primary key of the schema when using [@realm/babel-plugin](https://www.npmjs.com/package/@realm/babel-plugin).
     */
    static primaryKey?: string;
    /**
     * Optionally specify that the schema is an embedded schema when using [@realm/babel-plugin](https://www.npmjs.com/package/@realm/babel-plugin).
     */
    static embedded?: boolean;
    /**
     * Optionally specify that the schema should sync unidirectionally if using flexible sync when using [@realm/babel-plugin](https://www.npmjs.com/package/@realm/babel-plugin).
     */
    static asymmetric?: boolean;
    /**
     * Create an object in the database and set values on it
     * @internal
     */
    static create(realm: Realm, values: Record<string, unknown>, mode: UpdateMode, context: CreationContext): RealmObject;
    /**
     * Create an object in the database and populate its primary key value, if required
     * @internal
     */
    private static createObj;
    /**
     * Create a wrapper for accessing an object from the database
     * @internal
     */
    static createWrapper<T = DefaultObject>(internal: binding.Obj, constructor: Constructor): RealmObject<T> & T;
    /**
     * Create a `RealmObject` wrapping an `Obj` from the binding.
     * @param realm - The Realm managing the object.
     * @param values - The values of the object's properties at creation.
     */
    constructor(realm: Realm, values: Unmanaged<T, RequiredProperties>);
    /**
     * The Realm managing the object.
     * Note: this is on the injected prototype from ClassMap.defineProperties().
     * @internal
     */
    readonly [OBJECT_REALM]: Realm;
    /**
     * The object's representation in the binding.
     * @internal
     */
    readonly [OBJECT_INTERNAL]: binding.Obj;
    /**
     * Lazily created wrapper for the object notifier.
     * @internal
     */
    private [INTERNAL_LISTENERS];
    /**
     * Note: this is on the injected prototype from ClassMap.defineProperties()
     * @internal
     */
    private readonly [KEY_ARRAY];
    /**
     * Note: this is on the injected prototype from ClassMap.defineProperties()
     * @internal
     */
    private readonly [KEY_SET];
    /**
     * @returns An array of the names of the object's properties.
     * @deprecated Please use {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys | Object.keys()}
     */
    keys(): string[];
    /**
     * @returns An array of key/value pairs of the object's properties.
     * @deprecated Please use {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries | Object.entries()}
     */
    entries(): [string, unknown][];
    /**
     * The plain object representation for JSON serialization.
     * Use circular JSON serialization libraries such as [@ungap/structured-clone](https://www.npmjs.com/package/@ungap/structured-clone)
     * and [flatted](https://www.npmjs.com/package/flatted) to stringify Realm entities that have circular structures.
     * @returns A plain object.
     */
    toJSON(_?: string, cache?: unknown): DefaultObject;
    /**
     * Checks if this object has not been deleted and is part of a valid Realm.
     * @returns `true` if the object can be safely accessed, `false` if not.
     */
    isValid(): boolean;
    /**
     * The schema for the type this object belongs to.
     * @returns The {@link CanonicalObjectSchema} that describes this object.
     */
    objectSchema(): CanonicalObjectSchema<T>;
    /**
     * Returns all the objects that link to this object in the specified relationship.
     * @param objectType - The type of the objects that link to this object's type.
     * @param propertyName - The name of the property that references objects of this object's type.
     * @throws An {@link AssertionError} if the relationship is not valid.
     * @returns The {@link Results} that link to this object.
     */
    linkingObjects<T = DefaultObject>(objectType: string, propertyName: string): Results<RealmObject<T> & T>;
    linkingObjects<T extends AnyRealmObject>(objectType: Constructor<T>, propertyName: string): Results<T>;
    /**
     * Returns the total count of incoming links to this object
     * @returns The number of links to this object.
     */
    linkingObjectsCount(): number;
    /**
     * @deprecated
     * TODO: Remove completely once the type tests are abandoned.
     */
    _objectId(): string;
    /**
     * A string uniquely identifying the object across all objects of the same type.
     */
    _objectKey(): string;
    /**
     * Add a listener `callback` which will be called when a **live** object instance changes.
     * @param callback - A function to be called when changes occur.
     * @param keyPaths - Indicates a lower bound on the changes relevant for the listener. This is a lower bound, since if multiple listeners are added (each with their own `keyPaths`) the union of these key-paths will determine the changes that are considered relevant for all listeners registered on the object. In other words: A listener might fire more than the key-paths specify, if other listeners with different key-paths are present.
     * @throws A {@link TypeAssertionError} if `callback` is not a function.
     * @note
     * Adding the listener is an asynchronous operation, so the callback is invoked the first time to notify the caller when the listener has been added.
     * Thus, when the callback is invoked the first time it will contain an empty array for {@link Realm.ObjectChangeSet.changedProperties | changes.changedProperties}.
     *
     * Unlike {@link Collection.addListener}, changes on properties containing other objects (both standalone and embedded) will not trigger this listener.
     * @example
     * wine.addListener((obj, changes) => {
     *  // obj === wine
     *  console.log(`object is deleted: ${changes.deleted}`);
     *  console.log(`${changes.changedProperties.length} properties have been changed:`);
     *  changes.changedProperties.forEach(prop => {
     *      console.log(` ${prop}`);
     *   });
     * })
     * @example
     * wine.addListener((obj, changes) => {
     *  console.log("The wine got deleted or its brand might have changed");
     * }, ["brand"])
     */
    addListener(callback: ObjectChangeCallback<T>, keyPaths?: string | string[]): void;
    /**
     * Remove the listener `callback` from this object.
     * @throws A {@link TypeAssertionError} if `callback` is not a function.
     * @param callback A function previously added as listener
     */
    removeListener(callback: ObjectChangeCallback<T>): void;
    /**
     * Remove all listeners from this object.
     */
    removeAllListeners(): void;
    /**
     * Get underlying type of a property value.
     * @param propertyName - The name of the property to retrieve the type of.
     * @throws An {@link Error} if property does not exist.
     * @returns Underlying type of the property value.
     */
    getPropertyType(propertyName: string): string;
}
export {};
