"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isVariableOnImport = isVariableOnImport;
exports.safelyGeneratePatternPreview = safelyGeneratePatternPreview;
exports.getUsableVariablesAsList = getUsableVariablesAsList;
exports.getUsableVariablesAsMap = getUsableVariablesAsMap;
exports.getEditableVariablesAsList = getEditableVariablesAsList;
exports.getInputVariablesAsList = getInputVariablesAsList;
exports.proxify = proxify;
exports.unproxify = unproxify;
exports.wrapVariableRoot = wrapVariableRoot;
exports.printableVariableValue = printableVariableValue;
exports.normalizeVariable = normalizeVariable;
exports.extractSingleVariableName = extractSingleVariableName;
exports.getResolvedUserVariableValue = getResolvedUserVariableValue;
const dom_util_1 = require("@mablhq-internal/mablscript-find/dom-util");
const mablscriptFind_1 = require("@mablhq/test-model/mablscriptFind");
const variableCanonical_1 = require("@mablhq/test-model/variableCanonical");
const largeJsDependencyUtil_1 = require("../../domUtil/largeJsDependencyUtil");
const type_utils_1 = require("./type-utils");
const mablscript_step_types_1 = require("./mablscript-step-types");
function isVariableOnImport(value) {
    return value?.name && value.humanizedName;
}
function safelyGeneratePatternPreview(pattern = '', variables = undefined, undefinedCallback = () => '{{undefined}}', skipCanonicalization = false) {
    const value = skipCanonicalization
        ? pattern
        : (0, variableCanonical_1.canonicalizeVariablePattern)(variables, pattern);
    return (0, largeJsDependencyUtil_1.generatePatternPreview)(value, variables, undefinedCallback) ?? '';
}
const variableCompareReadonlyLast = (a, b) => !!a.readOnly === !!b.readOnly
    ? a.name.localeCompare(b.name)
    : Number(!!a.readOnly) - Number(!!b.readOnly);
const variableCompareReadonlyFirst = (a, b) => !!a.readOnly === !!b.readOnly
    ? a.name.localeCompare(b.name)
    : Number(!!b.readOnly) - Number(!!a.readOnly);
const isDefined = (variable, flowStepIndex) => flowStepIndex === undefined ||
    (variable.flowStepIndex !== undefined &&
        (0, mablscript_step_types_1.indexLessThan)(variable.flowStepIndex, flowStepIndex));
