"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AssertStep = exports.assertStepYamlMablscriptNames = exports.MAX_AI_ASSERTIONS_PER_CLOUD_RUN = exports.OnFailure = exports.ObservationScope = void 0;
exports.buildAssertStepDescriptorFromLegacyActions = buildAssertStepDescriptorFromLegacyActions;
const ConditionAction_1 = require("../actions/ConditionAction");
const FindAction_1 = require("../actions/FindAction");
const MablAction_1 = require("../MablAction");
const MablSymbol_1 = require("../MablSymbol");
const mablscriptFind_1 = require("../mablscriptFind");
const ActionBuilderUtils_1 = require("../actions/ActionBuilderUtils");
const ExtractDescriptor_1 = require("../types/ExtractDescriptor");
const ConditionDescriptor_1 = require("../types/ConditionDescriptor");
const GetUrlAction_1 = require("../actions/GetUrlAction");
const GetVariableValue_1 = require("../actions/GetVariableValue");
const CountAction_1 = require("../actions/CountAction");
const MobileFindAction_1 = require("../mobile/steps/actions/MobileFindAction");
const GetViewportAction_1 = require("../actions/GetViewportAction");
const MablStepV2_1 = require("../MablStepV2");
const MablStepWithFindAction_1 = require("../MablStepWithFindAction");
const AssertStepOld_1 = require("./AssertStepOld");
var ObservationScope;
(function (ObservationScope) {
    ObservationScope["Element"] = "element";
    ObservationScope["Page"] = "page";
})(ObservationScope || (exports.ObservationScope = ObservationScope = {}));
var OnFailure;
(function (OnFailure) {
    OnFailure["ContinueWithWarning"] = "continue";
    OnFailure["FailImmediately"] = "terminate";
    OnFailure["FailTestAtEnd"] = "failAtEnd";
})(OnFailure || (exports.OnFailure = OnFailure = {}));
exports.MAX_AI_ASSERTIONS_PER_CLOUD_RUN = 30;
const assertStepYamlMablscriptNames = () => {
    const assertionNames = Object.keys(ConditionDescriptor_1.AssertionStepNameToField);
    assertionNames.push('WaitUntil');
    return assertionNames;
};
exports.assertStepYamlMablscriptNames = assertStepYamlMablscriptNames;
class AssertStep extends MablStepV2_1.MablStepV2 {
    static actionCode = 'assert';
    static mablScriptStepNames = [
        AssertStep.actionCode,
        ...Object.keys(AssertStepOld_1.oldToV2StepNameMap),
    ];
    static yamlMablScriptNames = (0, exports.assertStepYamlMablscriptNames)();
    conditionAction;
    primaryAction;
    extractAction;
    countAction;
    assertionType;
    assertionValue;
    isWaitUntilStep;
    onFailure;
    observationScope;
    aiPrompt;
    constructor(descriptor, stepName, stepActions) {
        super('assert', descriptor, AssertStep.actionCode);
        if (stepActions) {
            this.primaryAction = stepActions.primaryAction;
            this.extractAction = stepActions.extractAction;
            this.countAction = stepActions.countAction;
            this.conditionAction = stepActions.conditionAction;
        }
        else {
            const name = stepName ?? this.determineStepNameFromDescriptor(descriptor);
            const actions = AssertStep.buildActionsFromDescriptor(name, {
                target: descriptor.target,
                extract: descriptor.extract,
                count: descriptor.count,
                condition: descriptor.condition,
            });
            this.primaryAction = actions.primaryAction;
            this.extractAction = actions.extractAction;
            this.countAction = actions.countAction;
            this.conditionAction = actions.conditionAction;
        }
        this.actions = [this.primaryAction];
        if (this.extractAction) {
            this.actions.push(this.extractAction);
        }
        if (this.countAction) {
            this.actions.push(this.countAction);
        }
        this.actions.push(this.conditionAction);
        this.assertionType = (0, ConditionDescriptor_1.getAssertionConditionFieldFromDescriptor)(this.conditionAction.conditionDescriptor);
        this.assertionValue = (0, ConditionDescriptor_1.getOptionalComparatorValue)(this.conditionAction.conditionDescriptor);
        this.aiPrompt = (0, ConditionDescriptor_1.isAIPromptCondition)(this.conditionAction.conditionDescriptor)
            ? {
                userPrompt: this.conditionAction.conditionDescriptor.userPrompt,
                metaPrompt: this.conditionAction.conditionDescriptor.metaPrompt,
                criteria: this.conditionAction.conditionDescriptor.criteria,
            }
            : undefined;
        this.isWaitUntilStep = this.determineIfWaitUntilStep();
        this.onFailure = descriptor.onFailure ?? OnFailure.FailImmediately;
        this.observationScope = descriptor.observationScope;
    }
    determineStepNameFromDescriptor(descriptor) {
        const assertionType = (0, ConditionDescriptor_1.getAssertionConditionFieldFromDescriptor)(descriptor.condition);
        return ConditionDescriptor_1.AssertionConditionFieldToStepName[assertionType];
    }
    canContinueOnFailure() {
        return this.onFailure !== OnFailure.FailImmediately;
    }
    canFailAtEnd() {
        return this.onFailure === OnFailure.FailTestAtEnd;
    }
    determineIfWaitUntilStep() {
        const find = this.primaryAction.toDescriptor();
        if (ConditionDescriptor_1.AssertionConditionFieldToStepName[this.assertionType] ===
            'AssertPresent' &&
            (0, mablscriptFind_1.isFindElementDescriptor)(find)) {
            if (find.findOptions?.waitUntil?.timeoutSeconds) {
                return true;
            }
        }
        return false;
    }
    getStepName() {
        if (this.isWaitUntilStep) {
            return 'WaitUntil';
        }
        return ConditionDescriptor_1.AssertionConditionFieldToStepName[this.assertionType];
    }
    static fromYaml(stepName, stepArgs) {
        const stepDescriptor = AssertStep.normalizeLegacyYamlFormatToDescriptor(stepName, stepArgs);
        const assertStep = new AssertStep(stepDescriptor, stepName);
        if (stepArgs.annotation) {
            assertStep.setAnnotation(stepArgs.annotation);
        }
        return assertStep;
    }
    static normalizeLegacyYamlFormatToDescriptor(stepName, stepArgs) {
        const normalized = { ...stepArgs };
        if (!normalized.condition) {
            normalized.condition = normalized.conditionDescriptor;
        }
        if (!normalized.extract && normalized.extractDescriptor) {
            normalized.extract = normalized.extractDescriptor;
        }
        if (!normalized.extract && normalized.attribute) {
            const extractType = normalized.extractType ??
                normalized.extractDescriptor?.extractType ??
                normalized.extract?.extractType;
            if (extractType) {
                const extractTypeMapping = {
                    ElementAttribute: ExtractDescriptor_1.ExtractType.EXTRACT_ATTRIBUTE,
                    CssProperty: ExtractDescriptor_1.ExtractType.EXTRACT_CSS_PROPERTIES,
                    EmailAttribute: ExtractDescriptor_1.ExtractType.EXTRACT_EMAIL_ATTRIBUTE,
                };
                const mappedExtractType = extractTypeMapping[extractType] ?? extractType;
                normalized.extract = {
                    extractType: mappedExtractType,
                    attributeName: normalized.attribute,
                };
            }
        }
        if (!normalized.count && normalized.countDescriptor) {
            normalized.count = normalized.countDescriptor;
        }
        if (!normalized.count && normalized.attribute === 'count') {
            normalized.count = { count: true };
        }
        if (!normalized.aiPrompt &&
            (normalized.userPrompt ||
                normalized.conditionDescriptor?.userPrompt ||
                normalized.condition?.userPrompt)) {
            const aiPromptData = {
                userPrompt: normalized.userPrompt ??
                    normalized.conditionDescriptor?.userPrompt ??
                    normalized.condition?.userPrompt,
                metaPrompt: normalized.metaPrompt ??
                    normalized.conditionDescriptor?.metaPrompt ??
                    normalized.condition?.metaPrompt,
                criteria: normalized.criteria ??
                    normalized.conditionDescriptor?.criteria ??
                    normalized.condition?.criteria,
            };
            normalized.aiPrompt = aiPromptData;
            if (!normalized.condition) {
                normalized.condition = {
                    conditionType: ConditionDescriptor_1.ConditionType.AIPrompt,
                    ...aiPromptData,
                };
            }
        }
        if (normalized.aiPrompt && !normalized.condition) {
            normalized.condition = {
                conditionType: ConditionDescriptor_1.ConditionType.AIPrompt,
                userPrompt: normalized.aiPrompt.userPrompt,
                metaPrompt: normalized.aiPrompt.metaPrompt,
                criteria: normalized.aiPrompt.criteria,
            };
        }
        if (!normalized.condition &&
            (stepName === 'AssertPresent' ||
                stepName === 'AssertNotPresent' ||
                stepName === 'WaitUntil')) {
            const presenceType = stepName === 'AssertNotPresent'
                ? ConditionDescriptor_1.PresenceEvaluationType.NOT_PRESENT
                : ConditionDescriptor_1.PresenceEvaluationType.PRESENT;
            normalized.condition = {
                conditionType: ConditionDescriptor_1.ConditionType.Presence,
                presenceType,
            };
            normalized.extract = undefined;
        }
        if (!normalized.condition &&
            normalized.assertionValue !== undefined &&
            stepName in ConditionDescriptor_1.AssertionStepNameToField) {
            const comparisonType = ConditionDescriptor_1.AssertionStepNameToField[stepName];
            if ((0, ConditionDescriptor_1.isComparisonType)(comparisonType)) {
                const caseInsensitive = normalized.conditionOptions?.caseInsensitive ??
                    normalized.caseInsensitive ??
                    normalized.conditionDescriptor?.caseInsensitive ??
                    normalized.condition?.caseInsensitive;
                normalized.condition = {
                    conditionType: ConditionDescriptor_1.ConditionType.Comparison,
                    comparisonType,
                    comparatorValue: normalized.assertionValue,
                    caseInsensitive,
                };
            }
        }
        if (!normalized.onFailure && normalized.assertArguments?.onFailure) {
            normalized.onFailure = normalized.assertArguments.onFailure;
        }
        if (!normalized.observationScope &&
            normalized.assertArguments?.observationScope) {
            normalized.observationScope = normalized.assertArguments.observationScope;
        }
        return {
            target: normalized.target,
            extract: normalized.extract,
            condition: normalized.condition,
            count: normalized.count,
            onFailure: normalized.onFailure,
            observationScope: normalized.observationScope,
            actionCode: AssertStep.actionCode,
            description: normalized.description,
            disabled: normalized.disabled,
            id: normalized.id,
        };
    }
    static buildActionsFromDescriptor(stepName, stepArgs) {
        const assertionType = ConditionDescriptor_1.AssertionStepNameToField[stepName];
        const primaryAction = ActionBuilderUtils_1.ActionBuilderUtils.buildPrimaryActionFromTarget(stepArgs.target);
        const extractAction = ActionBuilderUtils_1.ActionBuilderUtils.buildExtractActionFromDescriptor(stepArgs.extract);
        const countAction = ActionBuilderUtils_1.ActionBuilderUtils.buildCountActionFromDescriptor(stepArgs.count);
        let conditionAction;
        if (assertionType === 'present' || assertionType === 'not_present') {
            conditionAction = new ConditionAction_1.ConditionAction('evaluate_presence', [
                assertionType,
            ]);
        }
        else if (stepName === 'WaitUntil') {
            conditionAction = new ConditionAction_1.ConditionAction('evaluate_presence', ['present']);
        }
        else {
            const conditionOptions = {
                caseInsensitive: stepArgs.condition?.caseInsensitive,
            };
            conditionAction = ActionBuilderUtils_1.ActionBuilderUtils.buildConditionActionFromDescriptor(stepArgs.condition, conditionOptions);
        }
        return {
            primaryAction,
            conditionAction,
            extractAction,
            countAction,
        };
    }
    static fromLegacyMablscript(args, actions) {
        const { descriptor, stepActions } = buildAssertStepDescriptorFromLegacyActions('assert', args, actions);
        const assertionType = (0, ConditionDescriptor_1.getAssertionConditionFieldFromDescriptor)(descriptor.condition);
        const stepName = ConditionDescriptor_1.AssertionConditionFieldToStepName[assertionType];
        const step = new AssertStep(descriptor, stepName, stepActions);
        return step;
    }
    toMablscript() {
        if (this.primaryAction instanceof MobileFindAction_1.MobileFindAction) {
            throw new Error('Mobile steps do not generate mablscript');
        }
        let primaryActionMablscriptPrefix = this.primaryAction.toMablscript();
        if (primaryActionMablscriptPrefix.length > 0) {
            primaryActionMablscriptPrefix += '.';
        }
        let primaryActionFindMablscriptPrefix = this.primaryAction.generateFindMablscript();
        if (primaryActionFindMablscriptPrefix.length > 0) {
            primaryActionFindMablscriptPrefix += '.';
        }
        const assertAction = `.assert(${!!(this.observationScope ||
            (this.onFailure && this.onFailure !== OnFailure.FailImmediately))
            ? (0, MablAction_1.convertObjectToMablscriptArgs)({
                observationScope: this.observationScope,
                onFailure: this.onFailure,
            })
            : ''})`;
        if (this.countAction) {
            return `${primaryActionMablscriptPrefix}${this.countAction.toMablscript()}.${this.conditionAction.toMablscript()}${assertAction}`;
        }
        if (this.extractAction) {
            return `${primaryActionMablscriptPrefix}${this.extractAction.toMablscript()}.${this.conditionAction.toMablscript()}${assertAction}`;
        }
        if (this.assertionType === 'present' ||
            this.assertionType === 'not_present') {
            return `${primaryActionFindMablscriptPrefix}evaluate_presence("${this.assertionType}")${assertAction}`;
        }
        if (this.assertionType === 'ai_prompt') {
            const aiOptions = {};
            if (this.aiPrompt?.metaPrompt) {
                aiOptions.metaPrompt = this.aiPrompt.metaPrompt;
            }
            if (this.aiPrompt?.criteria && this.aiPrompt.criteria.length > 0) {
                aiOptions.criteria = this.aiPrompt?.criteria;
            }
            return `${primaryActionFindMablscriptPrefix}evaluate_ai_prompt("${this.aiPrompt?.userPrompt}", ${JSON.stringify(aiOptions)})${assertAction}`;
        }
        return `${primaryActionMablscriptPrefix}${this.conditionAction.toMablscript()}${assertAction}`;
    }
    getInputVariables() {
        return (0, MablAction_1.distinctStrings)([
            ...this.primaryAction.getInputVariables(),
            ...(this.countAction?.getInputVariables() ?? []),
            ...this.conditionAction.getInputVariables(),
            ...(this.extractAction?.getInputVariables() ?? []),
        ]);
    }
    stepDescription() {
        if (this.assertionType === 'ai_prompt') {
            return `Assert AI prompt: "${this.aiPrompt?.userPrompt}"`;
        }
        if (this.isWaitUntilStep) {
            const elementDescription = this.humanizeFind();
            return `Wait until ${elementDescription} is present`;
        }
        const elementDescription = this.humanizeFind();
        if (this.assertionType === 'present') {
            return `Assert that ${elementDescription} is present`;
        }
        if (this.assertionType === 'not_present') {
            return `Assert that ${elementDescription} is not present`;
        }
        if (this.countAction) {
            const comparator = this.getComparatorText();
            return `Assert that count of ${elementDescription} ${comparator} ${this.getDisplayAssertionValue()}`;
        }
        if (this.extractAction) {
            const attribute = this.extractAction.extractionAttribute;
            const comparator = this.getComparatorText();
            return `Assert that ${attribute} of ${elementDescription} ${comparator} ${this.getDisplayAssertionValue()}`;
        }
        const comparator = this.getComparatorText();
        return `Assert that ${elementDescription} ${comparator} ${this.getDisplayAssertionValue()}`;
    }
    getDisplayAssertionValue() {
        if (!this.assertionValue) {
            return this.assertionValue;
        }
        return this.assertionValue.replace(MablSymbol_1.SINGLE_VARIABLE_PATTERN_REGEX, (_, name) => (0, MablSymbol_1.formatSymbol)((0, mablscriptFind_1.removeUserNamespace)(name)));
    }
    humanizeFind() {
        if (this.primaryAction instanceof GetUrlAction_1.GetUrlAction) {
            return 'current URL';
        }
        if (this.primaryAction instanceof GetVariableValue_1.GetVariableValue) {
            return `variable ${(0, MablSymbol_1.formatSymbol)((0, mablscriptFind_1.removeUserNamespace)(this.primaryAction.variable.name))}`;
        }
        if (this.primaryAction instanceof GetViewportAction_1.GetViewportAction) {
            return 'viewport';
        }
        if (this.primaryAction instanceof FindAction_1.FindAction) {
            const findDescriptor = this.primaryAction.toDescriptor();
            return (0, MablStepWithFindAction_1.humanizeFindDescriptor)(findDescriptor);
        }
        return 'element';
    }
    getComparatorText() {
        switch (this.assertionType) {
            case 'equals':
                return 'equals';
            case 'does_not_equal':
                return 'does not equal';
            case 'contains':
                return 'contains';
            case 'does_not_contain':
                return 'does not contain';
            case 'matches_regex':
                return 'matches';
            case 'greater_than':
                return 'is greater than';
            case 'less_than':
                return 'is less than';
            case 'greater_than_or_equals':
                return 'is greater than or equal to';
            case 'less_than_or_equals':
                return 'is less than or equal to';
            case 'starts_with':
                return 'starts with';
            case 'starts_without':
                return 'starts without';
            case 'ends_with':
                return 'ends with';
            case 'ends_without':
                return 'ends without';
            default:
                return 'is';
        }
    }
    static create(descriptor) {
        descriptor.id = descriptor.id ?? MablStepV2_1.MablStepV2.generateStepId();
        return new AssertStep(descriptor);
    }
}
exports.AssertStep = AssertStep;
function buildAssertStepDescriptorFromLegacyActions(_name, args, actions) {
    const firstAction = actions[0];
    let primaryAction;
    if (firstAction instanceof FindAction_1.FindAction ||
        firstAction instanceof MobileFindAction_1.MobileFindAction ||
        firstAction instanceof GetUrlAction_1.GetUrlAction ||
        firstAction instanceof GetVariableValue_1.GetVariableValue ||
        firstAction instanceof GetViewportAction_1.GetViewportAction) {
        primaryAction = firstAction;
    }
    else if (firstAction instanceof ConditionAction_1.ConditionAction &&
        (0, ConditionDescriptor_1.isAIPromptCondition)(firstAction.conditionDescriptor)) {
        primaryAction = new GetViewportAction_1.GetViewportAction();
    }
    else {
        throw new Error(`Unexpected action type. Expected FindAction|MobileFindAction|GetUrlAction|GetVariableValue but got: ${firstAction.constructor.name}`);
    }
    let extractAction;
    let countAction;
    let conditionAction;
    if (actions.length === 3) {
        if (actions[1] instanceof CountAction_1.CountAction) {
            countAction = actions[1];
        }
        else {
            extractAction = actions[1];
        }
        conditionAction = actions[2];
    }
    else if (firstAction instanceof ConditionAction_1.ConditionAction) {
        conditionAction = firstAction;
    }
    else {
        conditionAction = actions[1];
    }
    const find = primaryAction.toDescriptor();
    const assertArguments = args[0] && typeof args[0] === 'object'
        ? args[0]
        : undefined;
    const onFailure = assertArguments?.onFailure || OnFailure.FailImmediately;
    const observationScope = assertArguments?.observationScope;
    const descriptor = {
        target: find,
        extract: extractAction?.toDescriptor(),
        condition: conditionAction.conditionDescriptor,
        count: countAction?.countDescriptor,
        onFailure,
        observationScope,
        actionCode: AssertStep.actionCode,
    };
    const stepActions = {
        primaryAction,
        conditionAction,
        extractAction,
        countAction,
    };
    return { descriptor, stepActions };
}
