"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.SelectorAttribute = void 0;
exports.getSpecifiedAttribute = getSpecifiedAttribute;
exports.humanizeSelectStep = humanizeSelectStep;
exports.selectStepToAIString = selectStepToAIString;
const StepWithFind_1 = __importStar(require("./StepWithFind"));
const yaml_utils_1 = require("../yaml-utils");
const dom_util_1 = require("@mablhq-internal/mablscript-find/dom-util");
const mablscriptFind_1 = require("@mablhq/test-model/mablscriptFind");
const type_utils_1 = require("../../type-utils");
const variable_utils_1 = require("../../variable-utils");
const variable_constants_1 = require("../../variable-constants");
const variable_names_util_1 = require("../../variable-names-util");
const mablscript_step_types_1 = require("../../mablscript-step-types");
var SelectorAttribute;
(function (SelectorAttribute) {
    SelectorAttribute["INDEX"] = "index";
    SelectorAttribute["POSITION"] = "position";
    SelectorAttribute["TEXT"] = "text";
    SelectorAttribute["VALUE"] = "value";
})(SelectorAttribute || (exports.SelectorAttribute = SelectorAttribute = {}));
function getSpecifiedAttribute(selector, optionType = 'exact') {
    if (selector.index === -1) {
        return SelectorAttribute.INDEX;
    }
    else if (selector.value) {
        return SelectorAttribute.VALUE;
    }
    else if (selector.text) {
        return SelectorAttribute.TEXT;
    }
    else if (!(0, type_utils_1.isNullOrUndefined)(selector.position)) {
        return SelectorAttribute.POSITION;
    }
    else if (!(0, type_utils_1.isNullOrUndefined)(selector.index)) {
        return SelectorAttribute.INDEX;
    }
    else if (!(0, type_utils_1.isNullOrUndefined)(selector.value)) {
        return SelectorAttribute.VALUE;
    }
    else if (!(0, type_utils_1.isNullOrUndefined)(selector.text)) {
        return SelectorAttribute.TEXT;
    }
    if (optionType === 'exact') {
        throw new Error(`Selector missing expected attribute. [${JSON.stringify(selector)}]`);
    }
    return;
}
class SelectStep extends StepWithFind_1.default {
    static getStepType() {
        return mablscript_step_types_1.StepType.SELECT;
    }
    constructor(findDescriptor, selectionSelector, selectOptionType = 'exact', findOptions, variable, isPattern) {
        super(SelectStep.getStepType(), findDescriptor, findOptions);
        this.selectionSelector = selectionSelector;
        this.selectOptionType = selectOptionType;
        this.options = {
            editable: true,
        };
        this.variable = variable;
        this.isPattern = isPattern;
    }
    generateMablscript() {
        return `${this.findDescriptorToMablscript()}.select(${this.getSelectionSelectorText()}, "${this.selectOptionType}")`;
    }
    getSelectionSelectorText() {
        return ('{' +
            Object.keys(this.selectionSelector)
                .sort()
                .map((key) => {
                const value = this.selectionSelector[key];
                if (value === undefined) {
                    return;
                }
                if (typeof value === 'number') {
                    return `${key}: ${value}`;
                }
                return `${key}: "${(0, mablscriptFind_1.escapeMablscriptString)(value)}"`;
            })
                .filter((attr) => attr)
                .join(', ') +
            '}');
    }
    inputVariables() {
        const variableNames = super.inputVariables();
        const patterns = Object.values(this.selectionSelector || {}).filter((pattern) => pattern && (0, type_utils_1.isString)(pattern));
        patterns.forEach((pattern) => variableNames.push(...(0, variable_names_util_1.extractVariableNamesFromPattern)(pattern)));
        return (0, type_utils_1.distinct)(variableNames);
    }
    static generateStepFromMablStep(mablSelectStep, importer) {
        const selectStepDescriptor = mablSelectStep.toStepDescriptor();
        const selectOptions = {
            index: selectStepDescriptor.index,
            position: selectStepDescriptor.position,
            selector_type: selectStepDescriptor.selector_type,
            text: selectStepDescriptor.text,
            uuid: selectStepDescriptor.uuid,
            value: selectStepDescriptor.value,
        };
        const attribute = getSpecifiedAttribute(selectOptions, selectStepDescriptor.selectOptionType);
        const attributeValue = selectStepDescriptor[attribute]?.toString();
        let variable, isPattern;
        const variableName = (0, mablscriptFind_1.getVariableNameFromLoneVariablePattern)(attributeValue);
        if (variableName) {
            const flattenedVariables = (0, variable_utils_1.flattenVariables)(importer.variables, undefined, undefined);
            variable = flattenedVariables[variableName];
            if (!variable && variableName.startsWith('user.')) {
                const humanizedName = (0, mablscriptFind_1.removeUserNamespace)(variableName);
                const newVar = {
                    name: variableName,
                    humanizedName,
                    value: variable_constants_1.EMPTY_VARIABLE_VALUE_PLACEHOLDER,
                };
                importer.variables[variableName] = newVar;
            }
        }
        else {
            isPattern =
                (0, type_utils_1.isString)(attributeValue) &&
                    (0, variable_utils_1.safelyGeneratePatternPreview)(attributeValue, importer.variables, () => attributeValue, true) !== attributeValue;
        }
        const { findDescriptor, findOptions } = this.getFindDescriptorAndFindOptions(mablSelectStep, importer);
        if ((0, mablscriptFind_1.isCustomFindDescriptor)(findDescriptor) ||
            (0, mablscriptFind_1.isFindOneDescriptor)(findDescriptor)) {
            return new SelectStep(findDescriptor, selectOptions, selectStepDescriptor.selectOptionType, findOptions, variable, isPattern);
        }
        throw new Error('No FindDescriptor found for Select Step');
    }
}
exports.default = SelectStep;
function humanizeSelectStep(step) {
    if (step.selectOptionType === 'any') {
        return `Select any option from ${(0, StepWithFind_1.humanizeFind)(step)}`;
    }
    const specifiedAttribute = getSpecifiedAttribute(step.selectionSelector);
    if (specifiedAttribute === SelectorAttribute.VALUE ||
        specifiedAttribute === SelectorAttribute.TEXT) {
        const selectedText = `"${(0, dom_util_1.compactWhitespace)(step.selectionSelector[specifiedAttribute] ?? '')}"`;
        if (step.variable) {
            const varDisplay = step.variable.humanizedName || step.variable.name;
            return `Select the option from ${(0, StepWithFind_1.humanizeFind)(step)} using the variable "${varDisplay}"`;
        }
        else if (step.isPattern) {
            return `Select the option from ${(0, StepWithFind_1.humanizeFind)(step)} using ${selectedText}`;
        }
        return `Select ${selectedText} from ${(0, StepWithFind_1.humanizeFind)(step)}`;
    }
    if (specifiedAttribute === SelectorAttribute.POSITION) {
        if (step.variable) {
            const varDisplay = step.variable.humanizedName || step.variable.name;
            return `Select the option from ${(0, StepWithFind_1.humanizeFind)(step)} whose position equals the value of the variable "${varDisplay}"`;
        }
        else if (step.isPattern) {
            return `Select the option from ${(0, StepWithFind_1.humanizeFind)(step)} whose position equals the value of "${step.selectionSelector.position}"`;
        }
        const position = (0, type_utils_1.getIntegerFromString)(step.selectionSelector.position ?? '');
        if (position === 0) {
            return `Clear the selected value from ${(0, StepWithFind_1.humanizeFind)(step)}`;
        }
        else if (position) {
            return `Select the ${(0, mablscriptFind_1.humanizeOrdinal)(position, true)} option from ${(0, StepWithFind_1.humanizeFind)(step)}`;
        }
        return `Select option from ${(0, StepWithFind_1.humanizeFind)(step)}`;
    }
    if (specifiedAttribute === SelectorAttribute.INDEX) {
        if (step.selectionSelector.index === -1) {
            return `Clear the selected value from ${(0, StepWithFind_1.humanizeFind)(step)}`;
        }
        const indexAsPosition = (step.selectionSelector.index ?? 0) + 1;
        return `Select the option from ${(0, StepWithFind_1.humanizeFind)(step)} position equals the value of "${indexAsPosition}"`;
    }
    throw new Error(`Unexpected select attribute type: ${specifiedAttribute}`);
}
function selectStepToAIString(step) {
    const result = {
        stepType: step.stepType,
        target: (0, StepWithFind_1.findDescriptorToAIObject)(step.findDescriptor, step.findOptions),
    };
    if (step.selectOptionType === 'any') {
        result.option_type = 'any';
    }
    else if (step.selectionSelector.index === -1) {
        result.option_type = 'clear';
    }
    else if (step.variable) {
        result.variable = step.variable.humanizedName || step.variable.name;
    }
    else if (step.selectionSelector.text) {
        result.option_text = step.selectionSelector.text;
    }
    else if (step.selectionSelector.value) {
        result.option_value = step.selectionSelector.value;
    }
    else if (step.selectionSelector.position !== undefined) {
        result.option_position = step.selectionSelector.position;
    }
    else if (step.selectionSelector.index !== undefined) {
        result.option_index = step.selectionSelector.index;
    }
    return (0, yaml_utils_1.toYaml)(result);
}
