"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FindAction = exports.formattedFindTypeToMablscript = exports.findTypesToFormattedType = void 0;
exports.isElementSelector = isElementSelector;
exports.normalize = normalize;
exports.isEmailSelectorOrDescriptor = isEmailSelectorOrDescriptor;
exports.normalizeEmail = normalizeEmail;
const mablscriptFind_1 = require("../mablscriptFind");
const MablAction_1 = require("../MablAction");
exports.findTypesToFormattedType = {
    find_all: 'FindAll',
    find_any: 'FindFirst',
    find_cookie: 'FindCookie',
    find_first: 'FindFirst',
    find_one: 'FindOne',
    find_email: 'FindEmail',
    find_tab: 'FindTab',
    find_last: 'FindLast',
};
exports.formattedFindTypeToMablscript = {};
Object.entries(exports.findTypesToFormattedType).forEach(([findType, field]) => (exports.formattedFindTypeToMablscript[field] = findType));
class FindAction extends MablAction_1.MablAction {
    static mablScriptStepNames = [
        'find_all',
        'find_one',
        'find_first',
        'find_last',
        'find_any',
        'find_cookie',
        'find_email',
        'find_tab',
    ];
    static yamlMablScriptNames = [
        'FindAll',
        'FindOne',
        'FindFirst',
        'FindLast',
        'FindAny',
        'FindCookie',
        'FindEmail',
        'FindTab',
    ];
    findDescriptor;
    isValid;
    constructor(name, args) {
        super(name, name, args);
        const actionName = this.getActionName();
        if (!(0, mablscriptFind_1.isFindType)(actionName)) {
            throw new Error(`Unknown find type for action: ${actionName}`);
        }
        const findType = mablscriptFind_1.FindType.fromString(actionName);
        this.isValid = true;
        switch (findType) {
            case mablscriptFind_1.FindType.FIND_ONE: {
                const [selectors, options] = this.getActionArgs();
                if (!isElementSelector(selectors)) {
                    this.isValid = false;
                }
                const [target, ancestor] = Array.isArray(selectors)
                    ? [...selectors]
                    : [selectors];
                const findTarget = normalize(target);
                if (ancestor) {
                    findTarget.auxiliaryDescriptors = [normalize(ancestor)];
                }
                this.findDescriptor = {
                    findType,
                    findTarget,
                };
                if ((0, mablscriptFind_1.isFindOptions)(options)) {
                    this.findDescriptor.findOptions = options;
                }
                break;
            }
            case mablscriptFind_1.FindType.FIND_FIRST:
            case mablscriptFind_1.FindType.FIND_LAST:
            case mablscriptFind_1.FindType.FIND_ANY:
            case mablscriptFind_1.FindType.FIND_ALL: {
                const [primarySelector, foundElementSelectors, findOptions] = this.getActionArgs();
                if (!(0, mablscriptFind_1.isCssSelector)(primarySelector) &&
                    !(0, mablscriptFind_1.isXPathSelector)(primarySelector)) {
                    this.isValid = false;
                }
                this.findDescriptor = {
                    findOptions,
                    findTarget: primarySelector,
                    findType,
                    foundElementSelectors,
                    primarySelectors: primarySelector,
                };
                break;
            }
            case mablscriptFind_1.FindType.FIND_COOKIE: {
                const [selectors] = this.getActionArgs();
                if (!(0, mablscriptFind_1.isCookieSelector)(selectors)) {
                    this.isValid = false;
                }
                this.findDescriptor = {
                    findType,
                    findTarget: selectors,
                };
                break;
            }
            case mablscriptFind_1.FindType.FIND_EMAIL:
                const [selectors] = this.getActionArgs();
                if (!isEmailSelectorOrDescriptor(selectors)) {
                    this.isValid = false;
                }
                const [target] = Array.isArray(selectors)
                    ? [...selectors]
                    : [selectors];
                const findTarget = normalizeEmail(target);
                this.findDescriptor = {
                    findType,
                    findTarget,
                };
                break;
            case mablscriptFind_1.FindType.FIND_TAB: {
                const [selectors] = this.getActionArgs();
                if (selectors !== 'initial' && !(0, mablscriptFind_1.isTabSelector)(selectors)) {
                    this.isValid = false;
                }
                this.findDescriptor = {
                    findType,
                    findTarget: selectors,
                };
            }
        }
        Object.freeze(this.findDescriptor);
        this.actionSourceIndexInStep = 0;
    }
    toDescriptor() {
        return this.findDescriptor;
    }
    static findActionFromStepArgs(stepArgs, suppliedFindType) {
        let findType;
        if (stepArgs.find) {
            findType = stepArgs.find.findType || 'find_one';
            const findTarget = stepArgs.find.findTarget;
            const findOptions = stepArgs.find.findOptions;
            if (findType === 'find_one') {
                if (findTarget.selector) {
                    if (findTarget.auxiliaryDescriptors?.length) {
                        const ancestors = [...findTarget.auxiliaryDescriptors];
                        return new FindAction(findType, [
                            [findTarget, ...ancestors],
                            findOptions,
                        ]);
                    }
                    return new FindAction(findType, [findTarget, findOptions]);
                }
                return new FindAction(findType, [findTarget, findOptions]);
            }
            if (findType === 'find_cookie') {
                return new FindAction(findType, [findTarget]);
            }
            if (findType === 'find_email') {
                return new FindAction(findType, [findTarget, findOptions]);
            }
            const primarySelector = findTarget && typeof findTarget === 'object' && 'selector' in findTarget
                ? findTarget.selector
                : findTarget;
            return new FindAction(findType, [
                primarySelector,
                stepArgs.find.foundElementSelectors,
                findOptions,
            ]);
        }
        if (stepArgs.selector) {
            if (suppliedFindType) {
                findType = suppliedFindType;
            }
            else if (stepArgs.findType) {
                findType = exports.formattedFindTypeToMablscript[stepArgs.findType];
            }
            else {
                const selectorKeys = Object.keys(stepArgs.selector).filter((k) => k !== 'selector_type');
                findType =
                    selectorKeys.length === 1 &&
                        (selectorKeys[0] === 'xpath' || selectorKeys[0] === 'css_query')
                        ? 'find_first'
                        : exports.formattedFindTypeToMablscript.FindOne;
            }
            if (!stepArgs.selectorAncestors) {
                return new FindAction(findType, [
                    stepArgs.selector,
                    stepArgs.findOptions,
                ]);
            }
            const ancestors = stepArgs.selectorAncestors || [];
            return new FindAction(findType, [
                [stepArgs.selector, ...ancestors],
                stepArgs.findOptions,
            ]);
        }
        throw new Error('No selector found in yaml');
    }
    toYaml() {
        const result = {};
        const find = this.toDescriptor();
        switch (find.findType) {
            case mablscriptFind_1.FindType.FIND_FIRST:
            case mablscriptFind_1.FindType.FIND_LAST:
            case mablscriptFind_1.FindType.FIND_ANY:
            case mablscriptFind_1.FindType.FIND_ALL:
                result.find_type = find.findType;
                result.selector = find.findTarget;
                break;
            case mablscriptFind_1.FindType.FIND_ONE:
                result.selector = find.findTarget.selector;
                if (find.findTarget.auxiliaryDescriptors?.length) {
                    result.selectorAncestors = find.findTarget.auxiliaryDescriptors.map((descriptor) => descriptor.selector);
                }
                break;
            default:
                throw new Error(`Unexpected find type ${find.findType}`);
        }
        return result;
    }
    toMablscript() {
        return this.generateFindMablscript();
    }
    generateFindMablscript() {
        let action = this.findDescriptor.findType;
        let args = '';
        switch (this.findDescriptor.findType) {
            case mablscriptFind_1.FindType.FIND_ONE:
                const find = this.findDescriptor;
                const selectors = find.findTarget.auxiliaryDescriptors?.length
                    ? '[' +
                        [find.findTarget, ...find.findTarget.auxiliaryDescriptors]
                            .map(mablscriptFind_1.buildFindDescriptorString)
                            .filter(Boolean)
                            .join(', ') +
                        ']'
                    : (0, mablscriptFind_1.buildFindDescriptorString)(find.findTarget);
                const options = buildFindOptionsString(find.findOptions);
                args = [selectors, options].filter(Boolean).join(', ');
                break;
            case mablscriptFind_1.FindType.FIND_LAST:
            case mablscriptFind_1.FindType.FIND_ANY:
            case mablscriptFind_1.FindType.FIND_ALL:
            case mablscriptFind_1.FindType.FIND_FIRST: {
                const find = this.findDescriptor;
                const selector = (0, mablscriptFind_1.buildElementSelectorString)(find.findTarget);
                let foundElementSelectors;
                if (find.foundElementSelectors) {
                    if (Array.isArray(find.foundElementSelectors)) {
                        foundElementSelectors = find.foundElementSelectors
                            .map((selector) => (0, mablscriptFind_1.buildFindDescriptorString)({ selector }))
                            .join(', ');
                    }
                    else {
                        foundElementSelectors = (0, mablscriptFind_1.buildFindDescriptorString)({
                            selector: find.foundElementSelectors,
                        });
                    }
                }
                else {
                    foundElementSelectors = '{selector_type: "element"}';
                }
                const options = buildFindOptionsString(find.findOptions);
                args = [selector, foundElementSelectors, options]
                    .filter(Boolean)
                    .join(', ');
                if (find.findType === mablscriptFind_1.FindType.FIND_ANY) {
                    action = mablscriptFind_1.FindType.FIND_FIRST;
                }
                break;
            }
            case mablscriptFind_1.FindType.FIND_COOKIE:
                args = (0, mablscriptFind_1.buildCookieSelectorString)(this.findDescriptor.findTarget);
                break;
            case mablscriptFind_1.FindType.FIND_EMAIL: {
                args = (0, mablscriptFind_1.buildFindEmailDescriptorString)(this.findDescriptor.findTarget);
                break;
            }
            case mablscriptFind_1.FindType.FIND_TAB:
                args = (0, mablscriptFind_1.buildTabSelectorString)(this.findDescriptor.findTarget);
                break;
            default:
                throw new Error(`Error generating mablscript: Unexpected find type in ${JSON.stringify(this.findDescriptor)}`);
        }
        return `${action}(${args})`;
    }
    isValidDescriptor() {
        return this.isValid;
    }
    getInputVariables() {
        return MablAction_1.MablAction.findUniqueVariableReferencesInValue(this.findDescriptor);
    }
}
exports.FindAction = FindAction;
function buildFindOptionsString(findOptions) {
    if (!findOptions) {
        return undefined;
    }
    return JSON.stringify(findOptions);
}
function isElementSelector(maybeSelectors) {
    const [target, ancestor] = Array.isArray(maybeSelectors)
        ? [...maybeSelectors]
        : [maybeSelectors];
    const validTarget = (0, mablscriptFind_1.isStandardSelector)(target) || (0, mablscriptFind_1.isNormalizedFindDescriptor)(target);
    const validAncestor = !ancestor ||
        (0, mablscriptFind_1.isStandardSelector)(ancestor) ||
        (0, mablscriptFind_1.isNormalizedFindDescriptor)(ancestor);
    return !!(validTarget && validAncestor);
}
function normalize(maybeFindDescriptor) {
    if ((0, mablscriptFind_1.isNormalizedFindDescriptor)(maybeFindDescriptor)) {
        return { ...maybeFindDescriptor };
    }
    const hasSelector = maybeFindDescriptor && 'selector' in maybeFindDescriptor;
    return hasSelector ? maybeFindDescriptor : { selector: maybeFindDescriptor };
}
function isEmailSelectorOrDescriptor(selectorOrDescriptor) {
    const [target] = Array.isArray(selectorOrDescriptor)
        ? [...selectorOrDescriptor]
        : [selectorOrDescriptor];
    return (0, mablscriptFind_1.isEmailSelector)(target) || (0, mablscriptFind_1.isNormalizedFindEmailDescriptor)(target);
}
function normalizeEmail(selectorOrDescriptor) {
    if ((0, mablscriptFind_1.isNormalizedFindEmailDescriptor)(selectorOrDescriptor)) {
        return { ...selectorOrDescriptor };
    }
    if ((0, mablscriptFind_1.isEmailSelector)(selectorOrDescriptor)) {
        if (selectorOrDescriptor.subject_exact) {
            const { subject_exact: subjectExact, ...restOfObject } = selectorOrDescriptor;
            return {
                selector: {
                    subject: subjectExact,
                    ...restOfObject,
                },
                type: 'email',
            };
        }
    }
    return { selector: selectorOrDescriptor, type: 'email' };
}
