import { Host, h } from "@stencil/core";
import { assignDescription, isRequired, isSpecTest, messageId, exposeTypeProperty } from "../../utils/form";
import { debounceEvent } from "../../utils/utils";
import { inheritAttributes, inheritAriaAttributes } from "../../utils/attributes";
import { danger } from "@pine-ds/icons/icons";
/**
 * @slot action - Content to be displayed in the label area, typically for help icons or links
 */
export class PdsTextarea {
    constructor() {
        this.inheritedAttributes = {};
        this._type = 'textarea';
        /**
         * Determines whether or not the textarea is disabled.
         * @defaultValue false
         */
        this.disabled = false;
        /**
         * Determines whether or not the textarea is invalid or throws an error.
         * @defaultValue false
         */
        this.invalid = false; // eslint-disable-line @stencil-community/strict-mutable
        /**
         * Specifies the name. Submitted with the form name/value pair. This value will mirror the componentId.
         */
        this.name = this.componentId;
        /**
         * Determines whether or not the textarea is readonly.
         * @defaultValue false
         */
        this.readonly = false;
        /**
         * Determines whether or not the textarea is required.
         * @defaultValue false
         */
        this.required = false;
        /**
         * The value of the textarea.
         */
        this.value = '';
        this.hasFocus = false;
        /**
         * If true, the textarea has action content in the label area
         */
        this.hasAction = false;
        this.onBlur = (ev) => {
            this.hasFocus = false;
            if (this.focusedValue !== this.value) {
                this.emitValueChange(ev);
            }
            this.pdsBlur.emit(ev);
        };
        this.onFocus = (ev) => {
            this.hasFocus = true;
            this.focusedValue = this.value;
            this.pdsFocus.emit(ev);
        };
        this.onInput = (ev) => {
            const input = ev.target;
            if (input) {
                // Handle maxLength validation
                if (this.maxLength && input.value.length > this.maxLength) {
                    // Prevent input beyond maxLength
                    input.value = input.value.substring(0, this.maxLength);
                }
                this.value = input.value || '';
            }
            this.emitInputChange(ev);
            // Update counter position when content changes
            if (this.maxLength && typeof ResizeObserver !== 'undefined') {
                // Use requestAnimationFrame to ensure DOM is updated
                requestAnimationFrame(() => {
                    this.updateCharacterCounterPosition();
                });
            }
        };
        this.onTextareaChange = (ev) => {
            this.emitValueChange(ev);
        };
        this.onKeyDown = (ev) => {
            this.pdsKeyDown.emit(ev);
        };
    }
    /**
     * Sets focus on the native `textarea` in the `pds-textarea`. Use this method instead of the global
     * `textarea.focus()`.
     */
    async setFocus() {
        if (this.nativeTextarea) {
            this.nativeTextarea.focus();
        }
    }
    debounceChanged() {
        const { pdsInput, debounce, originalPdsInput } = this;
        this.pdsInput = debounce === undefined ? originalPdsInput !== null && originalPdsInput !== void 0 ? originalPdsInput : pdsInput : debounceEvent(pdsInput, debounce);
    }
    /**
     * Update the native input element when the value changes
     */
    valueChanged() {
        const nativeTextarea = this.nativeTextarea;
        const value = this.getValue();
        if (nativeTextarea && nativeTextarea.value !== value) {
            nativeTextarea.value = value;
        }
        // Update form value for Form Associated Custom Elements API
        this.updateFormValue();
        // Update character counter position in case content changes affect sizing
        if (this.maxLength && typeof ResizeObserver !== 'undefined') {
            this.updateCharacterCounterPosition();
        }
    }
    maxLengthChanged() {
        // Setup or teardown ResizeObserver based on maxLength
        if (this.resizeObserver) {
            this.resizeObserver.disconnect();
        }
        if (this.maxLength && this.nativeTextarea) {
            this.setupResizeObserver();
        }
        // Update ElementInternals validity when maxLength changes
        if (!isSpecTest() && this.internals && this.internals.setValidity && this.nativeTextarea) {
            const isTooLong = this.nativeTextarea.value.length > (this.maxLength || 0);
            this.internals.setValidity({ tooLong: isTooLong }, isTooLong ? 'Value exceeds maxLength' : '', this.nativeTextarea);
        }
    }
    /**
     * Emits an `pdsInput` event.
     */
    emitInputChange(event) {
        const { value } = this;
        this.pdsInput.emit({ value, event });
    }
    /**
     * Emits an `pdsTextareaChange` event.
     */
    emitValueChange(event) {
        const textarea = event.target;
        isRequired(textarea, this);
        const { value } = textarea;
        // Checks for both null and undefined values
        const newValue = value == null ? value : value.toString();
        this.focusedValue = newValue;
        this.pdsTextareaChange.emit({ value: newValue, event });
    }
    getValue() {
        return this.value || '';
    }
    textareaClassNames() {
        const classNames = ['pds-textarea__field'];
        if (this.invalid && this.invalid === true) {
            classNames.push('is-invalid');
        }
        return classNames.join('  ');
    }
    connectedCallback() {
        this.debounceChanged();
        // Initialize ElementInternals for form association (only once per element instance)
        if (this.el.attachInternals && !this.internals) {
            this.internals = this.el.attachInternals();
        }
    }
    disconnectedCallback() {
        // Clean up ResizeObserver
        if (this.resizeObserver) {
            this.resizeObserver.disconnect();
        }
    }
    componentWillLoad() {
        this.inheritedAttributes = Object.assign(Object.assign({}, inheritAriaAttributes(this.el)), inheritAttributes(this.el));
        this.hasAction = this.el.querySelector('[slot="action"]') !== null;
    }
    componentDidLoad() {
        this.originalPdsInput = this.pdsInput;
        // Set initial form value
        this.updateFormValue();
        // Setup ResizeObserver for character counter positioning
        this.setupResizeObserver();
        // Expose type property on the element instance to match native form element behavior
        exposeTypeProperty(this.el, () => this._type);
    }
    /**
     * Sets up ResizeObserver to track textarea resize for character counter positioning
     */
    setupResizeObserver() {
        if (!this.maxLength || !this.nativeTextarea)
            return;
        // ResizeObserver may not be available in test environments
        if (typeof ResizeObserver !== 'undefined') {
            this.resizeObserver = new ResizeObserver(() => {
                // Use requestAnimationFrame to ensure DOM updates are complete
                requestAnimationFrame(() => {
                    this.updateCharacterCounterPosition();
                });
            });
            this.resizeObserver.observe(this.nativeTextarea);
            // Initial positioning with a small delay to ensure counter is rendered
            requestAnimationFrame(() => {
                this.updateCharacterCounterPosition();
            });
        }
    }
    /**
     * Updates character counter position to stay within textarea boundaries during resize
     */
    updateCharacterCounterPosition() {
        if (!this.characterCounter || !this.nativeTextarea)
            return;
        // Skip positioning in test environments where ResizeObserver isn't available
        if (typeof ResizeObserver === 'undefined')
            return;
        // Ensure the character counter has been rendered and has dimensions
        if (this.characterCounter.offsetWidth === 0 || this.characterCounter.offsetHeight === 0) {
            // Counter not ready or component hidden - return and let resize/input observers handle positioning later
            return;
        }
        // Position based on textarea's actual dimensions (which change during manual resize)
        const textareaWidth = this.nativeTextarea.offsetWidth;
        const textareaHeight = this.nativeTextarea.offsetHeight;
        const counterWidth = this.characterCounter.offsetWidth;
        const counterHeight = this.characterCounter.offsetHeight;
        // Calculate position within textarea boundaries with padding from edges
        const rightPosition = textareaWidth - counterWidth - 8;
        const bottomPosition = textareaHeight - counterHeight - 8;
        // Ensure counter stays within textarea boundaries even when resized very small
        const finalLeft = Math.max(8, Math.min(rightPosition, textareaWidth - counterWidth - 8));
        const finalTop = Math.max(8, Math.min(bottomPosition, textareaHeight - counterHeight - 8));
        // Apply absolute positioning within the field wrapper
        this.characterCounter.style.position = 'absolute';
        this.characterCounter.style.left = `${finalLeft}px`;
        this.characterCounter.style.top = `${finalTop}px`;
        this.characterCounter.style.right = 'auto';
        this.characterCounter.style.bottom = 'auto';
    }
    /**
     * Renders the character counter when maxLength is set
     */
    renderCharacterCounter() {
        if (!this.maxLength) {
            return null;
        }
        const currentLength = this.getValue().length;
        return (h("div", { class: "pds-textarea__character-counter", ref: (el) => this.characterCounter = el, role: "status", "aria-live": "polite", "aria-label": `${currentLength} of ${this.maxLength} characters` }, currentLength, " / ", this.maxLength));
    }
    renderAction() {
        const hasAction = this.el.querySelector('[slot="action"]') !== null;
        if (hasAction) {
            return (h("div", { class: "pds-textarea__action", part: "action" }, h("slot", { name: "action" })));
        }
        return null;
    }
    /**
     * Updates the form value using ElementInternals API
     */
    updateFormValue() {
        if (isSpecTest())
            return;
        if (this.internals && this.internals.setFormValue) {
            const value = this.getValue();
            this.internals.setFormValue(value || null);
            // Set validity based on native textarea validation
            if (this.nativeTextarea && this.internals && this.internals.setValidity) {
                this.internals.setValidity(this.nativeTextarea.validity, this.nativeTextarea.validationMessage, this.nativeTextarea);
            }
        }
    }
    /**
     * Form Associated Custom Elements API: Called when the form is reset
     */
    formResetCallback() {
        this.value = '';
        this.updateFormValue();
    }
    /**
     * Form Associated Custom Elements API: Called when the form is disabled
     */
    formDisabledCallback(disabled) {
        this.disabled = disabled;
    }
    /**
     * Form Associated Custom Elements API: Called to restore form state
     */
    formStateRestoreCallback(state) {
        if (typeof state === 'string') {
            this.value = state;
        }
        else if (state instanceof FormData && this.name) {
            // Extract value from FormData using the textarea's name
            const value = state.get(this.name);
            if (typeof value === 'string') {
                this.value = value;
            }
        }
    }
    render() {
        const value = this.getValue();
        return (h(Host, { key: '09726ef6454fe84a5c8d0ea25c6e8a7a6da128f9', "aria-disabled": this.disabled ? 'true' : null, "aria-readonly": this.readonly ? 'true' : null, "has-action": this.hasAction && !this.hideLabel ? 'true' : null }, h("div", { key: '6244104f11d26b25a908fbaf13a815988a3c33d9', class: "pds-textarea" }, this.label &&
            h("div", { key: '5dd7f6caedd7ebf5ecaacf8d111ec5e2426e84ae', class: "pds-textarea__label-wrapper" }, h("label", { key: 'd19f62cd28612423abf0d5696ff1cd88f39d32fe', htmlFor: this.componentId }, h("span", { key: '37f4e9e34ae3205bafa5f1bc8574a98d3a90060d', class: this.hideLabel ? 'visually-hidden' : '' }, this.label)), !this.hideLabel && this.renderAction()), h("div", { key: '4c3c8fadc5596630485ee1775f5d87d77c11d95b', class: "pds-textarea__field-wrapper" }, h("textarea", Object.assign({ key: 'a60be5f3d362cb9bcd2ecf5af16ffc467fc8322a', ref: (el) => this.nativeTextarea = el, "aria-describedby": assignDescription(this.componentId, this.invalid, this.helperMessage), "aria-invalid": this.invalid ? "true" : undefined, autocomplete: this.autocomplete, class: this.textareaClassNames(), disabled: this.disabled, id: this.componentId, maxlength: this.maxLength, name: this.name, placeholder: this.placeholder, readOnly: this.readonly, required: this.required, rows: this.rows, onBlur: this.onBlur, onChange: this.onTextareaChange, onFocus: this.onFocus, onInput: this.onInput, onKeyDown: this.onKeyDown }, this.inheritedAttributes), value), this.renderCharacterCounter()), this.helperMessage &&
            h("p", { key: 'ae03337ef85ac2a3995e967fe671e0ad2c352710', class: "pds-textarea__helper-message", id: messageId(this.componentId, 'helper') }, this.helperMessage), this.invalid &&
            h("p", { key: 'a2bda9a477e7d2b81862833da43158a626d8cc6f', "aria-live": "assertive", class: "pds-textarea__error-message", id: messageId(this.componentId, 'error') }, h("pds-icon", { key: '5ac785e8012aeb49dd0b1c5823233671531b0a7a', icon: danger, size: "small" }), this.errorMessage))));
    }
    static get is() { return "pds-textarea"; }
    static get encapsulation() { return "shadow"; }
    static get formAssociated() { return true; }
    static get originalStyleUrls() {
        return {
            "$": ["../../global/styles/utils/label.scss", "../pds-input/pds-input.tokens.scss", "pds-textarea.scss"]
        };
    }
    static get styleUrls() {
        return {
            "$": ["../../global/styles/utils/label.css", "../pds-input/pds-input.tokens.css", "pds-textarea.css"]
        };
    }
    static get properties() {
        return {
            "autocomplete": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Specifies if and how the browser provides `autocomplete` assistance for the field."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "autocomplete"
            },
            "componentId": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": true,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "A unique identifier used for the underlying component `id` attribute."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "component-id"
            },
            "disabled": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "defaultValue",
                            "text": "false"
                        }],
                    "text": "Determines whether or not the textarea is disabled."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "disabled",
                "defaultValue": "false"
            },
            "debounce": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The amount of time, in milliseconds, to wait to trigger the event after each keystroke."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "debounce"
            },
            "errorMessage": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Displays an error message below the textarea field."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "error-message"
            },
            "helperMessage": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Displays a message or hint below the textarea field."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "helper-message"
            },
            "invalid": {
                "type": "boolean",
                "mutable": true,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "defaultValue",
                            "text": "false"
                        }],
                    "text": "Determines whether or not the textarea is invalid or throws an error."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "invalid",
                "defaultValue": "false"
            },
            "label": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Text to be displayed as the textarea label."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "label"
            },
            "hideLabel": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Visually hides the label text for instances where only the textarea should be displayed. Label remains accessible to assistive technology such as screen readers.\nNote: When true, the action slot is also hidden to maintain a minimal UI."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "hide-label"
            },
            "name": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [],
                    "text": "Specifies the name. Submitted with the form name/value pair. This value will mirror the componentId."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "name",
                "defaultValue": "this.componentId"
            },
            "placeholder": {
                "type": "string",
                "mutable": false,
                "complexType": {
                    "original": "string",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Specifies a short hint that describes the expected value of the textarea."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "placeholder"
            },
            "readonly": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "defaultValue",
                            "text": "false"
                        }],
                    "text": "Determines whether or not the textarea is readonly."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "readonly",
                "defaultValue": "false"
            },
            "required": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": false,
                "docs": {
                    "tags": [{
                            "name": "defaultValue",
                            "text": "false"
                        }],
                    "text": "Determines whether or not the textarea is required."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "required",
                "defaultValue": "false"
            },
            "rows": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Sets number of rows of text visible without needing to scroll in the textarea."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "rows"
            },
            "maxLength": {
                "type": "number",
                "mutable": false,
                "complexType": {
                    "original": "number",
                    "resolved": "number",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Specifies the maximum number of characters allowed in the textarea. When set, displays a character counter."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "max-length"
            },
            "highlight": {
                "type": "boolean",
                "mutable": false,
                "complexType": {
                    "original": "boolean",
                    "resolved": "boolean",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "Applies highlight styling to the textarea field."
                },
                "getter": false,
                "setter": false,
                "reflect": true,
                "attribute": "highlight"
            },
            "value": {
                "type": "string",
                "mutable": true,
                "complexType": {
                    "original": "string | null",
                    "resolved": "string",
                    "references": {}
                },
                "required": false,
                "optional": true,
                "docs": {
                    "tags": [],
                    "text": "The value of the textarea."
                },
                "getter": false,
                "setter": false,
                "reflect": false,
                "attribute": "value",
                "defaultValue": "''"
            }
        };
    }
    static get states() {
        return {
            "hasFocus": {},
            "hasAction": {}
        };
    }
    static get events() {
        return [{
                "method": "pdsBlur",
                "name": "pdsBlur",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the input loses focus."
                },
                "complexType": {
                    "original": "FocusEvent",
                    "resolved": "FocusEvent",
                    "references": {
                        "FocusEvent": {
                            "location": "global",
                            "id": "global::FocusEvent"
                        }
                    }
                }
            }, {
                "method": "pdsFocus",
                "name": "pdsFocus",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when the input has focus."
                },
                "complexType": {
                    "original": "FocusEvent",
                    "resolved": "FocusEvent",
                    "references": {
                        "FocusEvent": {
                            "location": "global",
                            "id": "global::FocusEvent"
                        }
                    }
                }
            }, {
                "method": "pdsInput",
                "name": "pdsInput",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when a keyboard input occurs.\n\nFor elements that accept text input (`type=text`, `type=tel`, etc.), the interface\nis [`InputEvent`](https://developer.mozilla.org/en-US/docs/Web/API/InputEvent); for others,\nthe interface is [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Event). If\nthe input is cleared on edit, the type is `null`."
                },
                "complexType": {
                    "original": "TextareaInputEventDetail",
                    "resolved": "TextareaInputEventDetail",
                    "references": {
                        "TextareaInputEventDetail": {
                            "location": "import",
                            "path": "./textarea-interface",
                            "id": "src/components/pds-textarea/textarea-interface.ts::TextareaInputEventDetail"
                        }
                    }
                }
            }, {
                "method": "pdsTextareaChange",
                "name": "pdsTextareaChange",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Event emitted whenever the value of the textarea changes.\n\nThis event will not emit when programmatically setting the `value` property."
                },
                "complexType": {
                    "original": "TextareaChangeEventDetail",
                    "resolved": "TextareaChangeEventDetail",
                    "references": {
                        "TextareaChangeEventDetail": {
                            "location": "import",
                            "path": "./textarea-interface",
                            "id": "src/components/pds-textarea/textarea-interface.ts::TextareaChangeEventDetail"
                        }
                    }
                }
            }, {
                "method": "pdsKeyDown",
                "name": "pdsKeyDown",
                "bubbles": true,
                "cancelable": true,
                "composed": true,
                "docs": {
                    "tags": [],
                    "text": "Emitted when a key is pressed down in the textarea."
                },
                "complexType": {
                    "original": "KeyboardEvent",
                    "resolved": "KeyboardEvent",
                    "references": {
                        "KeyboardEvent": {
                            "location": "global",
                            "id": "global::KeyboardEvent"
                        }
                    }
                }
            }];
    }
    static get methods() {
        return {
            "setFocus": {
                "complexType": {
                    "signature": "() => Promise<void>",
                    "parameters": [],
                    "references": {
                        "Promise": {
                            "location": "global",
                            "id": "global::Promise"
                        }
                    },
                    "return": "Promise<void>"
                },
                "docs": {
                    "text": "Sets focus on the native `textarea` in the `pds-textarea`. Use this method instead of the global\n`textarea.focus()`.",
                    "tags": []
                }
            }
        };
    }
    static get elementRef() { return "el"; }
    static get watchers() {
        return [{
                "propName": "debounce",
                "methodName": "debounceChanged"
            }, {
                "propName": "value",
                "methodName": "valueChanged"
            }, {
                "propName": "maxLength",
                "methodName": "maxLengthChanged"
            }];
    }
}
//# sourceMappingURL=pds-textarea.js.map
