import { expect } from "vitest";
import * as path from "path";
import { DebuggerDriver } from "./driver.js";
import { UIState } from "./uiState.js";
import { Checkpoint, resetGlobalCheckpointCounter } from "../runtime/state/checkpointStore.js";
import { getTestDir } from "../importPaths.js";
import { hasInterrupts } from "../runtime/interrupts.js";
export const fixtureDir = path.join(getTestDir(), "debugger");
// A programmatic DebuggerIO that feeds a scripted sequence of commands
// and records all render calls for assertions.
export class TestDebuggerIO {
    state = new UIState();
    commands;
    commandIndex = 0;
    renderCalls = [];
    rewindSelector = null;
    constructor(commands) {
        this.commands = commands;
    }
    async render(_checkpoint) {
        if (_checkpoint) {
            const checkpoint = Checkpoint.fromJSON(_checkpoint);
            if (checkpoint) {
                this.renderCalls.push(checkpoint);
                // console.log(JSON.stringify(checkpoint, null, 2));
                // console.log(color.green("[DBG]"), checkpoint.getLocation());
            }
        }
    }
    async waitForCommand() {
        const cmd = this.commands[this.commandIndex++];
        // console.log(color.green("[DBG]"), "Command", cmd);
        if (!cmd) {
            return { type: "quit" };
        }
        return cmd;
    }
    async showRewindSelector(checkpoints) {
        if (this.rewindSelector) {
            return this.rewindSelector(checkpoints);
        }
        return null;
    }
    async promptForNodeArgs(_parameters) {
        return [];
    }
    async promptForInput(_prompt) {
        const cmd = this.commands[this.commandIndex++];
        if (!cmd)
            return "";
        switch (cmd.type) {
            case "approve": return "approve";
            case "reject": return "reject";
            case "resolve": return `resolve ${JSON.stringify(cmd.value)}`;
            case "modify": return `modify ${Object.entries(cmd.overrides).map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(" ")}`;
            default: return "";
        }
    }
    async showCheckpointsPanel(_checkpoints) { }
    appendStdout(_text) { }
    renderActivityOnly() { }
    startSpinner() { }
    stopSpinner() { }
    destroy() { }
}
let importCounter = 0;
// Fresh import with cache-busting to get clean module state per test.
// Also resets the global checkpoint ID counter so IDs from different
// checkpoint stores (debugger vs context) remain comparable.
export async function freshImport(compiledFile) {
    resetGlobalCheckpointCounter();
    // eslint-disable-next-line no-restricted-syntax -- cache-busting dynamic import is required for fresh module state per test
    return await import(compiledFile + `?t=${importCounter++}`);
}
export function makeDriver(mod, ui, opts = {}) {
    const driver = new DebuggerDriver({
        mod: {
            respondToInterrupts: mod.respondToInterrupts,
            rewindFrom: mod.rewindFrom,
            __setDebugger: mod.__setDebugger,
            __getCheckpoints: mod.__getCheckpoints,
        },
        sourceMap: mod.__sourceMap ?? {},
        rewindSize: Math.max(30, opts.checkpoints?.length ?? 0),
        ui,
        checkpoints: opts.checkpoints,
    });
    mod.__setDebugger(driver.debuggerState);
    return driver;
}
export async function getInitialResult(mod, driver, ...args) {
    const callbacks = driver.getCallbacks();
    const initialResult = await mod.main(...args, { callbacks });
    expect(initialResult?.data).toBeDefined();
    expect(hasInterrupts(initialResult.data)).toBe(true);
    return initialResult;
}
