/** @packageDocumentation
 * @module iModels
 */
import { BeEvent, DbConflictResolution, DbResult, Id64String, IModelStatus } from "@itwin/core-bentley";
import { EntityIdAndClassIdIterable, ModelGeometryChangesProps, ModelIdAndGeometryGuid } from "@itwin/core-common";
import { BriefcaseDb, SaveChangesArgs, StandaloneDb } from "./IModelDb";
import { RelationshipProps } from "./Relationship";
import { DbRebaseChangesetConflictArgs, RebaseChangesetConflictArgs } from "./internal/ChangesetConflictArgs";
/** A string that identifies a Txn.
 * @public @preview
 */
export type TxnIdString = string;
/** An error generated during dependency validation.
 * @see [[TxnManager.validationErrors]].
 * @public @preview
 */
export interface ValidationError {
    /** If true, txn is aborted. */
    fatal: boolean;
    /** The type of error. */
    errorType: string;
    /** Optional description of what went wrong. */
    message?: string;
}
/** Describes a set of [[Element]]s or [[Model]]s that changed as part of a transaction.
 * @see [[TxnManager.onElementsChanged]] and [[TxnManager.onModelsChanged]].
 * @public @preview
 */
export interface TxnChangedEntities {
    /** The entities that were inserted by the transaction. */
    readonly inserts: EntityIdAndClassIdIterable;
    /** The entities that were deleted by the transaction. */
    readonly deletes: EntityIdAndClassIdIterable;
    /** The entities that were modified by the transaction, including any [[Element]]s for which one of their [[ElementAspect]]s was changed. */
    readonly updates: EntityIdAndClassIdIterable;
}
/** Arguments supplied to [[TxnManager.queryLocalChanges]].
 * @beta
 */
export interface QueryLocalChangesArgs {
    /** If supplied and non-empty, restricts the results to include only EC instances belonging to the specified classes or subclasses thereof. */
    readonly includedClasses?: string[];
    /** If `true`, include changes that have not yet been saved. */
    readonly includeUnsavedChanges?: boolean;
}
/** Represents a change (insertion, deletion, or modification) to a single EC instance made in a local [[BriefcaseDb]].
 * @see [[TxnManager.queryLocalChanges]] to iterate all of the changed instances.
* @beta
*/
export interface ChangeInstanceKey {
    /** ECInstanceId of the instance. */
    id: Id64String;
    /** Fully-qualified class name of the instance. */
    classFullName: string;
    /** The type of change. */
    changeType: "inserted" | "updated" | "deleted";
}
/** Strictly for tests. @internal */
export declare function setMaxEntitiesPerEvent(max: number): number;
/**
 * @alpha
 * Transaction types
 */
export type TxnType = "Data" | "ECSchema" | "Ddl";
/**
 * @alpha
 * Transaction modes
 */
export type TxnMode = "direct" | "indirect";
/**
 * @alpha
 * Represents the properties of a transaction within the transaction manager.
 *
 * @property id - The unique identifier for the transaction.
 * @property sessionId - The identifier of the session to which the transaction belongs.
 * @property nextId - (Optional) The identifier of the next transaction in the sequence.
 * @property prevId - (Optional) The identifier of the previous transaction in the sequence.
 * @property props - The arguments or properties associated with the save changes operation.
 * @property type - The type of transaction, which can be "Data", "ECSchema", or "Ddl".
 * @property reversed - Indicates whether the transaction has been reversed.
 * @property grouped - Indicates whether the transaction is grouped with others.
 * @property timestamp - The timestamp when the transaction was created.
 */
export interface TxnProps {
    id: TxnIdString;
    sessionId: number;
    nextId?: TxnIdString;
    prevId?: TxnIdString;
    props: SaveChangesArgs;
    type: TxnType;
    reversed: boolean;
    grouped: boolean;
    timestamp: string;
}
/**
 * Manages the process of merging and rebasing local changes (transactions) in a [[BriefcaseDb]] or [[StandaloneDb]].
 *
 * The `RebaseManager` coordinates the rebase of local transactions when pulling and merging changes from other sources,
 * such as remote repositories or other users. It provides mechanisms to handle transaction conflicts, register custom conflict
 * handlers, and manage the rebase workflow. This includes resuming rebases, invoking user-defined handlers for conflict resolution,
 * and tracking the current merge/rebase state.
 *
 * Key responsibilities:
 * - Orchestrates the rebase of local transactions after a pull/merge operation.
 * - Allows registration and removal of custom conflict handlers to resolve changeset conflicts during rebase.
 * - Provides methods to check the current merge/rebase state.
 * - Raises events before and after each transaction is rebased.
 * - Ensures changes are saved or aborted appropriately based on the outcome of the rebase process.
 *
 * @alpha
 */
