/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { makeRandom } from "@fluid-private/stochastic-test-utils";
import { unreachableCase } from "@fluidframework/core-utils";
import { makeAnonChange, revisionMetadataSourceFromInfo } from "../../core/index.js";
var Operation;
(function (Operation) {
    Operation[Operation["Rebase"] = 0] = "Rebase";
    Operation[Operation["Compose"] = 1] = "Compose";
    Operation[Operation["Invert"] = 2] = "Invert";
})(Operation || (Operation = {}));
/**
 *
 * @param rebaser - `ChangeRebaser` instance used to combine generated changes
 * @param changeGenerator - Random change generator function
 * @param seed - Seed used to randomly generate and combine the changes
 * @param maxCombinations - Maximum number of changes to combine in order
 * to produce the final change. Must be greater or equal to 0.
 * @returns A random change resulting from the combination of several random changes.
 */
export function generateFuzzyCombinedChange(rebaser, changeGenerator, seed, maxCombinations) {
    const random = makeRandom(seed);
    const rebase = rebaser.rebase.bind(rebaser);
    const compose = rebaser.compose.bind(rebaser);
    const invert = rebaser.invert.bind(rebaser);
    let change = changeGenerator(seed);
    // Rules for combining changes:
    // - We must not combine a change with itself
    // - We must not rebase a change over itself
    // - We must not rebase a change over its inverse
    // - We can only combine a change with its inverse if the inverse comes after the original
    // - We can only combine a change with its inverse if it hasn't already been combined with its inverse
    for (let i = random.integer(0, maxCombinations); i > 0; --i) {
        const operation = random.integer(Operation.Rebase, Operation.Invert);
        switch (operation) {
            case Operation.Rebase:
                change = rebase(change, makeAnonChange(changeGenerator(random.real())), revisionMetadataSourceFromInfo([]));
                break;
            case Operation.Compose:
                change = compose([
                    makeAnonChange(change),
                    makeAnonChange(changeGenerator(random.real())),
                ]);
                break;
            case Operation.Invert:
                // TODO: test rollback inversions as well
                change = invert(makeAnonChange(change), false);
                break;
            default:
                unreachableCase(operation);
        }
    }
    return change;
}
//# sourceMappingURL=fuzz.js.map