"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.moveStepsExecutor = void 0;
const stepIndexUtils_1 = require("../../sharedUtils/stepIndexUtils");
const mablscript_step_types_1 = require("../../sharedUtils/mablscript-step-types");
const ExecuteStepGroupStep_1 = __importDefault(require("../../sharedUtils/mablscript/extended/ExecuteStepGroupStep"));
function getStepsArrayAtParent(rootSteps, parentPath) {
    if (parentPath.length === 0) {
        return rootSteps;
    }
    const parentStep = (0, stepIndexUtils_1.getStepAtPath)(rootSteps, parentPath, stepIndexUtils_1.getStepGroupNestedSteps);
    if (parentStep && (0, mablscript_step_types_1.isStepGroupStep)(parentStep) && parentStep.stepsInGroup) {
        return parentStep.stepsInGroup;
    }
    return undefined;
}
function resolveDestination(toolParams) {
    return toolParams.destination ?? 'new_group';
}
exports.moveStepsExecutor = {
    needsFind: () => false,
    getStepType: () => 'move_steps',
    execute: (payload, stateProvider, eventHandler, logger) => {
        const toolParams = payload.toolCall.toolParams;
        const startStepIndex = toolParams.start_step_index;
        const endStepIndex = toolParams.end_step_index;
        const stepId = toolParams.step_id;
        const endStepId = toolParams.end_step_id;
        const destination = resolveDestination(toolParams);
        const groupName = toolParams.group_name;
        if (stepId !== undefined && startStepIndex !== undefined) {
            logger.debug(`Both step_id and start_step_index provided; using step_id "${stepId}" (id-based addressing wins).`);
        }
        if (endStepId !== undefined && endStepIndex !== undefined) {
            logger.debug(`Both end_step_id and end_step_index provided; using end_step_id "${endStepId}" (id-based addressing wins).`);
        }
        const allSteps = stateProvider.getSteps();
        const startResolution = (0, stepIndexUtils_1.resolveStepPathFromIdOrIndex)(allSteps, stepIndexUtils_1.getStepGroupNestedSteps, stepId, startStepIndex, { idField: 'step_id', indexField: 'start_step_index' });
        if ('error' in startResolution) {
            return Promise.resolve({
                success: false,
                errorMessage: startResolution.error,
            });
        }
        const startPath = startResolution.path;
        const endResolution = (0, stepIndexUtils_1.resolveStepPathFromIdOrIndex)(allSteps, stepIndexUtils_1.getStepGroupNestedSteps, endStepId, endStepIndex, { idField: 'end_step_id', indexField: 'end_step_index' });
        if ('error' in endResolution) {
            return Promise.resolve({
                success: false,
                errorMessage: endResolution.error,
            });
        }
        const endPath = endResolution.path;
        const startStepLabel = (0, stepIndexUtils_1.pathToStepIndex)(startPath);
        const endStepLabel = (0, stepIndexUtils_1.pathToStepIndex)(endPath);
        if (startPath.length !== endPath.length) {
            return Promise.resolve({
                success: false,
                errorMessage: 'start_step_index and end_step_index must be at the same nesting level',
            });
        }
        const startParent = startPath.slice(0, -1);
        const endParent = endPath.slice(0, -1);
        if (startParent.length !== endParent.length ||
            !startParent.every((v, i) => v === endParent[i])) {
            return Promise.resolve({
                success: false,
                errorMessage: 'start_step_index and end_step_index must have the same parent',
            });
        }
        const startIdx = startPath[startPath.length - 1];
        const endIdx = endPath[endPath.length - 1];
        if (startIdx > endIdx) {
            return Promise.resolve({
                success: false,
                errorMessage: 'start_step_index must come before or equal end_step_index',
            });
        }
        const parentPath = startParent;
        const parentSteps = getStepsArrayAtParent(allSteps, parentPath);
        if (!parentSteps) {
            const parentLabel = parentPath.length === 0 ? 'root' : (0, stepIndexUtils_1.pathToStepIndex)(parentPath);
            return Promise.resolve({
                success: false,
                errorMessage: `Cannot resolve parent container at ${parentLabel} for the specified range`,
            });
        }
        if (startIdx < 0 || endIdx >= parentSteps.length) {
            const parentLabel = parentPath.length === 0
                ? 'root level'
                : `step group at ${(0, stepIndexUtils_1.pathToStepIndex)(parentPath)}`;
            return Promise.resolve({
                success: false,
                errorMessage: `Step range ${startStepLabel}-${endStepLabel} is out of bounds (${parentLabel} has ${parentSteps.length} step(s), valid range: 1-${parentSteps.length})`,
            });
        }
        if (destination === 'new_group') {
            const movedSteps = parentSteps.splice(startIdx, endIdx - startIdx + 1);
            const newGroup = new ExecuteStepGroupStep_1.default(movedSteps, groupName);
            parentSteps.splice(startIdx, 0, newGroup);
            const newCursor = [...parentPath, startIdx + 1];
            eventHandler.setNextStepIndex(newCursor);
            logger.info(`Wrapped ${movedSteps.length} steps into group at position ${startStepLabel}`);
            return Promise.resolve({
                success: true,
                message: `Wrapped ${movedSteps.length} step(s) into group "${groupName ?? '(unnamed)'}". Cursor is now at ${(0, stepIndexUtils_1.pathToStepIndex)(newCursor)}. Step indices have changed — refetch test context for updated step indices.`,
            });
        }
        if (destination === 'existing_group') {
            const targetGroupPosition = toolParams.target_group_position;
            if (!targetGroupPosition) {
                return Promise.resolve({
                    success: false,
                    errorMessage: 'target_group_position is required for destination "existing_group"',
                });
            }
            let targetPath;
            try {
                targetPath = (0, stepIndexUtils_1.parseStepIndex)(targetGroupPosition);
            }
            catch (e) {
                return Promise.resolve({
                    success: false,
                    errorMessage: `Invalid target_group_position "${targetGroupPosition}": ${e.message}`,
                });
            }
            const targetStep = (0, stepIndexUtils_1.getStepAtPath)(allSteps, targetPath, stepIndexUtils_1.getStepGroupNestedSteps);
            if (!targetStep) {
                return Promise.resolve({
                    success: false,
                    errorMessage: `No step found at target position ${targetGroupPosition}`,
                });
            }
            if ((0, mablscript_step_types_1.isStepWithReusableFlow)(targetStep)) {
                return Promise.resolve({
                    success: false,
                    errorMessage: 'Cannot move steps into a reusable flow. Flows are read-only.',
                });
            }
            if (!(0, mablscript_step_types_1.isStepGroupStep)(targetStep) || !targetStep.stepsInGroup) {
                return Promise.resolve({
                    success: false,
                    errorMessage: `Step at ${targetGroupPosition} is not a step group`,
                });
            }
            const targetParent = targetPath.slice(0, -1);
            const targetIdx = targetPath[targetPath.length - 1];
            if (parentPath.length === targetParent.length &&
                parentPath.every((v, i) => v === targetParent[i]) &&
                targetIdx >= startIdx &&
                targetIdx <= endIdx) {
                return Promise.resolve({
                    success: false,
                    errorMessage: 'Cannot move steps into a group that is within the selected range',
                });
            }
            const sameParent = parentPath.length === targetParent.length &&
                parentPath.every((v, i) => v === targetParent[i]);
            const movedSteps = parentSteps.splice(startIdx, endIdx - startIdx + 1);
            let adjustedTargetIdx = targetIdx;
            if (sameParent && targetIdx > endIdx) {
                adjustedTargetIdx -= movedSteps.length;
            }
            const targetStepAfterSplice = sameParent
                ? parentSteps[adjustedTargetIdx]
                : targetStep;
            if (!targetStepAfterSplice ||
                !(0, mablscript_step_types_1.isStepGroupStep)(targetStepAfterSplice) ||
                !targetStepAfterSplice.stepsInGroup) {
                parentSteps.splice(startIdx, 0, ...movedSteps);
                return Promise.resolve({
                    success: false,
                    errorMessage: 'Target group could not be resolved after removing source steps',
                });
            }
            targetStepAfterSplice.stepsInGroup.push(...movedSteps);
            const targetPathAfterSplice = sameParent
                ? [...targetParent, adjustedTargetIdx]
                : targetPath;
            const newCursor = [
                ...targetPathAfterSplice,
                targetStepAfterSplice.stepsInGroup.length,
            ];
            eventHandler.setNextStepIndex(newCursor);
            logger.info(`Moved ${movedSteps.length} steps into existing group at ${targetGroupPosition}`);
            return Promise.resolve({
                success: true,
                message: `Moved ${movedSteps.length} step(s) into group at ${targetGroupPosition}. Cursor is now at ${(0, stepIndexUtils_1.pathToStepIndex)(newCursor)}. Step indices have changed — refetch test context for updated step indices.`,
            });
        }
        if (parentPath.length === 0) {
            return Promise.resolve({
                success: false,
                errorMessage: 'Cannot move steps out of group: the specified steps are already at root level',
            });
        }
        const parentStep = (0, stepIndexUtils_1.getStepAtPath)(allSteps, parentPath, stepIndexUtils_1.getStepGroupNestedSteps);
        if (!parentStep) {
            return Promise.resolve({
                success: false,
                errorMessage: 'Cannot resolve parent step',
            });
        }
        if ((0, mablscript_step_types_1.isStepWithReusableFlow)(parentStep)) {
            return Promise.resolve({
                success: false,
                errorMessage: 'Cannot move steps out of a reusable flow. Flows are read-only.',
            });
        }
        if (!(0, mablscript_step_types_1.isStepGroupStep)(parentStep)) {
            return Promise.resolve({
                success: false,
                errorMessage: 'Parent is not a step group — cannot extract steps from it',
            });
        }
        const grandparentPath = parentPath.slice(0, -1);
        const parentIdxInGrandparent = parentPath[parentPath.length - 1];
        const grandparentSteps = getStepsArrayAtParent(allSteps, grandparentPath);
        if (!grandparentSteps) {
            return Promise.resolve({
                success: false,
                errorMessage: 'Cannot resolve grandparent container',
            });
        }
        const movedSteps = parentStep.stepsInGroup.splice(startIdx, endIdx - startIdx + 1);
        let newCursor;
        if (parentStep.stepsInGroup.length === 0) {
            grandparentSteps.splice(parentIdxInGrandparent, 1);
            grandparentSteps.splice(parentIdxInGrandparent, 0, ...movedSteps);
            newCursor = [
                ...grandparentPath,
                parentIdxInGrandparent + movedSteps.length,
            ];
        }
        else {
            grandparentSteps.splice(parentIdxInGrandparent + 1, 0, ...movedSteps);
            newCursor = [
                ...grandparentPath,
                parentIdxInGrandparent + 1 + movedSteps.length,
            ];
        }
        eventHandler.setNextStepIndex(newCursor);
        logger.info(`Extracted ${movedSteps.length} steps from group to parent level`);
        return Promise.resolve({
            success: true,
            message: `Extracted ${movedSteps.length} step(s) from group to parent level. Cursor is now at ${(0, stepIndexUtils_1.pathToStepIndex)(newCursor)}. Step indices have changed — refetch test context for updated step indices.`,
        });
    },
};
