"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
/* eslint-disable @typescript-eslint/no-non-null-assertion */
Object.defineProperty(exports, "__esModule", { value: true });
exports.defaultOptions = void 0;
const assert_1 = require("assert");
const stochastic_test_utils_1 = require("@fluid-private/stochastic-test-utils");
const mergeTreeOperationRunner_1 = require("./mergeTreeOperationRunner.cjs");
const testClient_1 = require("./testClient.cjs");
function applyMessagesWithReconnect(startingSeq, messageDatas, clients, logger, random) {
    let seq = startingSeq;
    const reconnectingClientIds = clients.length > 2 && random.bool()
        ? [clients[1].longClientId, clients[2].longClientId]
        : [clients[1].longClientId];
    const reconnectClientMsgs = new Map(reconnectingClientIds.map((id) => [id, []]));
    let minSeq = 0;
    // log and apply all the ops created in the round
    while (messageDatas.length > 0) {
        const [message, sg] = messageDatas.shift();
        (0, assert_1.strict)(message.clientId, "expected clientId to be defined");
        if (reconnectingClientIds.includes(message.clientId)) {
            reconnectClientMsgs.get(message.clientId).push([message.contents, sg]);
        }
        else {
            message.sequenceNumber = ++seq;
            clients.forEach((c) => c.applyMsg(message));
            minSeq = message.minimumSequenceNumber;
        }
    }
    const reconnectMsgs = [];
    reconnectClientMsgs.forEach((messageData, clientId) => {
        const client = clients.find(({ longClientId }) => longClientId === clientId);
        messageData.forEach(([op, segmentGroup]) => {
            const newMsg = client.makeOpMessage(client.regeneratePendingOp(op, segmentGroup));
            newMsg.minimumSequenceNumber = minSeq;
            // apply message doesn't use the segment group, so just pass undefined
            reconnectMsgs.push([newMsg, undefined]);
        });
    });
    return (0, mergeTreeOperationRunner_1.applyMessages)(seq, reconnectMsgs, clients, logger);
}
exports.defaultOptions = {
    minLength: 16,
    clients: { min: 2, max: 8 },
    opsPerRoundRange: { min: 40, max: 320 },
    rounds: 3,
    operations: [mergeTreeOperationRunner_1.annotateRange, mergeTreeOperationRunner_1.removeRange, mergeTreeOperationRunner_1.insert],
    growthFunc: (input) => input * 2,
};
// Generate a list of single character client names, support up to 69 clients
const clientNames = (0, mergeTreeOperationRunner_1.generateClientNames)();
function runReconnectFarmTests(opts, extraSeed) {
    (0, mergeTreeOperationRunner_1.doOverRange)(opts.clients, opts.growthFunc.bind(opts), (clientCount) => {
        it(`ReconnectFarm_${clientCount}_${extraSeed ?? 0}`, async () => {
            const random = (0, stochastic_test_utils_1.makeRandom)(0xdeadbeef, 0xfeedbed, clientCount, extraSeed ?? 0);
            const testOpts = { ...opts };
            if (extraSeed) {
                testOpts.resultsFilePostfix ?? (testOpts.resultsFilePostfix = "");
                testOpts.resultsFilePostfix += extraSeed;
            }
            const clients = [new testClient_1.TestClient()];
            clients.forEach((c, i) => c.startOrUpdateCollaboration(clientNames[i]));
            let seq = 0;
            clients.forEach((c) => c.updateMinSeq(seq));
            // Add double the number of clients each iteration
            const targetClients = Math.max(opts.clients.min, clientCount);
            for (let cc = clients.length; cc < targetClients; cc++) {
                const newClient = await testClient_1.TestClient.createFromClientSnapshot(clients[0], clientNames[cc]);
                clients.push(newClient);
            }
            seq = (0, mergeTreeOperationRunner_1.runMergeTreeOperationRunner)(random, seq, clients, testOpts.minLength, testOpts, applyMessagesWithReconnect);
        }).timeout(30 * 1000);
    });
}
(0, stochastic_test_utils_1.describeFuzz)("MergeTree.Client", ({ testCount }) => {
    const opts = exports.defaultOptions;
    if (testCount > 1) {
        (0, mergeTreeOperationRunner_1.doOverRange)({ min: 0, max: testCount - 1 }, (x) => x + 1, (seed) => {
            describe(`with seed ${seed}`, () => {
                runReconnectFarmTests(opts, seed);
            });
        });
    }
    else {
        runReconnectFarmTests(opts);
    }
});
//# sourceMappingURL=client.reconnectFarm.spec.cjs.map