export declare class RebaseManager {
    private _iModel;
    private _conflictHandlers?;
    private _customHandler?;
    constructor(_iModel: BriefcaseDb | StandaloneDb);
    /**
     * Resumes the rebase process for the current iModel, applying any pending local changes
     * on top of the latest pulled changes from the remote source.
     *
     * This method performs the following steps:
     * 1. Begins the rebase process using the native database.
     * 2. Iterates through each transaction that needs to be rebased:
     *    - Retrieves transaction properties.
     *    - Raises events before and after rebasing each transaction.
     *    - Optionally reinstates local changes based on the rebase handler.
     *    - Optionally recomputes transaction data using the rebase handler.
     *    - Updates the transaction in the native database.
     * 3. Ends the rebase process and saves changes if the database is not read-only.
     * 4. Drops any restore point associated with the pull-merge operation.
     *
     * If an error occurs during the process, the rebase is aborted and the error is rethrown.
     *
     * @throws {Error} If a transaction cannot be found or if any step in the rebase process fails.
     */
    resume(): Promise<void>;
    /**
     * Determines whether the current transaction can be aborted.
     *
     * This method checks if a transaction is currently in progress and if a specific restore point,
     * identified by `BriefcaseManager.PULL_MERGE_RESTORE_POINT_NAME`, exists in the briefcase manager.
     *
     * @returns {boolean} Returns `true` if a transaction is in progress and the required restore point exists; otherwise, returns `false`.
     */
    canAbort(): boolean;
    /**
     * Aborts the current transaction by restoring the iModel to a predefined restore point.
     *
     * If a restore point is available (as determined by `canAbort()`), this method restores the iModel
     * to the state saved at the restore point named by `BriefcaseManager.PULL_MERGE_RESTORE_POINT_NAME`.
     * If no restore point is available, an error is thrown.
     *
     * @returns A promise that resolves when the restore operation is complete.
     * @throws {Error} If there is no restore point to abort to.
     */
    abort(): Promise<void>;
    /**
     * Sets the handler to be invoked for rebase operations.
     *
     * @param handler - The {@link RebaseHandler} to handle rebase events.
     */
    setCustomHandler(handler: RebaseHandler): void;
    /**
     * Determines whether a transaction is currently in progress.
     *
     * @returns {boolean} Returns `true` if there is an active transaction stage, otherwise `false`.
     */
    inProgress(): boolean;
    /**
     * Indicates whether the current transaction manager is in the "Rebasing" stage.
     *
     * This property checks the internal native database's merge stage to determine if a rebase operation is in progress.
     *
     * @returns `true` if the transaction manager is currently rebasing; otherwise, `false`.
     */
    get isRebasing(): boolean;
    /**
     * Indicates whether the current iModel is in the process of merging changes from a pull operation.
     *
     * @returns `true` if the iModel is currently merging changes; otherwise, `false`.
     */
    get isMerging(): boolean;
    /**
     * Attempts to resolve a changeset conflict by invoking registered conflict handlers in sequence.
     *
     * Iterates through the linked list of conflict handlers, passing the provided conflict arguments to each handler.
     * If a handler returns a defined resolution, logs the resolution and returns it immediately.
     * If no handler resolves the conflict, returns `undefined`.
     *
     * @param args - The arguments describing the changeset conflict to resolve.
     * @returns The conflict resolution provided by a handler, or `undefined` if no handler resolves the conflict.
     */
    onConflict(args: RebaseChangesetConflictArgs): DbConflictResolution | undefined;
    /**
     * Registers a new conflict handler for rebase changeset conflicts.
     *
     * @param args - An object containing:
     *   - `id`: A unique identifier for the conflict handler.
     *   - `handler`: A function that handles rebase changeset conflicts and returns a `DbConflictResolution` or `undefined`.
     * @throws IModelError if a conflict handler with the same `id` already exists.
     *
     * @remarks
     * Conflict handlers are used during changeset rebase operations to resolve conflicts.
     * Each handler must have a unique `id`. Attempting to register a handler with a duplicate `id` will result in an error.
     */
    addConflictHandler(args: {
        id: string;
        handler: (args: RebaseChangesetConflictArgs) => DbConflictResolution | undefined;
    }): void;
    /**
     * Removes a conflict handler from the internal linked list by its identifier.
     *
     * @param id - The unique identifier of the conflict handler to remove.
     *
     * If the handler with the specified `id` exists in the list, it will be removed.
     * If no handler with the given `id` is found, the method does nothing.
     */
    removeConflictHandler(id: string): void;
}
/** Manages local changes to a [[BriefcaseDb]] or [[StandaloneDb]] via [Txns]($docs/learning/InteractiveEditing.md)
 * @public @preview
 */
