import Multivalue from '../multivalue/Multivalue';
import { announceScreenReaderMessage, convertStringToHTMLElement } from '../../../utils/index';
import Widgets from '../../../widgets/index';
import _ from 'lodash';
export default class Input extends Multivalue {
    constructor(component, options, data) {
        super(component, options, data);
        this.triggerUpdateValueAt = _.debounce(this.updateValueAt.bind(this), 100);
    }
    static schema(...extend) {
        return Multivalue.schema({
            widget: {
                type: 'input',
            },
        }, ...extend);
    }
    get inputInfo() {
        const attr = {
            name: this.options.name,
            type: this.component.inputType || 'text',
            class: 'form-control',
            lang: this.options.language,
        };
        if (this.options.attachMode === 'builder' ||
            this.options.building ||
            _.get(this.root, 'form.settings.disableAutocomplete')) {
            attr.autocomplete = this.autocompleteDisableAttrName;
        }
        if (this.component.inputMode) {
            attr.inputmode = this.component.inputMode;
        }
        if (this.component.placeholder && !this.options?.readOnly) {
            attr.placeholder = this.getFormattedAttribute(this.component.placeholder);
        }
        if (this.component.tabindex) {
            attr.tabindex = this.component.tabindex;
        }
        if (this.disabled) {
            attr.disabled = 'disabled';
        }
        if (this.component.autocomplete) {
            attr.autocomplete = this.component.autocomplete;
        }
        _.defaults(attr, this.component.attributes);
        return {
            id: this.key,
            type: 'input',
            changeEvent: 'input',
            content: '',
            attr,
        };
    }
    get autocompleteDisableAttrName() {
        return 'off';
    }
    get maskOptions() {
        return _.map(this.component.inputMasks, (mask) => {
            return {
                label: mask.label,
                value: mask.label,
            };
        });
    }
    get isMultipleMasksField() {
        return (this.component.allowMultipleMasks &&
            !!this.component.inputMasks &&
            !!this.component.inputMasks.length);
    }
    getMaskByName(maskName) {
        const inputMask = _.find(this.component.inputMasks, (inputMask) => {
            return inputMask.label === maskName;
        });
        return inputMask ? inputMask.mask : undefined;
    }
    setInputMask(input, inputMask) {
        const mask = inputMask || this.component.displayMask || this.component.inputMask;
        return super.setInputMask(input, mask, !this.component.placeholder);
    }
    getMaskOptions() {
        return this.component.inputMasks.map((mask) => ({
            label: mask.label,
            value: mask.label,
        }));
    }
    getWordCount(value) {
        return !value ? 0 : value.trim().split(/\s+/).length;
    }
    get remainingWords() {
        const maxWords = _.parseInt(_.get(this.component, 'validate.maxWords'), 10);
        const wordCount = this.getWordCount(this.dataValue);
        return maxWords - wordCount;
    }
    get prefix() {
        return this.component.prefix;
    }
    get suffix() {
        if (this.component.widget && this.component.widget.type === 'calendar') {
            const calendarIcon = this.renderTemplate('icon', {
                ref: 'icon',
                // After font-awesome would be updated to v5.x, "clock-o" should be replaced with "clock"
                className: this.iconClass(this.component.enableDate || this.component.widget.enableDate ? 'calendar' : 'clock-o'),
                styles: '',
                content: '',
            }).trim();
            if (this.component.prefix !== calendarIcon) {
                // converting string to HTML markup to render correctly DateTime component in portal.form.io
                return convertStringToHTMLElement(calendarIcon, `[${this._referenceAttributeName}="icon"]`);
            }
        }
        return this.component.suffix;
    }
    renderElement(value, index) {
        // Double quotes cause the input value to close so replace them with html quote char.
        if (value && typeof value === 'string') {
            value = value.replace(/"/g, '&quot;');
        }
        const info = this.inputInfo;
        info.attr = info.attr || {};
        info.attr.value = this.getValueAsString(this.formatValue(this.parseValue(value))).replace(/"/g, '&quot;');
        const valueMask = this.component.inputMask;
        const displayMask = this.component.displayMask;
        const hasDifferentDisplayAndSaveFormats = valueMask && displayMask && valueMask !== displayMask;
        if (this.isMultipleMasksField) {
            info.attr.class += ' formio-multiple-mask-input';
        }
        return this.isMultipleMasksField
            ? this.renderTemplate('multipleMasksInput', {
                input: info,
                value,
                index,
                selectOptions: this.getMaskOptions() || [],
            }, this.isHtmlRenderMode() ? 'html' : null)
            : this.renderTemplate('input', {
                prefix: this.prefix,
                suffix: this.suffix,
                input: info,
                value: this.formatValue(this.parseValue(value)),
                hasValueMaskInput: hasDifferentDisplayAndSaveFormats,
                index,
            }, this.isHtmlRenderMode() ? 'html' : null);
    }
    setCounter(type, element, count, max) {
        if (max) {
            const remaining = max - count;
            if (remaining > 0) {
                this.removeClass(element, 'text-danger');
            }
            else {
                this.addClass(element, 'text-danger');
            }
            this.setContent(element, this.t(`typeRemaining`, {
                remaining: remaining,
                type: type,
            }));
        }
        else {
            this.setContent(element, this.t(`typeCount`, {
                count: count,
                type: type,
            }));
        }
    }
    updateValueAt(value, flags, index) {
        if (flags.modified) {
            announceScreenReaderMessage(this, value, index);
        }
        flags = flags || {};
        if (_.get(this.component, 'showWordCount', false)) {
            if (this.refs.wordcount && this.refs.wordcount[index]) {
                const maxWords = _.parseInt(_.get(this.component, 'validate.maxWords', 0), 10);
                this.setCounter(this.t('words'), this.refs.wordcount[index], this.getWordCount(value), maxWords);
            }
        }
        if (_.get(this.component, 'showCharCount', false)) {
            if (this.refs.charcount && this.refs.charcount[index]) {
                const maxChars = _.parseInt(_.get(this.component, 'validate.maxLength', 0), 10);
                this.setCounter(this.t('characters'), this.refs.charcount[index], value.length, maxChars);
            }
        }
    }
    getValueAt(index) {
        const input = this.performInputMapping(this.refs.input[index]);
        if (input && input.widget) {
            return input.widget.getValue();
        }
        return input ? input.value : undefined;
    }
    updateValue(value, flags, index) {
        flags = flags || {};
        const changed = super.updateValue(value, flags);
        this.triggerUpdateValueAt(this.dataValue, { ...flags }, index);
        return changed;
    }
    parseValue(value) {
        return value;
    }
    formatValue(value) {
        return value;
    }
    attach(element) {
        this.loadRefs(element, {
            announceMessage: 'multiple',
            charcount: 'multiple',
            wordcount: 'multiple',
            prefix: 'multiple',
            suffix: 'multiple',
        });
        return super.attach(element);
    }
    getWidget(index) {
        index = index || 0;
        if (this.refs.input && this.refs.input[index]) {
            return this.refs.input[index].widget;
        }
        return null;
    }
    attachElement(element, index) {
        super.attachElement(element, index);
        if (element.widget) {
            element.widget.destroy();
        }
        // Attach the widget.
        let promise = Promise.resolve();
        element.widget = this.createWidget(index);
        if (element.widget) {
            promise = element.widget.attach(element);
            if (this.refs.prefix && this.refs.prefix[index]) {
                element.widget.addPrefix(this.refs.prefix[index]);
            }
            if (this.refs.suffix && this.refs.suffix[index]) {
                element.widget.addSuffix(this.refs.suffix[index]);
            }
        }
        // Add focus and blur events.
        this.addFocusBlurEvents(element);
        if (this.options.submitOnEnter) {
            this.addEventListener(element, 'keypress', (event) => {
                const key = event.keyCode || event.which;
                if (key === 13) {
                    event.preventDefault();
                    event.stopPropagation();
                    this.emit('submitButton');
                }
            });
        }
        this.on('focus', (comp) => {
            announceScreenReaderMessage(comp, comp.dataValue, 0, true);
        });
        this.on('blur', (comp) => {
            const el = comp.refs?.["announceMessage"]?.[0];
            if (el) {
                el.textContent = "";
            }
        });
        return promise;
    }
    /**
     * Creates an instance of a widget for this component.
     * @param {number} index - The index of the widget.
     * @returns {*} - The widget instance.
     */
    createWidget(index) {
        // Return null if no widget is found.
        if (!this.component.widget) {
            return null;
        }
        // Get the widget settings.
        const settings = typeof this.component.widget === 'string'
            ? {
                type: this.component.widget,
            }
            : this.component.widget;
        if (this.root?.shadowRoot) {
            settings.shadowRoot = this.root?.shadowRoot;
        }
        // Make sure we have a widget.
        if (!Widgets.hasOwnProperty(settings.type)) {
            return null;
        }
        // Create the widget.
        const widget = new Widgets[settings.type](settings, this.component, this, index);
        widget.on('update', () => this.updateValue(this.getValue(), {
            modified: true,
        }, index), true);
        widget.on('redraw', () => this.redraw(), true);
        return widget;
    }
    teardown() {
        if (this.element && this.element.widget) {
            this.element.widget.destroy();
            delete this.element.widget;
        }
        if (this.refs && this.refs.input) {
            for (let i = 0; i <= this.refs.input.length; i++) {
                const widget = this.getWidget(i);
                if (widget) {
                    widget.destroy();
                }
            }
        }
        super.teardown();
    }
    detach() {
        if (this.refs && this.refs.input) {
            for (let i = 0; i <= this.refs.input.length; i++) {
                const widget = this.getWidget(i);
                if (widget) {
                    widget.destroy();
                }
            }
        }
        this.refs.input = [];
        super.detach();
    }
}
