"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.shouldAutoAddElseEnd = shouldAutoAddElseEnd;
exports.generateConditionalWrapperSteps = generateConditionalWrapperSteps;
exports.recordTrainedStep = recordTrainedStep;
const frame_utils_1 = require("../frame-utils");
const mablApi_1 = require("../../../mablApi");
const mablscript_step_types_1 = require("../../sharedUtils/mablscript-step-types");
const translateMablscript_1 = require("../../sharedUtils/capture/translateMablscript");
const BaseStep_1 = __importDefault(require("../../sharedUtils/mablscript/canonical/BaseStep"));
const ElseStep_1 = __importDefault(require("../../sharedUtils/mablscript/canonical/ElseStep"));
const EndStep_1 = __importDefault(require("../../sharedUtils/mablscript/canonical/EndStep"));
const messages_1 = require("../../sharedUtils/messages");
const variable_utils_1 = require("../../sharedUtils/variable-utils");
const uuid_1 = require("uuid");
const REPLAY_RESPONSE_TIMEOUT_DELAY_MS = 6000;
function getLastStepExcludingTypes(steps, ...excludeStepTypes) {
    return steps
        .filter((step) => !excludeStepTypes.includes(step.stepType))
        .at(-1);
}
function shouldAutoAddElseEnd(conditionalType) {
    return conditionalType === mablscript_step_types_1.ConditionalType.IF;
}
function generateConditionalWrapperSteps() {
    return [new ElseStep_1.default(), new EndStep_1.default()];
}
function generateContextSwitchSteps(contextInfo, trainingContextState, eventMessage, stateProvider) {
    const steps = [];
    if (!(0, frame_utils_1.isRootFrameId)(contextInfo.frameId)) {
        if (['url', 'viewport', 'assert-cookie'].includes(eventMessage.listener)) {
            return steps;
        }
    }
    const switchTab = trainingContextState.currentTabId !== contextInfo.tabId;
    let switchFrame = trainingContextState.currentFrameId !== contextInfo.frameId;
    if (switchTab) {
        const tabSelector = trainingContextState.getTabSelectorInfo(contextInfo.tabId);
        const switchTabMessage = createSwitchContextMessage(0, contextInfo.tabId, trainingContextState.currentFrameId, trainingContextState.currentTabId, 'find_tab', tabSelector);
        const translatedSwitchTabMessage = translateStepRequest(switchTabMessage, stateProvider);
        if (translatedSwitchTabMessage) {
            steps.push(translatedSwitchTabMessage);
        }
        switchFrame = contextInfo.frameId !== 0;
    }
    if (switchFrame) {
        if (trainingContextState.currentFrameId !== 0 &&
            contextInfo.frameId !== 0) {
            const switchToRootMessage = translateStepRequest(createSwitchContextMessage(0, contextInfo.tabId, trainingContextState.currentFrameId, trainingContextState.currentTabId), stateProvider);
            if (switchToRootMessage) {
                steps.push(switchToRootMessage);
            }
        }
        const frameSelector = trainingContextState.getFrameIdSelectorInfo(contextInfo.frameId);
        if (frameSelector || (0, frame_utils_1.isRootFrameId)(contextInfo.frameId)) {
            if (contextInfo.frameId !== 0) {
                const parentFrameIds = trainingContextState.getParentFramesForFrameId(contextInfo.tabId, contextInfo.frameId);
                parentFrameIds.reverse();
                parentFrameIds.forEach((frameId) => {
                    const nestedSwitchContext = translateStepRequest(createSwitchContextMessage(frameId, contextInfo.tabId, trainingContextState.currentFrameId, trainingContextState.currentTabId, 'find_one', trainingContextState.getFrameIdSelectorInfo(frameId)), stateProvider);
                    if (nestedSwitchContext) {
                        steps.push(nestedSwitchContext);
                    }
                });
            }
            if (frameSelector &&
                typeof frameSelector.src === 'string' &&
                frameSelector.src.startsWith('chrome-extension')) {
                delete frameSelector.src;
            }
            const switchFrameMessage = translateStepRequest(createSwitchContextMessage(contextInfo.frameId, contextInfo.tabId, trainingContextState.currentFrameId, trainingContextState.currentTabId, 'find_one', frameSelector), stateProvider);
            if (switchFrameMessage) {
                steps.push(switchFrameMessage);
            }
        }
    }
    return steps;
}
function createSwitchContextMessage(frameId, tabId, originatingFrameId, originatingTabId, findType, selectorInfo = {}) {
    const message = {
        action: 'record',
        listener: 'switch-context-to',
        originatingFrameId,
        originatingTabId,
        frameId,
        tabId,
    };
    if (findType) {
        const findDescriptor = { type: findType };
        if (findType === 'find_tab') {
            findDescriptor.foundTabSelectors = selectorInfo;
            return Object.assign(message, {
                findDescriptor,
            });
        }
    }
    return Object.assign(message, selectorInfo);
}
function createTrainingContextState(stateProvider) {
    const trainingContext = stateProvider.getTrainingContext();
    return {
        currentTabId: trainingContext.getCurrentTab(),
        currentFrameId: trainingContext.getCurrentFrame(),
        getTabSelectorInfo: (tabId) => trainingContext.getTabSelectorInfo(tabId),
        getFrameIdSelectorInfo: (frameId) => trainingContext.getFrameIdSelectorInfo(frameId),
        getParentFramesForFrameId: (tabId, frameId) => trainingContext.getParentFramesForFrameId(tabId, frameId),
    };
}
function applyDefaultEnterTextMode(eventMessage, stateProvider) {
    if (eventMessage.listener !== 'input') {
        return;
    }
    if (eventMessage.enterTextMode !== undefined) {
        return;
    }
    eventMessage.enterTextMode =
        stateProvider.getApplicationEnterTextMode() ?? mablApi_1.EnterTextModeEnum.Fill;
}
function translateStepRequest(step, stateProvider) {
    applyDefaultEnterTextMode(step, stateProvider);
    const elementSelectors = stateProvider.getElementSelectors();
    return (0, translateMablscript_1.translateToMablscriptStep)(step, elementSelectors);
}
async function recordTrainedStep(eventMessage, contextInfo, synthetic, descriptionOverride, stateProvider, actions, isEditing = false) {
    const trainingContextState = createTrainingContextState(stateProvider);
    let recordedStep;
    eventMessage = (0, variable_utils_1.canonicalizeVariablePatternsInObject)(stateProvider.getVariables(), eventMessage);
    let wrapInConditional;
    const conditionalFlag = eventMessage.wrapInConditional ?? eventMessage.assertion?.wrapInConditional;
    const conditionalType = eventMessage.wrapInConditionalType ??
        eventMessage.assertion?.wrapInConditionalType;
    if (conditionalFlag && conditionalType) {
        wrapInConditional = {
            type: conditionalType,
            autoAddElseAndEnd: shouldAutoAddElseEnd(conditionalType),
        };
    }
    const steps = [];
    let generatedSteps = [];
    switch (eventMessage.listener) {
        case 'url':
            generatedSteps = handleUrlListenerSideEffects(eventMessage, contextInfo, stateProvider, actions);
            generatedSteps.push(...recordWithSwitchContextSupport(eventMessage, contextInfo, trainingContextState, descriptionOverride, stateProvider));
            recordedStep = getLastStepExcludingTypes(generatedSteps, mablscript_step_types_1.StepType.SWITCH_CONTEXT);
            steps.push(...generatedSteps);
            break;
        case 'mouse-select':
            handleMouseSelectSideEffects(actions);
            generatedSteps = recordWithSwitchContextSupport(eventMessage, contextInfo, trainingContextState, descriptionOverride, stateProvider);
            recordedStep = getLastStepExcludingTypes(generatedSteps, mablscript_step_types_1.StepType.SWITCH_CONTEXT);
            steps.push(...generatedSteps);
            break;
        case 'hover':
            if (!shouldRecordHoverStep(eventMessage, stateProvider)) {
                return { steps, stepsToReplay: steps.length };
            }
            generatedSteps = recordWithSwitchContextSupport(eventMessage, contextInfo, trainingContextState, descriptionOverride, stateProvider);
            recordedStep = getLastStepExcludingTypes(generatedSteps, mablscript_step_types_1.StepType.SWITCH_CONTEXT);
            steps.push(...generatedSteps);
            break;
        case 'set-files':
            if (synthetic) {
                generatedSteps = recordWithSwitchContextSupport(eventMessage, contextInfo, trainingContextState, descriptionOverride, stateProvider);
                recordedStep = getLastStepExcludingTypes(generatedSteps, mablscript_step_types_1.StepType.SWITCH_CONTEXT);
                steps.push(...generatedSteps);
            }
            else {
                generatedSteps = await trainUploadStep(eventMessage, contextInfo, trainingContextState, stateProvider, actions);
                recordedStep = getLastStepExcludingTypes(generatedSteps, mablscript_step_types_1.StepType.SWITCH_CONTEXT);
                steps.push(...generatedSteps);
            }
            break;
        default:
            generatedSteps = recordWithSwitchContextSupport(eventMessage, contextInfo, trainingContextState, descriptionOverride, stateProvider);
            recordedStep = getLastStepExcludingTypes(generatedSteps, mablscript_step_types_1.StepType.SWITCH_CONTEXT);
            steps.push(...generatedSteps);
            break;
    }
    if (recordedStep) {
        recordedStep.setStepId(eventMessage.id ?? (0, uuid_1.v4)());
    }
    const stepsToReplay = steps.length;
    if (wrapInConditional &&
        shouldAutoAddElseEnd(wrapInConditional.type) &&
        !isEditing) {
        const wrapperSteps = generateConditionalWrapperSteps();
        steps.push(...wrapperSteps);
    }
    return { steps, stepsToReplay, step: recordedStep };
}
function recordWithSwitchContextSupport(eventMessage, contextInfo, trainingContextState, descriptionOverride, stateProvider) {
    const steps = [];
    const translatedStep = translateStepRequest(eventMessage, stateProvider);
    const contextSwitchSteps = generateContextSwitchSteps(contextInfo, trainingContextState, eventMessage, stateProvider);
    steps.push(...contextSwitchSteps);
    if (translatedStep) {
        if (descriptionOverride && translatedStep instanceof BaseStep_1.default) {
            translatedStep.annotations = {
                note: '',
                ...translatedStep.annotations,
                description: descriptionOverride,
            };
        }
        steps.push(translatedStep);
    }
    return steps;
}
function handleUrlListenerSideEffects(eventMessage, contextInfo, stateProvider, actions) {
    if (eventMessage.url &&
        eventMessage.url !== stateProvider.getLastVisitUrl() &&
        (0, frame_utils_1.isRootFrameId)(contextInfo.frameId)) {
        const message = {
            action: 'record',
            listener: eventMessage.listener,
            variable: {
                name: 'web.defaults.url',
                humanizedName: 'app.url',
                value: eventMessage.url,
            },
        };
        const step = (0, translateMablscript_1.translateToMablscriptStep)(message);
        actions.setLastVisitUrl(eventMessage.url);
        return step ? [step] : [];
    }
    if (eventMessage.variable?.value) {
        actions.setLastVisitUrl(String(eventMessage.variable.value));
    }
    return [];
}
function handleMouseSelectSideEffects(actions) {
    void actions.sendMessageToAllFrames((0, messages_1.deactivateSelectionMessage)());
}
function shouldRecordHoverStep(eventMessage, stateProvider) {
    return stateProvider.isCapturingHovers() || !!eventMessage.findDescriptor;
}
async function trainUploadStep(eventMessage, contextInfo, trainingContextState, stateProvider, actions) {
    if (eventMessage.multiple) {
        actions.setReplayResponse({
            level: 'warning',
            message: 'Multi-file inputs not supported',
        });
        globalThis.setTimeout(() => actions.resetReplayResponse(), REPLAY_RESPONSE_TIMEOUT_DELAY_MS);
    }
    const organizationId = stateProvider.getActiveOrgId();
    try {
        const files = await actions.uploadFiles(organizationId, eventMessage);
        const firstUploadFailure = files.find((file) => 'level' in file && file.level === 'error');
        if (firstUploadFailure) {
            const errorMessage = 'message' in firstUploadFailure && firstUploadFailure.message
                ? String(firstUploadFailure.message)
                : 'Error uploading file(s) to mabl';
            actions.setReplayResponse({
                level: 'error',
                message: errorMessage,
            });
            return [];
        }
        await Promise.all((eventMessage.files ?? []).map(async (file, index) => {
            file.id = files[index]?.id;
            return actions.downloadUploadedFile(file);
        }));
        const steps = recordWithSwitchContextSupport(eventMessage, contextInfo, trainingContextState, undefined, stateProvider);
        return steps;
    }
    catch (e) {
        console.error('Error occurred while training a file upload step: ', e);
    }
    return [];
}
