"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.setCurrentStepCommand = void 0;
exports.setCurrentStep = setCurrentStep;
const debugFailWrapper_1 = require("../util/debugFailWrapper");
const constants_1 = require("../../../constants");
const debugCommands_1 = require("../../debugCommands");
const DebugSession_1 = require("@mablhq-internal/runtime/debug/DebugSession");
const expandSteps_1 = require("@mablhq-internal/runtime/debug/expandSteps");
const resolveStepReference_1 = require("@mablhq-internal/runtime/debug/resolveStepReference");
const buildDebugSessionState_1 = require("@mablhq-internal/runtime/debug/buildDebugSessionState");
const stepIndexUtils_1 = require("@mablhq-internal/runtime/trainer/sharedUtils/stepIndexUtils");
const cursorOperations_1 = require("@mablhq-internal/runtime/trainer/generation/cursorOperations");
exports.setCurrentStepCommand = (0, debugCommands_1.defineLeaf)({
    command: `set-current-step <${constants_1.CommandArgSessionId}> <${constants_1.CommandArgStepId}>`,
    describe: 'Move the execution cursor to a step (no execution — agent owns browser state). Accepts a step id or 1-based dot-notation position (e.g. "3.2").',
    builder: (yargs) => {
        yargs
            .positional(constants_1.CommandArgSessionId, {
            type: 'string',
            demandOption: true,
            describe: 'Debug session id (returned by `session start`).',
        })
            .positional(constants_1.CommandArgStepId, {
            type: 'string',
            demandOption: true,
            describe: 'Step id (UUID) OR 1-based dot-notation position (e.g. "3.2"). Nested addressing ("3.2") requires step 3 to be a step-group / reusable-flow wrapper; for a leaf, use the bare position ("3"). Run `list-steps` to discover both shapes.',
        });
    },
    handler: (0, debugFailWrapper_1.debugFailWrapper)(setCurrentStep),
});
async function setCurrentStep(parsed) {
    const sessionId = parsed[constants_1.CommandArgSessionId];
    const target = parsed[constants_1.CommandArgStepId];
    const session = (0, DebugSession_1.readSession)(sessionId);
    let outcome;
    const applied = await (0, buildDebugSessionState_1.mutateDebugState)(sessionId, (state) => {
        outcome = applyCursorMove(state, session.snapshot, target);
    });
    if (!applied) {
        process.stderr.write(`No state.json on disk for session ${sessionId}. Start a session before moving the cursor.\n`);
        process.exit(2);
        return;
    }
    if (!outcome) {
        process.stderr.write('set-current-step: internal error (no outcome)\n');
        process.exit(2);
        return;
    }
    if (!outcome.success) {
        process.stderr.write(outcome.errorMessage + '\n');
        process.exit(2);
        return;
    }
    const { stepId: resolvedStepId, path: resolvedPath } = outcome;
    const expanded = (0, expandSteps_1.expandSessionSteps)(session.snapshot);
    const previousIndex = session.currentStepIndex;
    let matchedFlatIndex = expanded.findIndex(({ step }) => step.stepId() === resolvedStepId);
    if (matchedFlatIndex < 0) {
        const positionFallback = (0, resolveStepReference_1.resolveStepReference)(session.snapshot, (0, stepIndexUtils_1.pathToStepIndex)(resolvedPath));
        if (positionFallback.success) {
            matchedFlatIndex = positionFallback.flatIndex;
        }
    }
    if (matchedFlatIndex >= 0) {
        session.currentStepIndex = matchedFlatIndex;
        (0, DebugSession_1.writeSession)(session);
    }
    const addressableId = matchedFlatIndex >= 0
        ? (0, expandSteps_1.addressableStepId)(expanded[matchedFlatIndex], matchedFlatIndex)
        : resolvedStepId;
    process.stdout.write(JSON.stringify({
        stepId: addressableId,
        position: (0, stepIndexUtils_1.pathToStepIndex)(resolvedPath),
        path: resolvedPath,
        currentStepIndex: session.currentStepIndex,
        previousStepIndex: previousIndex,
    }) + '\n');
}
function applyCursorMove(state, snapshot, target) {
    const getNestedSteps = (0, stepIndexUtils_1.createNestedStepResolver)((0, buildDebugSessionState_1.buildFlowStepsResolverFromSnapshot)(snapshot, state));
    const targetPath = resolveTargetPath(state, target, getNestedSteps);
    if ('error' in targetPath) {
        return { success: false, errorMessage: targetPath.error };
    }
    const validation = (0, cursorOperations_1.validateMoveCursorTarget)(state.getSteps(), getNestedSteps, targetPath.path);
    if (!validation.success) {
        return {
            success: false,
            errorMessage: validation.errorMessage ?? 'Invalid target',
        };
    }
    const baseStepAtPath = (0, stepIndexUtils_1.getStepAtPath)(state.getSteps(), targetPath.path, getNestedSteps);
    if (!baseStepAtPath?.id) {
        return {
            success: false,
            errorMessage: `Position ${(0, stepIndexUtils_1.pathToStepIndex)(targetPath.path)} does not point at an existing step. Pass the id (or dot-notation position) of a step that exists in the test.`,
        };
    }
    state.setNextStepIndex(targetPath.path);
    return { success: true, stepId: baseStepAtPath.id, path: targetPath.path };
}
function resolveTargetPath(state, target, getNestedSteps) {
    if (stepIndexUtils_1.DOT_NOTATION_PATTERN.test(target)) {
        try {
            return { path: (0, stepIndexUtils_1.parseStepIndex)(target) };
        }
        catch (error) {
            return {
                error: `Invalid position "${target}": ${error instanceof Error ? error.message : 'unknown error'}`,
            };
        }
    }
    const resolved = (0, stepIndexUtils_1.findStepById)(state.getSteps(), target, getNestedSteps);
    if (!resolved) {
        return { error: `Step not found: ${target}` };
    }
    if ('ambiguous' in resolved) {
        return {
            error: `Step id "${target}" matches multiple steps; pass a dot-notation position instead.`,
        };
    }
    return { path: resolved.path };
}
