"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.ReconnectTestHelper = void 0;
const node_assert_1 = require("node:assert");
const index_js_1 = require("../index.js");
const testClientLogger_js_1 = require("./testClientLogger.js");
const ClientIds = ["A", "B", "C", "D"];
class ReconnectTestHelper {
    idxFromName(name) {
        return (name.codePointAt(0) ?? 0) - ("A".codePointAt(0) ?? 0);
    }
    constructor(options = {}) {
        this.ops = [];
        this.seq = 0;
        this.clients = (0, testClientLogger_js_1.createClientsAtInitialState)({
            initialState: "",
            options: {
                mergeTreeEnableObliterate: true,
                mergeTreeEnableObliterateReconnect: true,
                ...options,
            },
        }, ...ClientIds);
        this.logger = new testClientLogger_js_1.TestClientLogger(this.clients.all);
        this.perClientOps = this.clients.all.map(() => []);
    }
    insertText(clientName, pos, text) {
        const client = this.clients[clientName];
        this.ops.push(client.makeOpMessage(client.insertTextLocal(pos, text), ++this.seq));
    }
    removeRange(clientName, start, end) {
        const client = this.clients[clientName];
        this.ops.push(client.makeOpMessage(client.removeRangeLocal(start, end), ++this.seq));
    }
    obliterateRange(clientName, start, end) {
        const client = this.clients[clientName];
        this.ops.push(client.makeOpMessage(
        // TODO: remove type assertions when sidedness is enabled
        client.obliterateRangeLocal(start, end), ++this.seq));
    }
    insertTextLocal(clientName, pos, text) {
        const client = this.clients[clientName];
        const op = client.insertTextLocal(pos, text);
        (0, node_assert_1.strict)(op);
        const seg = client.peekPendingSegmentGroups();
        (0, node_assert_1.strict)(seg);
        return { op, seg, refSeq: client.getCollabWindow().currentSeq };
    }
    removeRangeLocal(clientName, start, end) {
        const client = this.clients[clientName];
        const op = client.removeRangeLocal(start, end);
        (0, node_assert_1.strict)(op);
        const seg = client.peekPendingSegmentGroups();
        (0, node_assert_1.strict)(seg);
        return { op, seg, refSeq: client.getCollabWindow().currentSeq };
    }
    obliterateRangeLocal(clientName, start, end) {
        const client = this.clients[clientName];
        let { startPos, endPos } = (0, index_js_1.endpointPosAndSide)(start, end);
        (0, node_assert_1.strict)(startPos !== undefined && endPos !== undefined, "start and end positions must be defined");
        startPos = startPos === "start" ? 0 : startPos;
        endPos = endPos === "end" ? client.getLength() : endPos;
        (0, node_assert_1.strict)(startPos !== "end" && endPos !== "start", "start cannot be end and end cannot be start");
        const op = client.obliterateRangeLocal(startPos, endPos);
        (0, node_assert_1.strict)(op);
        const seg = client.peekPendingSegmentGroups();
        (0, node_assert_1.strict)(seg);
        return { op, seg, refSeq: client.getCollabWindow().currentSeq };
    }
    disconnect(clientNames) {
        const clientIdxs = new Set(clientNames.map((element) => this.idxFromName(element)));
        for (const op of this.ops.splice(0))
            for (const [i, c] of this.clients.all.entries()) {
                if (clientIdxs.has(i)) {
                    this.perClientOps[i].push(op);
                }
                else {
                    c.applyMsg(op);
                }
            }
    }
    processAllOps() {
        for (const op of this.ops.splice(0))
            for (const c of this.clients.all) {
                c.applyMsg(op);
            }
    }
    reconnect(clientNames) {
        const clientIdxs = new Set(clientNames.map((element) => this.idxFromName(element)));
        for (const [i, clientOps] of this.perClientOps.entries()) {
            if (clientIdxs.has(i)) {
                for (const op of clientOps.splice(0))
                    this.clients.all[i].applyMsg(op);
            }
        }
    }
    submitDisconnectedOp(clientName, op) {
        const client = this.clients[clientName];
        this.ops.push(client.makeOpMessage(client.regeneratePendingOp(op.op, op.seg), ++this.seq));
    }
}
exports.ReconnectTestHelper = ReconnectTestHelper;
//# sourceMappingURL=reconnectHelper.js.map