"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.MockContainerRuntimeForSummarizer = exports.MockContainerRuntimeFactoryForSummarizer = void 0;
const client_utils_1 = require("@fluid-internal/client-utils");
const driver_definitions_1 = require("@fluidframework/driver-definitions");
const internal_1 = require("@fluidframework/driver-definitions/internal");
const internal_2 = require("@fluidframework/runtime-utils/internal");
const internal_3 = require("@fluidframework/telemetry-utils/internal");
const internal_4 = require("@fluidframework/test-runtime-utils/internal");
const uuid_1 = require("uuid");
const index_js_1 = require("../../summary/index.js");
class MockContainerRuntimeFactoryForSummarizer extends internal_4.MockContainerRuntimeFactoryForReconnection {
    createContainerRuntime(dataStoreRuntime, _) {
        const containerRuntime = new MockContainerRuntimeForSummarizer(dataStoreRuntime, this, this.runtimeOptions);
        this.runtimes.add(containerRuntime);
        return containerRuntime;
    }
}
exports.MockContainerRuntimeFactoryForSummarizer = MockContainerRuntimeFactoryForSummarizer;
const DefaultSummaryConfiguration = {
    state: "disableHeuristics",
    maxAckWaitTime: 3 * 60 * 1000, // 3 mins.
    maxOpsSinceLastSummary: 7000,
    initialSummarizerDelayMs: 5 * 1000, // 5 secs.
};
class MockContainerRuntimeForSummarizer extends internal_4.MockContainerRuntimeForReconnection {
    constructor(dataStoreRuntime, factory, runtimeOptions = {}) {
        // trackRemoteOps is needed for replaying all ops on creating new ContainerRuntime
        super(dataStoreRuntime, factory, runtimeOptions, { trackRemoteOps: true });
        this.baseLogger = (0, internal_3.createChildLogger)();
        this.nackScheduled = false;
        this.disposed = false;
        this.deltaManager.on("op", (message) => {
            this.emit("op", message);
        });
        this.summarizerClientElection = new MockSummarizerClientElection(this.clientId);
        this.connectedState = new MockConnectedState(this.baseLogger, this.clientId);
        this.summaryCollection = new index_js_1.SummaryCollection(this.deltaManager, this.baseLogger);
        const summaryConfiguration = {
            ...DefaultSummaryConfiguration,
            ...runtimeOptions.summaryConfiguration,
        };
        this.summarizer = new index_js_1.Summarizer(this /* summarizerRuntime */, () => summaryConfiguration /* configurationGetter */, this /* ISummarizerInternalsProvider */, {} /* handleContext */, this.summaryCollection, async (runtime) => index_js_1.RunWhileConnectedCoordinator.create(runtime, () => this.deltaManager.active));
        this.summaryManager = new index_js_1.SummaryManager(this.summarizerClientElection, this.connectedState, this.summaryCollection, this.baseLogger, async () => this.summarizer, new MockThrottler());
        this.summaryManager.start();
    }
    /**
     * Prepare a SummaryNack to be sent by the server
     */
    prepareSummaryNack() {
        this.nackScheduled = true;
    }
    /**
     * Call on the Summarizer object to summarize
     */
    async summarize() {
        const result = this.summarizer.summarizeOnDemand({
            reason: "fuzzTest",
            retryOnFailure: false,
        });
        await Promise.all([
            result.summarySubmitted,
            result.summaryOpBroadcasted,
            result.receivedSummaryAckOrNack,
        ]);
    }
    async submitSummary(options) {
        const handle = (0, uuid_1.v4)();
        const summaryMessage = {
            handle,
            head: "",
            message: "",
            parents: [],
        };
        const clientSequenceNumber = ++this.deltaManager.clientSequenceNumber;
        const referenceSequenceNumber = this.deltaManager.lastSequenceNumber;
        const minimumSequenceNumber = this.factory.getMinSeq();
        const summarizeMessage = {
            type: internal_1.MessageType.Summarize,
            clientSequenceNumber,
            referenceSequenceNumber,
            contents: summaryMessage,
        };
        this.deltaManager.outbound.push([summarizeMessage]);
        this.addPendingMessage(summarizeMessage.contents, summarizeMessage.metadata, summarizeMessage.clientSequenceNumber);
        this.factory.processAllMessages();
        this.scheduleAckNack(this.nackScheduled /* isNack */, handle, this.deltaManager.lastSequenceNumber);
        this.nackScheduled = false;
        const summaryStats = {
            ...(0, internal_2.mergeStats)(),
            dataStoreCount: 1,
            summarizedDataStoreCount: 1,
            summaryNumber: 1,
        };
        return {
            stage: "submit",
            handle,
            clientSequenceNumber,
            referenceSequenceNumber,
            minimumSequenceNumber,
            submitOpDuration: 0,
            uploadDuration: 0,
            generateDuration: 0,
            summaryTree: {
                type: driver_definitions_1.SummaryType.Tree,
                tree: {},
            },
            summaryStats,
        };
    }
    scheduleAckNack(isNack, handle, summarySequenceNumber) {
        // eslint-disable-next-line @typescript-eslint/no-floating-promises
        Promise.resolve().then(() => {
            const contents = {
                handle,
                summaryProposal: {
                    summarySequenceNumber,
                },
            };
            const summaryAckMessage = {
                type: isNack ? internal_1.MessageType.SummaryNack : internal_1.MessageType.SummaryAck,
                clientSequenceNumber: ++this.deltaManager.clientSequenceNumber,
                referenceSequenceNumber: this.deltaManager.lastSequenceNumber,
                contents,
            };
            this.deltaManager.outbound.push([summaryAckMessage]);
            this.addPendingMessage(summaryAckMessage.contents, undefined, summaryAckMessage.clientSequenceNumber);
            this.factory.processAllMessages();
        });
    }
    async refreshLatestSummaryAck(options) {
        // Do nothing
    }
    setConnectedState(value) {
        super.setConnectedState(value);
        this.connectedState.setConnectedState(value, this.clientId);
        this.summarizerClientElection.setClientId(this.clientId);
    }
    closeFn() {
        this.disposeFn();
    }
    disposeFn() {
        this.connected = false;
        this.disposed = true;
        this.summaryManager.dispose();
        this.summarizer.dispose();
        this.deltaManager.dispose();
    }
}
exports.MockContainerRuntimeForSummarizer = MockContainerRuntimeForSummarizer;
class MockSummarizerClientElection extends client_utils_1.TypedEventEmitter {
    constructor(clientId) {
        super();
        this.setClientId(clientId);
    }
    setClientId(clientId) {
        this.electedClientId = clientId;
        this.electedParentId = clientId;
    }
}
class MockConnectedState extends client_utils_1.TypedEventEmitter {
    constructor(logger, clientId) {
        super();
        this.logger = logger;
        this.clientId = clientId;
        this.connected = false;
    }
    setConnectedState(connected, clientId) {
        if (this.connected === connected) {
            return;
        }
        this.clientId = clientId;
        (0, internal_3.raiseConnectedEvent)(this.logger, this, connected, clientId);
    }
}
class MockThrottler {
    constructor() {
        this.getDelay = () => 0;
        this.numAttempts = 3;
        this.delayWindowMs = 0;
        this.maxDelayMs = 0;
        this.delayFn = () => 0;
    }
}
//# sourceMappingURL=summarizerFuzzMocks.js.map