function isStrictPrefix(prefix, full) {
    if (prefix.length >= full.length) {
        return false;
    }
    for (let i = 0; i < prefix.length; i++) {
        if (prefix[i] !== full[i]) {
            return false;
        }
    }
    return true;
}
function isFlowParameterInScope(variable, flowStepIndex) {
    if (variable.source !== mablscriptFind_1.LegacyVariableSource.FLOW_PARAMETER) {
        return true;
    }
    if (flowStepIndex === undefined) {
        return true;
    }
    const paramOwnerIndex = variable.flowStepIndex;
    if (!paramOwnerIndex || paramOwnerIndex.length === 0) {
        return true;
    }
    return isStrictPrefix(paramOwnerIndex, flowStepIndex);
}
function getUsableVariablesAsList(variables, flowStepIndex = undefined) {
    const flattenedVariables = (0, variableCanonical_1.flattenVariables)(variables);
    return Object.values(flattenedVariables)
        .filter(variableCanonical_1.isVariableDescriptor)
        .filter((variable) => !variable.hidden &&
        isDefined(variable, flowStepIndex) &&
        isFlowParameterInScope(variable, flowStepIndex))
        .sort(variableCompareReadonlyLast);
}
function getUsableVariablesAsMap(variables, flowStepIndex = undefined, keyByName = true, keyByHumanizedName = false) {
    const dict = {};
    const flattenedVariables = (0, variableCanonical_1.flattenVariables)(variables);
    Object.keys(flattenedVariables)
        .filter((name) => (0, variableCanonical_1.isVariableDescriptor)(flattenedVariables[name]))
        .filter((name) => !flattenedVariables[name].hidden &&
        isDefined(flattenedVariables[name], flowStepIndex) &&
        isFlowParameterInScope(flattenedVariables[name], flowStepIndex))
        .forEach((name) => {
        const variable = flattenedVariables[name];
        if (keyByHumanizedName && variable.humanizedName) {
            dict[variable.humanizedName] = variable;
        }
        if (keyByName && variable.name) {
            dict[variable.name] = variable;
        }
    });
    return dict;
}
function getEditableVariablesAsList(variables, flowStepIndex) {
    const flattenedVariables = (0, variableCanonical_1.flattenVariables)(variables);
    return Object.values(flattenedVariables)
        .filter(variableCanonical_1.isVariableDescriptor)
        .filter((variable) => !variable.hidden &&
        !variable.readOnly &&
        variable.variableType !== 'input' &&
        isDefined(variable, flowStepIndex))
        .sort(variableCompareReadonlyLast);
}
function getInputVariablesAsList(variables) {
    const flattenedVariables = (0, variableCanonical_1.flattenVariables)(variables);
    return Object.values(flattenedVariables)
        .filter(variableCanonical_1.isVariableDescriptor)
        .filter((variable) => !variable.hidden && variable.variableType === 'input')
        .sort(variableCompareReadonlyFirst);
}
const identity = (variable) => variable;
function proxify(variables, getValue = identity) {
    const proxy = (0, mablscriptFind_1.namespace)();
    const emptyNamespaceCallback = (key) => {
        proxy[key] = (0, mablscriptFind_1.namespace)();
    };
    const arr = Array.isArray(variables)
        ? variables
        : Object.values((0, variableCanonical_1.flattenVariables)(variables, emptyNamespaceCallback));
    arr.forEach((variable) => (proxy[variable.name] = getValue(variable)));
    return proxy;
}
function unflattenVariables(variables, getValue = identity) {
    const arr = Array.isArray(variables) ? variables : Object.values(variables);
    return JSON.parse(JSON.stringify(proxify(arr, getValue)));
}
function unproxify(variables, getValue = identity) {
    return unflattenVariables((0, variableCanonical_1.flattenVariables)(variables), getValue);
}
function wrapVariableRoot(variableRoot) {
    return new Proxy(variableRoot, {
        set(target, property, value) {
            if ((0, variableCanonical_1.isVariableDescriptor)(value)) {
                value.name = value.name || property;
                value.readOnly = value.readOnly === undefined ? false : value.readOnly;
                value.maskDisplay =
                    value.maskDisplay === undefined ? false : value.maskDisplay;
            }
            target[property] = value;
            return true;
        },
    });
}
function printableVariableValue(value) {
    return (0, type_utils_1.isString)(value) ? value : JSON.stringify(value);
}
function normalizeVariable(variableValue) {
    switch (typeof variableValue) {
        case 'number':
        case 'boolean':
            return variableValue.toString();
        case 'string':
            return (0, dom_util_1.compactWhitespace)(variableValue);
        case 'object':
            return JSON.stringify(variableValue);
        case 'undefined':
            return 'undefined';
        default:
            return `${variableValue}`;
    }
}
function extractSingleVariableName(value) {
    const variables = (0, mablscriptFind_1.findVariables)(value);
    return !!variables &&
        variables.length === 1 &&
        value === `{{@${variables[0]}}}`
        ? variables[0]
        : undefined;
}
function getResolvedUserVariableValue(variables, variableName, defaultValue) {
    const flattenedVariables = (0, variableCanonical_1.flattenVariables)(variables);
    const fullVariableName = `user.${variableName}`;
    const variable = flattenedVariables[fullVariableName];
    if (variable?.value !== undefined) {
        return String(variable.value);
    }
    return defaultValue;
}
