/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
/* eslint-disable import-x/no-nodejs-modules */
import { strict as assert } from "node:assert";
import { mkdirSync, readFileSync } from "node:fs";
import { TypedEventEmitter } from "@fluid-internal/client-utils";
import { asyncGeneratorFromArray, createFuzzDescribe, defaultOptions, getSaveDirectory, getSaveInfo, makeRandom, performFuzzActionsAsync, } from "@fluid-private/stochastic-test-utils";
import { MockFluidDataStoreRuntime } from "@fluidframework/test-runtime-utils/internal";
import { MockContainerRuntimeFactoryForSummarizer, } from "./summarizerFuzzMocks.js";
/**
 * @internal
 */
export const defaultSummarizerFuzzSuiteOptions = {
    defaultTestCount: defaultOptions.defaultTestCount,
    emitter: new TypedEventEmitter(),
    only: [],
    skip: [],
    saveFailures: false,
    parseOperations: (serialized) => JSON.parse(serialized),
};
export function createSummarizerFuzzSuite(model, providedOptions) {
    const options = {
        ...defaultSummarizerFuzzSuiteOptions,
        ...providedOptions,
    };
    const only = new Set(options.only);
    const skip = new Set(options.skip);
    Object.assign(options, { only, skip });
    assert(isInternalOptions(options));
    const describeFuzz = createFuzzDescribe({ defaultTestCount: options.defaultTestCount });
    describeFuzz(model.workloadName, ({ testCount }) => {
        before(() => {
            if (options.saveFailures !== undefined && options.saveFailures !== false) {
                mkdirSync(getSaveDirectory(options.saveFailures.directory, model), {
                    recursive: true,
                });
            }
        });
        for (let seed = 0; seed < testCount; seed++) {
            runTest(model, options, seed, getSaveInfo(model, options, seed));
        }
        if (options.replay !== undefined) {
            const seed = options.replay;
            describe.only(`replay from file`, () => {
                const saveInfo = getSaveInfo(model, options, seed);
                assert(saveInfo.saveOnFailure !== false, "Cannot replay a file without a directory to save files in!");
                const operations = options.parseOperations(readFileSync(saveInfo.saveOnFailure.path).toString());
                const replayModel = {
                    ...model,
                    // We lose some type safety here because the options interface isn't generic
                    generatorFactory: () => asyncGeneratorFromArray(operations),
                };
                runTest(replayModel, options, seed, undefined);
            });
        }
    });
}
/**
 * Runs the provided Summarizer fuzz model. All functionality is already assumed to be mixed in.
 * @privateRemarks This is currently file-exported for testing purposes, but it could be reasonable to
 * expose at the package level if we want to expose some of the harness's building blocks.
 */
async function runTestForSeed(model, options, seed, saveInfo) {
    const random = makeRandom(seed);
    const containerRuntimeFactory = new MockContainerRuntimeFactoryForSummarizer(options.containerRuntimeOptions);
    const containerRuntime = containerRuntimeFactory.createContainerRuntime(new MockFluidDataStoreRuntime());
    const initialState = {
        containerRuntimeFactory,
        random,
        containerRuntime,
    };
    options.emitter.emit("testStart", initialState);
    const finalState = await performFuzzActionsAsync(model.generatorFactory(), model.reducer, initialState, saveInfo);
    const oldRuntime = finalState.containerRuntime;
    oldRuntime.disposeFn();
    const newRuntime = containerRuntimeFactory.createContainerRuntime(new MockFluidDataStoreRuntime());
    await newRuntime.initializeWithStashedOps(oldRuntime);
    await newRuntime.summarize();
    options.emitter.emit("testEnd", finalState);
    return finalState;
}
function runTest(model, options, seed, saveInfo) {
    const itFn = options.only.has(seed) ? it.only : options.skip.has(seed) ? it.skip : it;
    itFn(`seed ${seed}`, async () => {
        const inCi = process.env.TF_BUILD !== undefined;
        await runTestForSeed(model, options, seed, inCi ? undefined : saveInfo);
    });
}
function isInternalOptions(options) {
    return options.only instanceof Set && options.skip instanceof Set;
}
//# sourceMappingURL=summarizerFuzzSuite.js.map