"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildFlowObjectForApi = buildFlowObjectForApi;
exports.buildPrimaryFlowForChunk = buildPrimaryFlowForChunk;
exports.composeInputVariables = composeInputVariables;
exports.composeOutputVariables = composeOutputVariables;
exports.prepareVersionedEntityForUpdate = prepareVersionedEntityForUpdate;
exports.prepareReusableVersionedEntityForUpdate = prepareReusableVersionedEntityForUpdate;
exports.parseMobilePlatform = parseMobilePlatform;
exports.buildJourneyObjectForApi = buildJourneyObjectForApi;
exports.buildJourneyFromOptions = buildJourneyFromOptions;
const mablscript_step_types_1 = require("../../sharedUtils/mablscript-step-types");
const mablscript_utils_1 = require("../../sharedUtils/mablscript/mablscript-utils");
const stepSerialization_1 = require("../../sharedUtils/mablscript/stepSerialization");
const variable_utils_1 = require("../../sharedUtils/variable-utils");
function buildFlowObjectForApi(params) {
    const { flowId, flowVersion, flowType, description, steps, scriptDescription = '', inputVariables, outputVariables, trainedAgainstUrl, parameters = [], reusable, workspaceId, mobilePlatform, mobileTrainingInfo, appVersion, useJsonSteps = false, variableDefinitions, } = params;
    let mablscript;
    let jsonSteps;
    const isMablscriptFlow = flowType === 'mablscript';
    const saveJsonSteps = flowType === 'mobile' || useJsonSteps;
    const saveLegacyMablscript = isMablscriptFlow && !saveJsonSteps;
    if (saveJsonSteps) {
        const aliasedVariables = variableDefinitions
            ? (0, variable_utils_1.aliasVariables)(variableDefinitions)
            : undefined;
        jsonSteps = {
            steps: steps.map((step) => (0, stepSerialization_1.parseStepToV2Format)(step, isMablscriptFlow, variableDefinitions, aliasedVariables)),
        };
    }
    if (saveLegacyMablscript) {
        mablscript = (0, mablscript_utils_1.translateToMablScript)(steps);
    }
    let flow = {
        organization_id: workspaceId,
        description,
        flow_type: flowType,
        parameters,
        reusable,
        script: mablscript,
        json_steps: jsonSteps,
        mobile_platform: mobilePlatform,
        mobile_training_info: mobileTrainingInfo,
        script_description: scriptDescription,
        url: trainedAgainstUrl,
        variant_last_updated_by_app_version: appVersion,
        variables: {
            inputs: composeInputVariables(inputVariables),
            outputs: composeOutputVariables(outputVariables),
        },
    };
    flow = maybeUpdateFileReferencesForFlow(flow, steps);
    flow = maybeUpdateSnippetReferencesForFlow(flow, steps);
    if (flowId) {
        flow.id = flowId;
    }
    if (flowVersion !== undefined) {
        flow.version = flowVersion;
    }
    return prepareReusableVersionedEntityForUpdate(flow);
}
function buildPrimaryFlowForChunk(steps, options) {
    return buildFlowObjectForApi({
        flowType: 'mablscript',
        description: 'Generated flow',
        steps,
        scriptDescription: options.scriptDescription,
        inputVariables: new Map(),
        outputVariables: new Set(),
        trainedAgainstUrl: options.url,
        reusable: false,
        workspaceId: options.workspaceId,
        mobileTrainingInfo: options.mobileTrainingInfo,
        appVersion: options.appVersion,
        useJsonSteps: true,
    });
}
function composeInputVariables(variableMap) {
    if (!variableMap) {
        return [];
    }
    return [...variableMap.keys()].sort().map((name) => {
        let defaultVal = variableMap.get(name);
        if (typeof defaultVal !== 'string') {
            defaultVal = '';
        }
        return { name, default_value: defaultVal };
    });
}
function composeOutputVariables(variableSet) {
    if (!variableSet) {
        return [];
    }
    return [...variableSet].sort().map((name) => ({ name }));
}
function maybeUpdateFileReferencesForFlow(flow, steps) {
    if (flow.flow_type !== 'mobile') {
        return flow;
    }
    if (!flow.file_references) {
        flow.file_references = [];
    }
    collectFileReferencesFromSteps(steps, flow.file_references);
    return flow;
}
function collectSnippetIds(steps) {
    const snippetIds = new Set();
    for (const step of steps) {
        if ((0, mablscript_step_types_1.isStepGroupStep)(step)) {
            for (const nestedId of collectSnippetIds(step.stepsInGroup)) {
                snippetIds.add(nestedId);
            }
        }
        else if ((0, mablscript_step_types_1.isStepWithSnippet)(step)) {
            const snippetId = step.getSnippetInvariantId();
            if (snippetId) {
                snippetIds.add(snippetId);
            }
        }
    }
    return snippetIds;
}
function maybeUpdateSnippetReferencesForFlow(flow, steps) {
    const snippetIds = collectSnippetIds(steps);
    if (snippetIds.size > 0) {
        flow.snippet_references = [...snippetIds].map((id) => ({ id }));
    }
    return flow;
}
function collectFileReferencesFromSteps(steps, fileReferences) {
    for (const step of steps) {
        if ((0, mablscript_step_types_1.isMablStepAdapter)(step)) {
            collectFileReferencesFromMablStep(step.mablStep, fileReferences);
        }
        else if ((0, mablscript_step_types_1.isStepGroupStep)(step)) {
            collectFileReferencesFromSteps(step.stepsInGroup, fileReferences);
        }
    }
}
function collectFileReferencesFromMablStep(mablStep, fileReferences) {
    if (isPushFileStep(mablStep)) {
        mablStep.descriptor.files.forEach((file) => {
            fileReferences.push({ id: file.file.id, name: file.file.name });
        });
    }
    if (isStepGroupWithNestedSteps(mablStep)) {
        for (const nestedStep of mablStep.getSteps()) {
            collectFileReferencesFromMablStep(nestedStep, fileReferences);
        }
    }
}
function isStepGroupWithNestedSteps(value) {
    return (value.getStepName() === 'StepGroup' &&
        typeof value.getSteps === 'function');
}
function isPushFileStep(value) {
    if (typeof value !== 'object' || !value) {
        return false;
    }
    return ('descriptor' in value &&
        value.descriptor?.files !== undefined);
}
function prepareVersionedEntityForUpdate(entity) {
    delete entity.previous_version;
    delete entity.merged_version;
    delete entity.change_description;
    delete entity.source_control_tags;
    delete entity.version_tags;
    return entity;
}
function prepareReusableVersionedEntityForUpdate(entity) {
    prepareVersionedEntityForUpdate(entity);
    if (!entity.reusable) {
        delete entity.version;
    }
    return entity;
}
function parseMobilePlatform(platformName) {
    const normalizedPlatformName = platformName?.toString()?.toLowerCase();
    if (normalizedPlatformName === 'ios') {
        return 'ios';
    }
    else if (normalizedPlatformName === 'android') {
        return 'android';
    }
    return undefined;
}
function buildJourneyObjectForApi(params) {
    const { existingTest, flows, flowIterationsByIndex = {}, flowConfigurationsByIndex = {}, url, testName, testDescription = '', testIntent = '', workspaceId, applicationId, labels, datatables, variables, mobilePlatform, mobileTrainingInfo, credentialsId, environmentId, scenarioId, deviceEmulation, trainingSessionId, agentSessionId, appVersion, } = params;
    const isExistingJourney = !!existingTest?.id;
    const finalMobilePlatform = mobilePlatform ?? existingTest?.mobile_platform;
    const finalDeviceEmulation = deviceEmulation ?? existingTest?.device_emulation;
    const variantAttributes = {
        iterations: flowIterationsByIndex,
        flow_configuration: flowConfigurationsByIndex,
        application_id: applicationId ?? existingTest?.application_id,
        credentials_id: credentialsId ?? existingTest?.credentials_id,
        datatable_row_id: scenarioId ?? existingTest?.datatable_row_id,
        device_emulation: finalDeviceEmulation,
        device_emulations: finalDeviceEmulation ? [finalDeviceEmulation] : [],
        environment_id: environmentId ?? existingTest?.environment_id,
        url: url ?? existingTest?.url,
        variant_last_updated_by_app_version: appVersion,
        training_session_id: trainingSessionId,
        agent_session_id: agentSessionId,
        variables,
        mobile_training_info: finalMobilePlatform
            ? {
                ...existingTest?.mobile_training_info,
                ...mobileTrainingInfo,
            }
            : undefined,
    };
    let journey;
    if (isExistingJourney) {
        journey = {
            id: existingTest?.id,
            version: existingTest?.version,
            intent: testIntent,
            ...variantAttributes,
        };
    }
    else {
        const labelObjects = labels?.map((label) => typeof label === 'string' ? { name: label } : label);
        journey = {
            name: testName,
            description: testDescription,
            intent: testIntent,
            labels: labelObjects ?? existingTest?.labels,
            tags: [{ name: 'training' }],
            datatables: datatables ?? existingTest?.datatables,
            mobile_platform: finalMobilePlatform,
            ...variantAttributes,
        };
    }
    journey.organization_id = workspaceId;
    journey.flows = flows.map((flow) => flow.reusable ? flow.invariant_id : flow.id);
    return journey;
}
function buildJourneyFromOptions(flows, options) {
    return buildJourneyObjectForApi({
        existingTest: options.existingTest,
        flows,
        flowIterationsByIndex: options.flowIterations,
        flowConfigurationsByIndex: options.flowConfigurations,
        url: options.url,
        testName: options.testName,
        testDescription: options.testDescription,
        workspaceId: options.workspaceId,
        applicationId: options.applicationId,
        labels: options.labels,
        datatables: options.datatables,
        credentialsId: options.credentialsId,
        mobileTrainingInfo: options.mobileTrainingInfo,
        deviceEmulation: options.deviceEmulation,
        scenarioId: options.scenarioId,
        appVersion: options.appVersion,
        trainingSessionId: options.trainingSessionId,
        agentSessionId: options.agentSessionId,
    });
}
