"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkTextMatchRelative = exports.TestServer = void 0;
const internal_1 = require("@fluidframework/core-utils/internal");
const MergeTreeTextHelper_js_1 = require("../MergeTreeTextHelper.js");
const index_js_1 = require("../collections/index.js");
const mergeTreeNodes_js_1 = require("../mergeTreeNodes.js");
const testClient_js_1 = require("./testClient.js");
const clientSeqComparer = {
    min: { refSeq: -1, clientId: "" },
    compare: (a, b) => a.refSeq - b.refSeq,
};
/**
 * Server for tests.  Simulates client communication by directing placing
 * messages in client queues.
 */
class TestServer extends testClient_js_1.TestClient {
    constructor(options) {
        super(options);
        this.seq = 1;
        this.clients = [];
        this.clientSeqNumbers = new internal_1.Heap(clientSeqComparer);
        this.upstreamMap = new index_js_1.RedBlackTree(mergeTreeNodes_js_1.compareNumbers);
        this.minSeq = 0;
    }
    addClients(clients) {
        this.clientSeqNumbers = new internal_1.Heap(clientSeqComparer);
        this.clients = clients;
        for (const client of clients) {
            this.clientSeqNumbers.add({
                refSeq: client.getCurrentSeq(),
                clientId: client.longClientId ?? "",
            });
        }
    }
    applyMsg(msg) {
        super.applyMsg(msg);
        if (testClient_js_1.TestClient.useCheckQ) {
            const clid = this.getShortClientId(msg.clientId);
            return checkTextMatchRelative(msg.referenceSequenceNumber, clid, this, msg);
        }
        else {
            return false;
        }
    }
    // TODO: remove mappings when no longer needed using min seq
    // in upstream message
    transformUpstreamMessage(msg) {
        if (msg.referenceSequenceNumber > 0) {
            msg.referenceSequenceNumber =
                this.upstreamMap.get(msg.referenceSequenceNumber)?.data ?? 0;
        }
        msg.origin = {
            id: "A",
            sequenceNumber: msg.sequenceNumber,
            minimumSequenceNumber: msg.minimumSequenceNumber,
        };
        this.upstreamMap.put(msg.sequenceNumber, this.seq);
        msg.sequenceNumber = -1;
    }
    copyMsg(msg) {
        return {
            clientId: msg.clientId,
            clientSequenceNumber: msg.clientSequenceNumber,
            contents: msg.contents,
            minimumSequenceNumber: msg.minimumSequenceNumber,
            referenceSequenceNumber: msg.referenceSequenceNumber,
            sequenceNumber: msg.sequenceNumber,
            type: msg.type,
        };
    }
    applyMessages(msgCount) {
        let _msgCount = msgCount;
        while (_msgCount > 0) {
            const msg = this.dequeueMsg();
            if (msg) {
                if (msg.sequenceNumber >= 0) {
                    this.transformUpstreamMessage(msg);
                }
                msg.sequenceNumber = this.seq++;
                msg.minimumSequenceNumber = this.minSeq;
                if (this.applyMsg(msg)) {
                    return true;
                }
                if (this.clients) {
                    let minCli = this.clientSeqNumbers.peek()?.value;
                    if (minCli &&
                        minCli.clientId === msg.clientId &&
                        minCli.refSeq < msg.referenceSequenceNumber) {
                        // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
                        const cliSeq = this.clientSeqNumbers.get();
                        const oldSeq = cliSeq.refSeq;
                        cliSeq.refSeq = msg.referenceSequenceNumber;
                        this.clientSeqNumbers.add(cliSeq);
                        minCli = this.clientSeqNumbers.peek()?.value;
                        if (minCli && minCli.refSeq > oldSeq) {
                            msg.minimumSequenceNumber = minCli.refSeq;
                            this.minSeq = minCli.refSeq;
                        }
                    }
                    for (const client of this.clients) {
                        client.enqueueMsg(msg);
                    }
                }
            }
            else {
                break;
            }
            _msgCount--;
        }
        return false;
    }
}
exports.TestServer = TestServer;
/**
 * Used for in-memory testing.  This will queue a reference string for each client message.
 */
function checkTextMatchRelative(refSeq, clientId, server, msg) {
    const client = server.clients[clientId];
    const serverText = new MergeTreeTextHelper_js_1.MergeTreeTextHelper(server.mergeTree).getText(refSeq, clientId);
    const cliText = client.checkQ.shift()?.data;
    if (cliText === undefined || cliText !== serverText) {
        console.log(`mismatch `);
        console.log(msg);
        // eslint-disable-next-line @typescript-eslint/no-base-to-string
        console.log(server.mergeTree.toString());
        // eslint-disable-next-line @typescript-eslint/no-base-to-string
        console.log(client.mergeTree.toString());
        return true;
    }
    return false;
}
exports.checkTextMatchRelative = checkTextMatchRelative;
//# sourceMappingURL=testServer.js.map