/**
 * @license
 * Copyright Tyler Technologies, Inc. 
 * License: Apache-2.0
 */
import { getShadowElement, listenOwnProperty, randomChars, toggleAttribute } from '@tylertech/forge-core';
import { FIELD_CONSTANTS } from '../field';
import { BaseFieldAdapter } from '../field/base/base-field-adapter';
import { TEXT_FIELD_CONSTANTS } from './text-field-constants';
export class TextFieldAdapter extends BaseFieldAdapter {
    get hasValue() {
        return this._inputElements.some(el => !!el.value);
    }
    get hasPlaceholder() {
        return this._inputElements.some(el => !!el.placeholder);
    }
    get popoverTargetElement() {
        if (!this._popoverTargetElement) {
            this._popoverTargetElement = getShadowElement(this._fieldElement, FIELD_CONSTANTS.selectors.POPOVER_TARGET);
        }
        return this._popoverTargetElement;
    }
    constructor(component) {
        super(component);
        this._inputElements = [];
        this._destroyValueChangerListeners = [];
        this._fieldElement = getShadowElement(component, TEXT_FIELD_CONSTANTS.selectors.FIELD);
        this._clearButtonSlotElement = getShadowElement(component, TEXT_FIELD_CONSTANTS.selectors.CLEAR_BUTTON_SLOT);
        this._fieldElement.setAttribute('exportparts', Object.values(FIELD_CONSTANTS.parts).join(', '));
        this._clearButtonSlotElement.remove();
    }
    addRootListener(name, listener) {
        this._fieldElement.addEventListener(name, listener);
    }
    removeRootListener(name, listener) {
        this._fieldElement.removeEventListener(name, listener);
    }
    disableInput(disabled) {
        this._inputElements.forEach(el => el.disabled = disabled);
    }
    inputIsDisabled() {
        return this._inputElements.some(el => el.disabled);
    }
    click() {
        var _a;
        (_a = this._inputElements[0]) === null || _a === void 0 ? void 0 : _a.focus();
    }
    applyLabel(value) {
        this._inputElements.forEach((inputElement) => {
            toggleAttribute(inputElement, !!value, 'aria-label', value !== null && value !== void 0 ? value : '');
        });
    }
    handleDefaultSlotChange(slot, listener) {
        var _a;
        // Destroy the mutation observer if it exists
        (_a = this._inputMutationObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
        // If there are no assigned elements, return
        const assignedElements = slot.assignedElements();
        if (!assignedElements.length) {
            return;
        }
        // Get all the slotted inputs and textfields, if a textfield is slotted the field is multiline
        this._inputElements = assignedElements.filter(el => el.matches(TEXT_FIELD_CONSTANTS.selectors.INPUT));
        this._fieldElement.multiline = this._inputElements.some(el => el.tagName === TEXT_FIELD_CONSTANTS.tagNames.TEXTAREA);
        // Create a new mutation observer and observe each input
        this._inputMutationObserver = new MutationObserver(mutations => {
            mutations.forEach(mutation => {
                if (mutation.attributeName) {
                    const element = mutation.target;
                    const attribute = element.getAttribute(mutation.attributeName);
                    const attributeName = mutation.attributeName;
                    listener(attributeName, attribute);
                }
            });
        });
        this._inputElements.forEach(el => {
            var _a;
            (_a = this._inputMutationObserver) === null || _a === void 0 ? void 0 : _a.observe(el, { attributes: true, attributeFilter: [...TEXT_FIELD_CONSTANTS.observedInputAttributes] });
            if (this._component.disabled) {
                el.disabled = true;
            }
            // Call the listener with each observed attribute to capture the initial state
            Object.values(TEXT_FIELD_CONSTANTS.observedInputAttributes).forEach(value => {
                const attributeName = value;
                listener(attributeName, el.getAttribute(attributeName));
            });
        });
    }
    tryAddValueChangeListener(context, listener) {
        // Destroy the previous value change listeners
        this._destroyValueChangerListeners.forEach(callback => callback());
        // Add a new value change listener to each input
        this._destroyValueChangerListeners = this._inputElements.map(el => {
            return listenOwnProperty(context, el, 'value', listener);
        });
    }
    removeValueChangeListener() {
        this._destroyValueChangerListeners.forEach(callback => callback());
    }
    tryFloatLabel(force) {
        // Force the label to float if specified
        if (force !== undefined) {
            this._fieldElement.floatLabel = force;
            return;
        }
        // Float the label if no input has a value or a placeholder
        this._fieldElement.floatLabel = this.hasValue || this.hasPlaceholder;
    }
    tryConnectSlottedLabel(slot) {
        var _a;
        // Only one input can be automatically connected to a label, return if there are no or more
        // than one inputs or if the input is already labelled
        if (this._inputElements.length !== 1 || ((_a = this._inputElements[0].labels) === null || _a === void 0 ? void 0 : _a.length)) {
            return;
        }
        const inputElement = this._inputElements[0];
        const elements = slot.assignedElements({ flatten: true });
        // Attempt to find and connect a `<forge-label>` element
        const forgeLabel = elements.find(el => el.matches(TEXT_FIELD_CONSTANTS.selectors.FORGE_LABEL));
        if (forgeLabel) {
            forgeLabel.forElement = this._component;
            forgeLabel.clickTarget = inputElement;
            return;
        }
        // Attempt to find and connect a `<label>` element
        const label = elements.find(el => el.tagName === TEXT_FIELD_CONSTANTS.tagNames.LABEL);
        if (!label || label.control) {
            return;
        }
        const id = inputElement.id || `forge-input-${randomChars()}`;
        inputElement.id = id;
        label.htmlFor = id;
    }
    connectClearButton(listener) {
        this._clearButtonSlotElement.addEventListener('click', listener);
    }
    disconnectClearButton(listener) {
        this._clearButtonSlotElement.removeEventListener('click', listener);
    }
    toggleClearButtonVisibility(visible) {
        if (visible) {
            this._fieldElement.append(this._clearButtonSlotElement);
        }
        else {
            this._clearButtonSlotElement.remove();
        }
    }
    clearInput() {
        if (!this._inputElements.length) {
            return;
        }
        this._inputElements.forEach(el => el.value = '');
        this._inputElements[0].focus();
    }
}