export declare class TxnManager {
    private _iModel;
    /** @internal */
    private _isDisposed;
    /** @internal */
    get isDisposed(): boolean;
    /** @internal */
    readonly rebaser: RebaseManager;
    /** @internal */
    constructor(_iModel: BriefcaseDb | StandaloneDb);
    /** Array of errors from dependency propagation */
    readonly validationErrors: ValidationError[];
    private get _nativeDb();
    private _getElementClass;
    private _getRelationshipClass;
    /** If a -watch file exists for this iModel, update its timestamp so watching processes can be
     * notified that we've modified the briefcase.
     * @internal Used by IModelDb on push/pull.
     */
    touchWatchFile(): void;
    /** @internal */
    protected _onBeforeOutputsHandled(elClassName: string, elId: Id64String): void;
    /** @internal */
    protected _onAllInputsHandled(elClassName: string, elId: Id64String): void;
    /** @internal */
    protected _onRootChanged(props: RelationshipProps): void;
    /** @internal */
    protected _onDeletedDependency(props: RelationshipProps): void;
    /** @internal */
    protected _onBeginValidate(): void;
    /** called from native code after validation of a Txn, either from saveChanges or apply changeset.
     * @internal
     */
    protected _onEndValidate(): void;
    /** @internal */
    protected _onGeometryChanged(modelProps: ModelGeometryChangesProps[]): void;
    /** @internal */
    protected _onGeometryGuidsChanged(changes: ModelIdAndGeometryGuid[]): void;
    /** @internal */
    protected _onCommit(): void;
    /** @internal */
    protected _onCommitted(): void;
    /** @internal */
    protected _onReplayExternalTxns(): void;
    /** @internal */
    protected _onReplayedExternalTxns(): void;
    /** @internal */
    protected _onChangesApplied(): void;
    /** @internal */
    protected _onBeforeUndoRedo(isUndo: boolean): void;
    /** @internal */
    protected _onAfterUndoRedo(isUndo: boolean): void;
    private _onRebaseLocalTxnConflict;
    /**
     * @alpha
     * Retrieves the txn properties for a given txn ID.
     *
     * @param id - The unique identifier of the transaction.
     * @returns The properties of the transaction if found; otherwise, `undefined`.
     */
    getTxnProps(id: TxnIdString): TxnProps | undefined;
    /**
     * @alpha
     * Iterates over all transactions in the sequence, yielding each transaction's properties.
     *
     * @yields {TxnProps} The properties of each transaction in the sequence.
     */
    queryTxns(): Generator<TxnProps>;
    /**
     * @alpha
     * Retrieves the properties of the last saved txn via `IModelDb.saveChanges()`, if available.
     *
     * @returns The properties of the last saved txn, or `undefined` if none exist.
     */
    getLastSavedTxnProps(): TxnProps | undefined;
    /** Dependency handlers may call method this to report a validation error.
     * @param error The error. If error.fatal === true, the transaction will cancel rather than commit.
     */
    reportError(error: ValidationError): void;
    /** Determine whether any fatal validation errors have occurred during dependency propagation.  */
    get hasFatalError(): boolean;
    /** @internal */
    readonly onEndValidation: BeEvent<() => void>;
    /** Called after validation completes from [[IModelDb.saveChanges]].
     * The argument to the event holds the list of elements that were inserted, updated, and deleted.
     * @note If there are many changed elements in a single Txn, the notifications are sent in batches so this event *may be called multiple times* per Txn.
     */
    readonly onElementsChanged: BeEvent<(changes: TxnChangedEntities) => void>;
    /** Called after validation completes from [[IModelDb.saveChanges]].
     * The argument to the event holds the list of models that were inserted, updated, and deleted.
     * @note If there are many changed models in a single Txn, the notifications are sent in batches so this event *may be called multiple times* per Txn.
     */
    readonly onModelsChanged: BeEvent<(changes: TxnChangedEntities) => void>;
    /** Event raised after the geometry within one or more [[GeometricModel]]s is modified by applying a changeset or validation of a transaction.
     * A model's geometry can change as a result of:
     *  - Insertion or deletion of a geometric element within the model; or
     *  - Modification of an existing element's geometric properties; or
     *  - An explicit request to flag it as changed via [[IModelDb.Models.updateModel]].
     */
    readonly onModelGeometryChanged: BeEvent<(changes: ReadonlyArray<ModelIdAndGeometryGuid>) => void>;
    readonly onGeometryChanged: BeEvent<(models: ModelGeometryChangesProps[]) => void>;
    /** Event raised before a commit operation is performed. Initiated by a call to [[IModelDb.saveChanges]], unless there are no changes to save. */
    readonly onCommit: BeEvent<() => void>;
    /** Event raised after a commit operation has been performed. Initiated by a call to [[IModelDb.saveChanges]], even if there were no changes to save. */
    readonly onCommitted: BeEvent<() => void>;
    /** Event raised after a ChangeSet has been applied to this briefcase */
    readonly onChangesApplied: BeEvent<() => void>;
    /** Event raised before an undo/redo operation is performed. */
    readonly onBeforeUndoRedo: BeEvent<(isUndo: boolean) => void>;
    /** Event raised after an undo/redo operation has been performed.
     * @param _action The action that was performed.
     */
    readonly onAfterUndoRedo: BeEvent<(isUndo: boolean) => void>;
    /** Event raised for a read-only briefcase that was opened with the `watchForChanges` flag enabled when changes made by another connection are applied to the briefcase.
     * @see [[onReplayedExternalTxns]] for the event raised after all such changes have been applied.
     */
    readonly onReplayExternalTxns: BeEvent<() => void>;
    /** Event raised for a read-only briefcase that was opened with the `watchForChanges` flag enabled when changes made by another connection are applied to the briefcase.
     * @see [[onReplayExternalTxns]] for the event raised before the changes are applied.
     */
    readonly onReplayedExternalTxns: BeEvent<() => void>;
    /**
     * @alpha
     * Event raised when a rebase transaction begins.
     */
    readonly onRebaseTxnBegin: BeEvent<(txn: TxnProps) => void>;
    /**
     * @alpha
     * Event raised when a rebase transaction ends.
     */
    readonly onRebaseTxnEnd: BeEvent<(txn: TxnProps) => void>;
    /**
     * if handler is set and it does not return undefined then default handler will not be called
     * @internal
     * */
    appCustomConflictHandler?: (args: DbRebaseChangesetConflictArgs) => DbConflictResolution | undefined;
    /**
     * Restart the current TxnManager session. This causes all Txns in the current session to no longer be undoable (as if the file was closed
     * and reopened.)
     * @note This can be quite disconcerting to the user expecting to be able to undo previously made changes. It should only be used
     * under extreme circumstances where damage to the file or session could happen if the currently committed are reversed. Use sparingly and with care.
     * Probably a good idea to alert the user it happened.
     */
    restartSession(): void;
    /** Determine whether current txn is propagating indirect changes or not. */
    get isIndirectChanges(): boolean;
    /** Determine if there are currently any reversible (undoable) changes from this editing session. */
    get isUndoPossible(): boolean;
    /** Determine if there are currently any reinstatable (redoable) changes */
    get isRedoPossible(): boolean;
    /** Get the description of the operation that would be reversed by calling reverseTxns(1).
     * This is useful for showing the operation that would be undone, for example in a menu.
     */
    getUndoString(): string;
    /** Get a description of the operation that would be reinstated by calling reinstateTxn.
     * This is useful for showing the operation that would be redone, in a pull-down menu for example.
     */
    getRedoString(): string;
    /** Begin a new multi-Txn operation. This can be used to cause a series of Txns that would normally
     * be considered separate actions for undo to be grouped into a single undoable operation. This means that when reverseTxns(1) is called,
     * the entire group of changes are undone together. Multi-Txn operations can be nested and until the outermost operation is closed
     * all changes constitute a single operation.
     * @note This method must always be paired with a call to endMultiTxnAction.
     */
    beginMultiTxnOperation(): DbResult;
    /** End a multi-Txn operation */
    endMultiTxnOperation(): DbResult;
    /** Return the depth of the multi-Txn stack. Generally for diagnostic use only. */
    getMultiTxnOperationDepth(): number;
    /** Reverse (undo) the most recent operation(s) to this IModelDb.
     * @param numOperations the number of operations to reverse. If this is greater than 1, the entire set of operations will
     *  be reinstated together when/if ReinstateTxn is called.
     * @note If there are any outstanding uncommitted changes, they are reversed.
     * @note The term "operation" is used rather than Txn, since multiple Txns can be grouped together via [[beginMultiTxnOperation]]. So,
     * even if numOperations is 1, multiple Txns may be reversed if they were grouped together when they were made.
     * @note If numOperations is too large only the operations are reversible are reversed.
     */
    reverseTxns(numOperations: number): IModelStatus;
    /** Reverse the most recent operation. */
    reverseSingleTxn(): IModelStatus;
    /** Reverse all changes back to the beginning of the session. */
    reverseAll(): IModelStatus;
    /** Reverse all changes back to a previously saved TxnId.
     * @param txnId a TxnId obtained from a previous call to GetCurrentTxnId.
     * @returns Success if the transactions were reversed, error status otherwise.
     * @see  [[getCurrentTxnId]] [[cancelTo]]
     */
    reverseTo(txnId: TxnIdString): IModelStatus;
    /** Reverse and then cancel (make non-reinstatable) all changes back to a previous TxnId.
     * @param txnId a TxnId obtained from a previous call to [[getCurrentTxnId]]
     * @returns Success if the transactions were reversed and cleared, error status otherwise.
     */
    cancelTo(txnId: TxnIdString): IModelStatus;
    /** Reinstate the most recently reversed transaction. Since at any time multiple transactions can be reversed, it
     * may take multiple calls to this method to reinstate all reversed operations.
     * @returns Success if a reversed transaction was reinstated, error status otherwise.
     * @note If there are any outstanding uncommitted changes, they are canceled before the Txn is reinstated.
     */
    reinstateTxn(): IModelStatus;
    /** Get the Id of the first transaction, if any.
     */
    queryFirstTxnId(): TxnIdString;
    /** Get the successor of the specified TxnId */
    queryNextTxnId(txnId: TxnIdString): TxnIdString;
    /** Get the predecessor of the specified TxnId */
    queryPreviousTxnId(txnId: TxnIdString): TxnIdString;
    /** Get the Id of the current (tip) transaction.  */
    getCurrentTxnId(): TxnIdString;
    /**
     * @alpha
     * Get the Id of the current session.
     */
    getCurrentSessionId(): number;
    /** Get the description that was supplied when the specified transaction was saved. */
    getTxnDescription(txnId: TxnIdString): string;
    /** Test if a TxnId is valid */
    isTxnIdValid(txnId: TxnIdString): boolean;
    /** Query if there are any pending Txns in this IModelDb that are waiting to be pushed.
     * @see [[IModelDb.pushChanges]]
     */
    get hasPendingTxns(): boolean;
    /**
     * Query if there are any changes in memory that have yet to be saved to the IModelDb.
     * @see [[IModelDb.saveChanges]]
     */
    get hasUnsavedChanges(): boolean;
    /**
     * @alpha
     * Query if there are any pending schema changes in this IModelDb.
     */
    get hasPendingSchemaChanges(): boolean;
    /**
     * Query if there are changes in memory that have not been saved to the iModelDb or if there are Txns that are waiting to be pushed.
     * @see [[IModelDb.saveChanges]]
     * @see [[IModelDb.pushChanges]]
     */
    get hasLocalChanges(): boolean;
    /** Destroy the record of all local changes that have yet to be saved and/or pushed.
     * This permanently eradicates your changes - use with caution!
     * Typically, callers will want to subsequently use [[LockControl.releaseAllLocks]].
     * After calling this function, [[hasLocalChanges]], [[hasPendingTxns]], and [[hasUnsavedChanges]] will all be `false`.
     */
    deleteAllTxns(): void;
    /** Obtain a list of the EC instances that have been changed locally by the [[BriefcaseDb]] associated with this `TxnManager` and have not yet been pushed to the iModel.
     * @beta
    */
    queryLocalChanges(args?: QueryLocalChangesArgs): Iterable<ChangeInstanceKey>;
    /** Query the number of bytes of memory currently allocated by SQLite to keep track of
     * changes to the iModel, for debugging/diagnostic purposes, as reported by [sqlite3session_memory_used](https://www.sqlite.org/session/sqlite3session_memory_used.html).
     */
    getChangeTrackingMemoryUsed(): number;
    /**
     * @alpha
     * Get the current transaction mode.
     * @returns The current transaction mode, either "direct" or "indirect".
     */
    getMode(): TxnMode;
    /**
     * @alpha
     * Execute a series of changes in an indirect transaction.
     * @param callback The function containing the changes to make.
     */
    withIndirectTxnMode(callback: () => void): void;
}
/**
 * Interface for handling rebase operations on transactions.
 * @alpha
 */
export interface RebaseHandler {
    /**
     * Determine whether a transaction should be reinstated during a rebase operation.
     * @param txn The transaction to check.
     *
     * @alpha
     */
    shouldReinstate(txn: TxnProps): boolean;
    /**
     * Recompute the changes for a given transaction.
     * @param txn The transaction to recompute.
     *
     * @alpha
     */
    recompute(txn: TxnProps): Promise<void>;
}
//# sourceMappingURL=TxnManager.d.ts.map