import { ElementIDUtils } from '@sankhyalabs/core';
import { h, Host } from '@stencil/core';
export class EzTextArea {
  constructor() {
    this.LINE_HEIGHT = 24;
    this.HEIGHT_RATIO = 1.4;
    this.label = undefined;
    this.value = undefined;
    this.enabled = true;
    this.errorMessage = undefined;
    this.rows = 4;
    this.canShowError = true;
    this.mode = 'regular';
    this.enableResize = true;
    this.autoRows = false;
    this.autoFocus = false;
    this.alternativePlaceholder = undefined;
    this.forceLabelFloat = false;
  }
  observeErrorMessage() {
    var _a, _b, _c, _d;
    const hasError = typeof this.errorMessage === 'string' && this.errorMessage !== '';
    if (hasError) {
      (_a = this._container) === null || _a === void 0 ? void 0 : _a.classList.add('hasError');
      (_b = this._messageBoxElem) === null || _b === void 0 ? void 0 : _b.classList.add('hasError');
    }
    else {
      (_c = this._container) === null || _c === void 0 ? void 0 : _c.classList.remove('hasError');
      (_d = this._messageBoxElem) === null || _d === void 0 ? void 0 : _d.classList.remove('hasError');
    }
  }
  observeValue(newValue, oldValue) {
    if (this._inputElem) {
      if (newValue != oldValue) {
        if (this.canChangeValue()) {
          this._inputElem.value = this.value || '';
        }
        this.adjustFloatingLabel();
        this.errorMessage = '';
        this.ezChange.emit(this.value);
      }
    }
  }
  observeMode() {
    if (this._initialRows == undefined) {
      this._initialRows = this.rows > 0 ? this.rows : undefined;
    }
    const rows = this._initialRows > 0 ? this._initialRows : this.mode != 'slim' ? 4 : 2;
    if (rows !== this.rows) {
      this.rows = rows;
    }
  }
  observeRows() {
    const rows = this.rows > 0 ? this.rows : this.mode != 'slim' ? 4 : 2;
    if (rows !== this.rows) {
      this.updateRows(rows);
    }
  }
  observeAutoRows() {
    var _a, _b;
    if (this.autoRows) {
      (_a = this._resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
      this.initializeResizeObserver();
    }
    else {
      (_b = this._resizeObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
    }
  }
  observeAlternativePlaceholder(newValue) {
    this.forceLabelFloat = !!newValue;
  }
  //---------------------------------------------
  // Public methods
  //---------------------------------------------
  /**
   * Adiciona o argumento text no value do text area, seguindo as regras:
   * - Se o cursor do mouse está posicionado em algum local do texto, o argumento será adicionado nesse local.
   * - Se existir uma seleção no texto, o trecho selecionado deve ser substituído pelo argumento.
   * - Se não existir seleção nem posicionamento do cursor do mouse, o argumento será adicionado no final do texto.
   *
   * @param text: texto que irá ser adicionado
   */
  async appendTextToSelection(text) {
    var _a, _b, _c, _d;
    const selectionStart = this._inputElem.selectionStart;
    const selectionEnd = this._inputElem.selectionEnd;
    const textStart = (_b = (_a = this.value) === null || _a === void 0 ? void 0 : _a.substring(0, selectionStart)) !== null && _b !== void 0 ? _b : '';
    const textEnd = (_d = (_c = this.value) === null || _c === void 0 ? void 0 : _c.substring(selectionEnd)) !== null && _d !== void 0 ? _d : '';
    this.value = `${textStart}${text}${textEnd}`;
    const newSelectionEnd = selectionStart + text.length;
    const start = (selectionStart === selectionEnd) ? newSelectionEnd : selectionStart;
    this._inputElem.setSelectionRange(start, newSelectionEnd);
    await this.setFocus();
  }
  /**
   * Aplica o foco no campo.
   */
  async setFocus() {
    this._inputElem.focus();
  }
  /**
   * Remove o foco do campo.
   */
  async setBlur() {
    this._inputElem.blur();
  }
  /**
   * Retorna se o conteúdo é inválido.
   */
  async isInvalid() {
    return typeof this.errorMessage === 'string' && this.errorMessage.trim() !== '';
  }
  //---------------------------------------------
  // Private methods
  //---------------------------------------------
  canChangeValue() {
    return this._inputElem && (this.value || '') !== this._inputElem.value;
  }
  adjustFloatingLabel() {
    if (this.forceLabelFloat)
      return;
    if (this.label && this._labelElem) {
      const hasValue = this.value && this.value.toString().length > 0;
      const containsFloatedClass = this._labelElem.classList.contains('textarea__label--floated');
      if (hasValue || this.isFocused()) {
        if (!containsFloatedClass) {
          this._labelElem.classList.add('textarea__label--floated');
        }
      }
      else {
        if (containsFloatedClass) {
          this._labelElem.classList.remove('textarea__label--floated');
        }
      }
    }
  }
  isFocused() {
    return this._hostElement.shadowRoot.activeElement !== null;
  }
  updateRows(newRows) {
    this.rows = newRows;
    this._initialRows = newRows;
  }
  calculateMaxRows() {
    const parentElement = this._hostElement.parentElement;
    if (!parentElement) {
      return;
    }
    const height = Math.max((parentElement === null || parentElement === void 0 ? void 0 : parentElement.clientHeight) || 0, this.LINE_HEIGHT);
    if (height > 0) {
      const maxRows = Math.floor(height / this.LINE_HEIGHT * this.HEIGHT_RATIO);
      if (maxRows !== this.rows) {
        this.updateRows(maxRows);
      }
    }
  }
  initializeResizeObserver() {
    if (!this.autoRows) {
      return;
    }
    const parentElement = this._hostElement.parentElement;
    if (parentElement) {
      try {
        if (this._resizeObserver != undefined) {
          this._resizeObserver.unobserve(parentElement);
        }
        this._resizeObserver = new ResizeObserver(this.calculateMaxRows.bind(this));
        this._resizeObserver.observe(parentElement);
      }
      catch (e) {
        console.warn(e);
      }
      this.calculateMaxRows();
    }
  }
  //---------------------------------------------
  // Event handlers
  //---------------------------------------------
  handleFocusout() {
    this.adjustFloatingLabel();
    if (this._container && this._container.classList.contains('textarea--focus')) {
      this._container.classList.remove('textarea--focus');
    }
  }
  handleChange() {
    if (this.canChangeValue()) {
      this.value = this._inputElem.value;
    }
  }
  handleFocus() {
    if (this.label && this._labelElem && !this._labelElem.classList.contains('textarea__label--floated')) {
      this._labelElem.classList.add('textarea__label--floated');
    }
    if (this._container && !this._container.classList.contains('textarea--focus')) {
      this._container.classList.add('textarea--focus');
    }
  }
  connectedCallback() {
    this.initializeResizeObserver();
  }
  disconnectedCallback() {
    var _a;
    (_a = this._resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
  }
  buildPlaceholder() {
    if (this.alternativePlaceholder)
      return this.alternativePlaceholder;
    return (this.mode === 'slim' && this.label) ? this.label : '';
  }
  buildLabelClass() {
    let classList = this.enabled ? 'textarea__label' : 'textarea__label textarea__label--disabled';
    if (this.errorMessage)
      classList = classList + ' hasError';
    if (this.forceLabelFloat)
      classList = classList + ' textarea__label--floated';
    return classList;
  }
  renderErrorTooltip() {
    if (!this.canShowError || this.mode == 'slim' || !this.errorMessage)
      return;
    return (h("div", { class: "tooltip-container" }, h("ez-tooltip", { type: "error", message: this.errorMessage }, h("ez-icon", { class: `tooltip-icon ${this.errorMessage ? 'hasError' : ''}`, "data-element-id": ElementIDUtils.getInternalIDInfo('tooltip-icon'), iconName: "alert-circle" }))));
  }
  renderLabel() {
    if (!this.label || this.mode == 'slim')
      return null;
    return h("label", { ref: (el) => this._labelElem = el, class: this.buildLabelClass(), onClick: () => this._inputElem.focus(), title: this.label }, this.label);
  }
  renderTextArea() {
    return h("textarea", { onFocus: () => this.handleFocus(), "data-element-id": ElementIDUtils.getInternalIDInfo('input'), ref: (el) => this._inputElem = el, value: this.value, disabled: !this.enabled, class: { 'textarea--slim': this.mode === 'slim' }, placeholder: this.buildPlaceholder(), onInput: () => this.handleChange(), onFocusout: () => this.handleFocusout(), rows: this.rows });
  }
  //---------------------------------------------
  // Lifecycle web component
  //---------------------------------------------
  componentDidLoad() {
    this.observeErrorMessage();
    this.adjustFloatingLabel();
    this.observeMode();
    if (this.autoFocus) {
      requestAnimationFrame(() => {
        this.setFocus();
      });
    }
  }
  render() {
    ElementIDUtils.addIDInfoIfNotExists(this._hostElement, 'input');
    return (h(Host, null, h("div", { class: `textarea ${this.enabled ? '' : 'textarea--disabled'}`, ref: (el) => this._container = el }, this.renderLabel(), h("div", { class: `input-container ${this.enableResize ? 'textarea--resizable' : ""}` }, this.renderTextArea(), this.renderErrorTooltip()))));
  }
  static get is() { return "ez-text-area"; }
  static get encapsulation() { return "shadow"; }
  static get originalStyleUrls() {
    return {
      "$": ["ez-text-area.css"]
    };
  }
  static get styleUrls() {
    return {
      "$": ["ez-text-area.css"]
    };
  }
  static get properties() {
    return {
      "label": {
        "type": "string",
        "mutable": false,
        "complexType": {
          "original": "string",
          "resolved": "string",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Texto a ser apresentado como t\u00EDtulo do campo."
        },
        "attribute": "label",
        "reflect": true
      },
      "value": {
        "type": "string",
        "mutable": true,
        "complexType": {
          "original": "string",
          "resolved": "string",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Define o valor do campo."
        },
        "attribute": "value",
        "reflect": true
      },
      "enabled": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Se false o usu\u00E1rio n\u00E3o pode interagir com o campo."
        },
        "attribute": "enabled",
        "reflect": true,
        "defaultValue": "true"
      },
      "errorMessage": {
        "type": "string",
        "mutable": true,
        "complexType": {
          "original": "string",
          "resolved": "string",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Define uma mensagem de orienta\u00E7\u00E3o ao usu\u00E1rio, colocando o campo em modo inv\u00E1lido."
        },
        "attribute": "error-message",
        "reflect": true
      },
      "rows": {
        "type": "number",
        "mutable": true,
        "complexType": {
          "original": "number",
          "resolved": "number",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Define o n\u00FAmero de linhas."
        },
        "attribute": "rows",
        "reflect": true,
        "defaultValue": "4"
      },
      "canShowError": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Se false deixa de exibir a mensagem de erro dentro do campo."
        },
        "attribute": "can-show-error",
        "reflect": true,
        "defaultValue": "true"
      },
      "mode": {
        "type": "string",
        "mutable": false,
        "complexType": {
          "original": "'slim' | 'regular'",
          "resolved": "\"regular\" | \"slim\"",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Define o tamanho do campo."
        },
        "attribute": "mode",
        "reflect": true,
        "defaultValue": "'regular'"
      },
      "enableResize": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Ativa a op\u00E7\u00E3o de fazer resize do input."
        },
        "attribute": "enable-resize",
        "reflect": true,
        "defaultValue": "true"
      },
      "autoRows": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Ativa a op\u00E7\u00E3o de fazer as linhas do componente serem baseados na altura m\u00E1xima."
        },
        "attribute": "auto-rows",
        "reflect": true,
        "defaultValue": "false"
      },
      "autoFocus": {
        "type": "boolean",
        "mutable": false,
        "complexType": {
          "original": "boolean",
          "resolved": "boolean",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Se true o campo de texto receber\u00E1 o foco ao ser renderizado."
        },
        "attribute": "auto-focus",
        "reflect": false,
        "defaultValue": "false"
      },
      "alternativePlaceholder": {
        "type": "string",
        "mutable": false,
        "complexType": {
          "original": "string",
          "resolved": "string",
          "references": {}
        },
        "required": false,
        "optional": false,
        "docs": {
          "tags": [],
          "text": "Texto alternativo a ser apresentado como t\u00EDtulo do campo."
        },
        "attribute": "alternative-placeholder",
        "reflect": true
      }
    };
  }
  static get states() {
    return {
      "forceLabelFloat": {}
    };
  }
  static get events() {
    return [{
        "method": "ezChange",
        "name": "ezChange",
        "bubbles": true,
        "cancelable": true,
        "composed": true,
        "docs": {
          "tags": [],
          "text": "Emitido quando acontece a altera\u00E7\u00E3o de valor do campo."
        },
        "complexType": {
          "original": "string",
          "resolved": "string",
          "references": {}
        }
      }];
  }
  static get methods() {
    return {
      "appendTextToSelection": {
        "complexType": {
          "signature": "(text: string) => Promise<void>",
          "parameters": [{
              "tags": [{
                  "name": "param",
                  "text": "text : texto que ir\u00E1 ser adicionado"
                }],
              "text": ": texto que ir\u00E1 ser adicionado"
            }],
          "references": {
            "Promise": {
              "location": "global"
            }
          },
          "return": "Promise<void>"
        },
        "docs": {
          "text": "Adiciona o argumento text no value do text area, seguindo as regras:\n- Se o cursor do mouse est\u00E1 posicionado em algum local do texto, o argumento ser\u00E1 adicionado nesse local.\n- Se existir uma sele\u00E7\u00E3o no texto, o trecho selecionado deve ser substitu\u00EDdo pelo argumento.\n- Se n\u00E3o existir sele\u00E7\u00E3o nem posicionamento do cursor do mouse, o argumento ser\u00E1 adicionado no final do texto.",
          "tags": [{
              "name": "param",
              "text": "text : texto que ir\u00E1 ser adicionado"
            }]
        }
      },
      "setFocus": {
        "complexType": {
          "signature": "() => Promise<void>",
          "parameters": [],
          "references": {
            "Promise": {
              "location": "global"
            }
          },
          "return": "Promise<void>"
        },
        "docs": {
          "text": "Aplica o foco no campo.",
          "tags": []
        }
      },
      "setBlur": {
        "complexType": {
          "signature": "() => Promise<void>",
          "parameters": [],
          "references": {
            "Promise": {
              "location": "global"
            }
          },
          "return": "Promise<void>"
        },
        "docs": {
          "text": "Remove o foco do campo.",
          "tags": []
        }
      },
      "isInvalid": {
        "complexType": {
          "signature": "() => Promise<boolean>",
          "parameters": [],
          "references": {
            "Promise": {
              "location": "global"
            }
          },
          "return": "Promise<boolean>"
        },
        "docs": {
          "text": "Retorna se o conte\u00FAdo \u00E9 inv\u00E1lido.",
          "tags": []
        }
      }
    };
  }
  static get elementRef() { return "_hostElement"; }
  static get watchers() {
    return [{
        "propName": "errorMessage",
        "methodName": "observeErrorMessage"
      }, {
        "propName": "value",
        "methodName": "observeValue"
      }, {
        "propName": "mode",
        "methodName": "observeMode"
      }, {
        "propName": "rows",
        "methodName": "observeRows"
      }, {
        "propName": "autoRows",
        "methodName": "observeAutoRows"
      }, {
        "propName": "alternativePlaceholder",
        "methodName": "observeAlternativePlaceholder"
      }];
  }
}
