/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { type TelemetryEventBatcher } from "@fluidframework/telemetry-utils/internal";
import { type ChangeFamily, type ChangeFamilyEditor, CommitKind, type GraphCommit, type RevisionTag, type TaggedChange, type RebaseStatsWithDuration } from "../core/index.js";
import type { Listenable } from "@fluidframework/core-interfaces";
/**
 * Describes a change to a `SharedTreeBranch`. Each of the following event types provides a `change` which contains the net change to the branch (or is undefined if there was no net change):
 * * Append - when one or more commits are appended to the head of the branch, for example via
 * a change applied by the branch's editor, or as a result of merging another branch into this one
 * * Remove - when one or more commits are removed from the head of the branch.
 * * Rebase - when a rebase operation adds commits from another branch and replaces existing commits with their rebased versions.
 */
export type SharedTreeBranchChange<TChange> = {
    type: "append";
    kind: CommitKind;
    change: TaggedChange<TChange>;
    /** The commits appended to the head of the branch by this operation */
    newCommits: readonly [GraphCommit<TChange>, ...GraphCommit<TChange>[]];
} | {
    type: "remove";
    change: TaggedChange<TChange>;
    /** The commits removed from the head of the branch by this operation */
    removedCommits: readonly [GraphCommit<TChange>, ...GraphCommit<TChange>[]];
} | {
    type: "rebase";
    change: TaggedChange<TChange> | undefined;
};
/**
 * The events emitted by a `SharedTreeBranch`
 */
export interface SharedTreeBranchEvents<TEditor extends ChangeFamilyEditor, TChange> extends BranchTrimmingEvents {
    /**
     * Fired just before the head of this branch changes.
     * @param change - the change to this branch's state and commits
     */
    beforeChange(change: SharedTreeBranchChange<TChange>): void;
    /**
     * Fired just after the head of this branch changes.
     * @param change - the change to this branch's state and commits
     */
    afterChange(change: SharedTreeBranchChange<TChange>): void;
    /**
     * Fired when this branch forks
     * @param fork - the new branch that forked off of this branch
     */
    fork(fork: SharedTreeBranch<TEditor, TChange>): void;
    /**
     * Fired after this branch is disposed
     */
    dispose(): void;
}
/**
 * Events related to branch trimming.
 *
 * @remarks
 * Trimming is a very specific kind of mutation which is the only allowed mutations to branches.
 * References to commits from other commits are removed so that the commit objects can be GC'd by the JS engine.
 * This happens by changing a commit's parent property to undefined, which drops all commits that are in its "ancestry".
 * It is done as a performance optimization when it is determined that commits are no longer needed for future computation.
 */
export interface BranchTrimmingEvents {
    /**
     * Fired when some contiguous range of commits beginning with the "global tail" of this branch are trimmed from the branch.
     * This happens by deleting the parent pointer to the last commit in that range. This event can be fired at any time.
     */
    ancestryTrimmed(trimmedRevisions: RevisionTag[]): void;
}
/**
 * A branch of changes that can be applied to a SharedTree.
 */
export declare class SharedTreeBranch<TEditor extends ChangeFamilyEditor, TChange> {
    #private;
    private head;
    readonly changeFamily: ChangeFamily<TEditor, TChange>;
    private readonly mintRevisionTag;
    private readonly branchTrimmer?;
    private readonly telemetryEventBatcher?;
    readonly events: Listenable<SharedTreeBranchEvents<TEditor, TChange>>;
    readonly editor: TEditor;
    private disposed;
    private readonly unsubscribeBranchTrimmer?;
    /**
     * Construct a new branch.
     * @param head - the head of the branch
     * @param changeFamily - determines the set of changes that this branch can commit
     * @param branchTrimmer - an optional event emitter that informs the branch it has been trimmed. If this is not supplied, then the branch must
     * never be trimmed. See {@link BranchTrimmingEvents} for details on trimming.
     */
    constructor(head: GraphCommit<TChange>, changeFamily: ChangeFamily<TEditor, TChange>, mintRevisionTag: () => RevisionTag, branchTrimmer?: Listenable<BranchTrimmingEvents> | undefined, telemetryEventBatcher?: TelemetryEventBatcher<keyof RebaseStatsWithDuration> | undefined);
    /**
     * Sets the head of this branch.
     * @remarks This is a "manual override" of sorts, for when the branch needs to be set to a certain state without going through the usual flow of edits.
     * This might be necessary as a performance optimization, or to prevent parts of the system updating incorrectly (this method emits no change events!).
     */
    setHead(head: GraphCommit<TChange>): void;
    /**
     * Apply a change to this branch.
     * @param change - the change to apply
     * @param kind - the kind of change to apply
     * @returns the change that was applied and the new head commit of the branch
     */
    apply(change: TaggedChange<TChange>, kind?: CommitKind): void;
    /**
     * @returns the commit at the head of this branch.
     */
    getHead(): GraphCommit<TChange>;
    /**
     * Spawn a new branch that is based off of the current state of this branch.
     * @param commit - The commit to base the new branch off of. Defaults to the head of this branch.
     * @remarks Changes made to the new branch will not be applied to this branch until the new branch is {@link SharedTreeBranch.merge | merged} back in.
     * Forks created during a transaction will be disposed when the transaction ends.
     */
    fork(commit?: GraphCommit<TChange>): SharedTreeBranch<TEditor, TChange>;
    /**
     * Rebase the changes that have been applied to this branch over divergent changes in the given branch.
     * After this operation completes, this branch will be based off of `branch`.
     *
     * @param branch - the branch to rebase onto
     * @param upTo - the furthest commit on `branch` over which to rebase (inclusive). Defaults to the head commit of `branch`.
     * @returns the result of the rebase or undefined if nothing changed
     */
    rebaseOnto(branch: SharedTreeBranch<TEditor, TChange>, upTo?: GraphCommit<TChange>): void;
    /**
     * Remove a range of commits from this branch.
     * @param commit - All commits after (but not including) this commit will be removed.
     * @returns The net change to this branch and the commits that were removed from this branch.
     */
    removeAfter(commit: GraphCommit<TChange>): void;
    /**
     * Apply all the divergent changes on the given branch to this branch.
     *
     * @param branch - the branch to merge into this branch
     * @returns the net change to this branch and the commits that were added to this branch by the merge,
     * or undefined if nothing changed
     */
    merge(branch: SharedTreeBranch<TEditor, TChange>): void;
    /** Rebase `branchHead` onto `onto`, but return undefined if nothing changed */
    private rebaseBranch;
    /**
     * Dispose this branch, freezing its state.
     *
     * @remarks
     * Attempts to further mutate the branch will error.
     * Any transactions in progress will be aborted.
     * Calling dispose more than once has no effect.
     */
    dispose(): void;
    private assertNotDisposed;
}
/**
 * Registers an event listener that fires when the given branch forks.
 * The listener will also fire when any of those forks fork, and when those forks of forks fork, and so on.
 * @param branch - the branch that will be listened to for forks
 * @param onFork - the fork event listener
 * @returns a function which when called will deregister all registrations (including transitive) created by this function.
 * The deregister function has undefined behavior if called more than once.
 */
export declare function onForkTransitive<T extends {
    events: Listenable<{
        fork(t: T): void;
    }>;
}>(branch: T, onFork: (fork: T) => void): () => void;
//# sourceMappingURL=branch.d.ts.map