"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SendKeyStep = void 0;
const FindAction_1 = require("../actions/FindAction");
const mablscriptFind_1 = require("../mablscriptFind");
const SendKeyStepDescriptor_1 = require("../types/SendKeyStepDescriptor");
const MablStepWithFindAction_1 = require("../MablStepWithFindAction");
class SendKeyStep extends MablStepWithFindAction_1.MablStepWithFindAction {
    static stepName = 'SendKeys';
    static actionCode = 'send_keys';
    static mablScriptStepNames = [SendKeyStep.actionCode];
    static yamlMablScriptNames = [SendKeyStep.stepName];
    keys;
    static modifierKeyHumanizedMap = {
        altKey: 'Alt',
        ctrlKey: 'Ctrl',
        metaKey: 'Cmd',
        shiftKey: 'Shift',
    };
    static modifierKeyIdentifierMap = {
        altKey: false,
        ctrlKey: false,
        metaKey: false,
        shiftKey: false,
    };
    static specialKeys = [
        'Enter',
        'Tab',
        'Escape',
        'Backspace',
        'Delete',
        'ArrowUp',
        'ArrowDown',
        'ArrowLeft',
        'ArrowRight',
        'Home',
        'End',
        'PageUp',
        'PageDown',
        'Insert',
        'F1',
        'F2',
        'F3',
        'F4',
        'F5',
        'F6',
        'F7',
        'F8',
        'F9',
        'F10',
        'F11',
        'F12',
    ];
    constructor(descriptor, findAction) {
        super(SendKeyStep.stepName, descriptor, SendKeyStep.actionCode, findAction);
        if (!this.isValidDescriptor(this.descriptor)) {
            throw new Error(`${SendKeyStep.stepName}: descriptor.keys must be a non-empty array of valid CrossPlatformKeyPress objects`);
        }
        this.keys = this.descriptor.keys;
        if (this.isPasswordField() && this.description) {
            const masked = this.stepDescription();
            this.description = masked;
            this.descriptor.description = masked;
        }
    }
    isValidDescriptor(value) {
        return (Array.isArray(value.keys) &&
            value.keys.length > 0 &&
            value.keys.every(SendKeyStepDescriptor_1.isCrossPlatformKeyPress));
    }
    static validateActionsAndGetFindAction(name, actions) {
        if (actions.length !== 1 || !(actions[0] instanceof FindAction_1.FindAction)) {
            throw new Error(`${name} step should have one sub-action and it should be a find`);
        }
        if ((0, mablscriptFind_1.isFindElementType)(actions[0].getActionName())) {
            return actions[0];
        }
        throw new Error(`Unexpected find action for ${name} step: ${JSON.stringify(actions[0])}`);
    }
    static validateKeys(name, args) {
        if (!args?.length) {
            throw new Error(`${name} step expects at least one key`);
        }
        if (args.every(SendKeyStepDescriptor_1.isCrossPlatformKeyPress)) {
            return args;
        }
        throw new Error(`Unexpected key format for ${name} step: ${JSON.stringify(args)}`);
    }
    getStepName() {
        return SendKeyStep.stepName;
    }
    static fromYaml(_stepName, stepArgs) {
        if (stepArgs.sendKeys && !stepArgs.keys) {
            stepArgs.keys = stepArgs.sendKeys;
        }
        return new SendKeyStep(stepArgs);
    }
    static fromLegacyMablscript(args, actions) {
        const findAction = SendKeyStep.validateActionsAndGetFindAction(SendKeyStep.stepName, actions);
        const keys = SendKeyStep.validateKeys(SendKeyStep.stepName, args);
        const stepDescriptor = buildStepDescriptor(findAction, keys);
        const step = new SendKeyStep(stepDescriptor, findAction);
        step.actions = actions;
        return step;
    }
    toMablscript() {
        const keysToSend = this.keys
            .map((key) => (0, mablscriptFind_1.buildStepArgumentString)({ params: { ...key }, legacy: true }))
            .join();
        return `${this.findAction.toMablscript()}.send_keys(${keysToSend})`;
    }
    getInputVariables() {
        return this.findAction.getInputVariables();
    }
    stepDescription() {
        const keypresses = this.generateHumanizedKeys(this.isPasswordField());
        const pluralizedKeypress = this.keys.length > 1 ? 'keypresses' : 'keypress';
        const elementDescription = this.humanizeFind();
        return `Send "${keypresses}" ${pluralizedKeypress} to ${elementDescription}`;
    }
    isPasswordField() {
        const findDescriptor = this.findAction.findDescriptor;
        if (findDescriptor.findType !== mablscriptFind_1.FindType.FIND_ONE) {
            return false;
        }
        const selector = findDescriptor.findTarget?.selector;
        return selector?.inputElementType === 'password';
    }
    generateHumanizedKeys(isPasswordField) {
        return this.keys
            .map((key) => this.humanizeKeyInfo(key, isPasswordField))
            .join('');
    }
    humanizeKeyInfo(keyInfo, isPasswordField) {
        if (!keyInfo) {
            return '';
        }
        const activeModifiers = SendKeyStep.getActiveModifiers(keyInfo, false);
        const activeModifierStrings = activeModifiers.map((modifierKey) => SendKeyStep.modifierKeyHumanizedMap[modifierKey]);
        const hasActiveModifiersFlag = !this.isEmpty(activeModifierStrings);
        const activeModifiersPrefix = hasActiveModifiersFlag
            ? activeModifierStrings.join('+') + '+'
            : '';
        const hasMacOverride = keyInfo.mac?.key;
        const hasWindowsOverride = keyInfo.windows?.key;
        let humanizedString = `${activeModifiersPrefix}${this.generateHumanizedKey(keyInfo, isPasswordField)}`;
        if (hasMacOverride || hasWindowsOverride) {
            humanizedString = `Default: ${humanizedString}`;
        }
        if (hasMacOverride) {
            humanizedString += `, Mac: ${this.humanizeKeyInfo(keyInfo.mac, isPasswordField)}`;
        }
        if (hasWindowsOverride) {
            humanizedString += `, Windows: ${this.humanizeKeyInfo(keyInfo.windows, isPasswordField)}`;
        }
        return humanizedString;
    }
    generateHumanizedKey(keyInfo, isPasswordField) {
        if (SendKeyStep.keyIsSpecial(keyInfo.key)) {
            return `[${keyInfo.key.toUpperCase()}]`;
        }
        return isPasswordField ? '*' : keyInfo.key;
    }
    static keyIsSpecial(key) {
        return SendKeyStep.specialKeys.includes(key);
    }
    static getActiveModifiers(keyInfo, includeOverrides) {
        const modifiers = SendKeyStep.getModifiers(keyInfo, includeOverrides);
        return Object.keys(SendKeyStep.pickBy(modifiers));
    }
    static getModifiers(keyInfo, includeOverrides) {
        const objectKeys = Object.keys(SendKeyStep.modifierKeyIdentifierMap);
        let modifiers = SendKeyStep.pick(keyInfo, objectKeys);
        if (includeOverrides) {
            modifiers = {
                ...modifiers,
                ...SendKeyStep.pick(keyInfo, objectKeys.map((key) => `windows.${key}`)),
                ...SendKeyStep.pick(keyInfo, objectKeys.map((key) => `mac.${key}`)),
            };
        }
        return modifiers;
    }
    isEmpty(obj) {
        return obj === undefined || Object.keys(obj).length === 0;
    }
    static pick(object, paths) {
        const result = {};
        for (const path of paths) {
            if (path in object) {
                result[path] = object[path];
            }
        }
        return result;
    }
    static pickBy(object) {
        const result = {};
        for (const key in object) {
            if (object[key]) {
                result[key] = object[key];
            }
        }
        return result;
    }
}
exports.SendKeyStep = SendKeyStep;
function buildStepDescriptor(findAction, keys) {
    const find = findAction.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_ONE:
            return {
                find,
                keys,
                actionCode: 'send_keys',
            };
        default:
            throw new Error(`Error generating step descriptor for SendKeys: Unexpected find type ${find.findType}`);
    }
}
