import { test, expect, vi } from "vitest";
import { openLix } from "../../lix/open-lix.js";
import { cacheMissSimulation } from "./cache-miss-simulation.js";
import { outOfOrderSequenceSimulation } from "./out-of-order-sequence-simulation.js";
import { engineBoundarySimulation } from "./engine-boundary-simulation.js";
/**
 * Normal simulation - Standard test execution without any modifications.
 */
const normalSimulation = {
    name: "normal",
    setup: async (lix) => lix,
};
// Default simulations available
export const defaultSimulations = [
    normalSimulation,
    // disabledQueryPreprocessorSimulation,
    cacheMissSimulation,
    engineBoundarySimulation,
];
// Export individual simulations for custom use
export { engineBoundarySimulation, normalSimulation, cacheMissSimulation, outOfOrderSequenceSimulation, };
export function simulationTest(name, fn, options) {
    // Use provided simulations or default ones
    const simulationsToRun = options?.simulations || defaultSimulations;
    const expectedValues = new Map();
    test.each(simulationsToRun)(`${name} > $name`, async (simulation) => {
        vi.restoreAllMocks();
        let callIndex = 0;
        const isFirstSimulation = simulation === simulationsToRun[0];
        const deterministicExpect = (actual, diffCallback) => {
            const key = `expect-${callIndex++}`;
            if (isFirstSimulation) {
                // Store expected values in first simulation
                expectedValues.set(key, actual);
            }
            else {
                // Verify values match first simulation in subsequent simulations
                const expected = expectedValues.get(key);
                if (expected !== undefined) {
                    // Check if values differ before invoking callback
                    let valuesMatch = false;
                    try {
                        expect(actual).toEqual(expected);
                        valuesMatch = true;
                    }
                    catch {
                        // Values don't match
                    }
                    // Only call diff callback if values actually differ
                    if (!valuesMatch && diffCallback) {
                        diffCallback({
                            actual,
                            expected,
                        });
                    }
                    // Always perform the assertion (will throw if values differ)
                    const errorMessage = `
SIMULATION DETERMINISM VIOLATION

expectDeterministic() failed: Values differ between simulations

Location: Call #${callIndex - 1}
Simulation: ${simulation.name} vs ${simulationsToRun[0]?.name || "normal"}

Use expectDeterministic() for values that must be identical across simulations.
Use regular expect() for simulation-specific assertions.

`;
                    expect(actual, errorMessage).toEqual(expected);
                }
            }
            return expect(actual);
        };
        // Create openSimulatedLix function
        const openSimulatedLix = async (args) => {
            // Open lix with the provided arguments
            const lix = await openLix(args);
            // Apply simulation setup
            return await simulation.setup(lix);
        };
        await fn({
            simulation: simulation,
            openSimulatedLix,
            expectDeterministic: deterministicExpect,
        });
        vi.restoreAllMocks(); // Restore original implementations, not just reset
    }, options?.timeout);
}
//# sourceMappingURL=simulation-test.js.map