import { Component, Event, h, Prop, State, Watch, Method, } from '@stencil/core';
import { TextFieldTypes } from '../../types/InputType';
import uniqueId from '../../utils/uniqueId';
import stringCombiner from '../../utils/stringCombiner';
export class TeliaTextInput {
  constructor() {
    /** Type of input as a string */
    this.type = TextFieldTypes.text;
    /** Value of input */
    this.value = '';
    /** Additional description id */
    this.additionalId = uniqueId('additional');
    /** Input element id */
    this.inputId = uniqueId('input');
    /** Error description id */
    this.errorId = uniqueId('error');
    /** Disabled state */
    this.disabled = false;
    /** Readonly state */
    this.readonly = false;
    /** Field needs to be filled, so it can be submitted  */
    this.required = false;
    /** Show valid icon when value passes all validations. Use sparingly. */
    this.showValidIcon = false;
    /** Tracking id is used to identify and count Component usage */
    this.dataTrackingId = 'telia-text-input';
    /**
     * Input has been blurred at least once.
     */
    this.touched = false;
    /**
     * Input has received data at least once.
     */
    this.dirty = false;
    /**
     * Real time value of input
     */
    this.inputValue = '';
    /**
     * Error message
     */
    this.errorMessageState = '';
    this.updateInputValue = () => {
      // eslint-disable-next-line @stencil/strict-boolean-conditions
      this.inputValue = this.inputElement ? this.inputElement.value : this.value;
    };
    /**
     * Check if input value state is valid with given pattern. This is
     * imitating native input validation.
     */
    this.isValuePatternValid = () => {
      if (this.pattern) {
        const regexp = new RegExp('^(?:' + this.pattern + ')$');
        return regexp.test(this.inputValue);
      }
      return true;
    };
    this.isValueLessThanMinlength = () => {
      return (this.inputValue.length > 0 && this.inputValue.length < this.minlength);
    };
    /**
     * Check if validation failed due to type mismatch.
     * Type mismatch is set to true when email, url, ... field type built-in validation triggers
     */
    this.isValueTypeInvalid = () => {
      var _a;
      return (_a = this.inputElement) === null || _a === void 0 ? void 0 : _a.validity.typeMismatch;
    };
    /**
     * Update error message and keep native input error message in sync.
     */
    this.updateErrorMessage = message => {
      var _a;
      (_a = this.inputElement) === null || _a === void 0 ? void 0 : _a.setCustomValidity(message);
      this.errorMessageState = message;
    };
    /**
     * Check if input value is empty, so required should be triggered.
     */
    this.isValueMissing = () => {
      return this.inputValue.length === 0;
    };
    this.updateErrorState = () => {
      var _a, _b;
      const errorMessageIsSet = !!((_a = this.errorMessageState) === null || _a === void 0 ? void 0 : _a.length);
      const requiredInUse = this.required;
      const patternInUse = !!this.pattern;
      const minlengthInUse = this.minlength;
      const generalErrorInUse = !!((_b = this.errorMessage) === null || _b === void 0 ? void 0 : _b.length);
      const emailErrorInUse = !!this.emailErrorMessage && this.type === 'email';
      if (generalErrorInUse) {
        this.updateErrorMessage(this.errorMessage);
        this.touched = true;
        // General error message overrides other errors, so exit here.
        return;
      }
      if (patternInUse && !this.isValueMissing()) {
        if (this.touched &&
          !!this.patternErrorMessage &&
          !this.isValuePatternValid()) {
          this.updateErrorMessage(this.patternErrorMessage);
        }
      }
      if (minlengthInUse) {
        if (this.touched &&
          !!this.minlengthErrorMessage &&
          this.isValueLessThanMinlength()) {
          this.updateErrorMessage(this.minlengthErrorMessage);
        }
      }
      if (requiredInUse) {
        /**
         * Follow HTML5 input ways of working,
         * email field is validated only if type is email and required is set to true
         */
        if (emailErrorInUse && this.isValueTypeInvalid() && this.touched) {
          this.updateErrorMessage(this.emailErrorMessage);
        }
        if (this.touched &&
          !!this.requiredErrorMessage &&
          this.isValueMissing()) {
          this.updateErrorMessage(this.requiredErrorMessage);
        }
      }
      // Clean error message if needed
      if (errorMessageIsSet) {
        if (patternInUse && !this.isValuePatternValid())
          return;
        if (minlengthInUse && this.isValueLessThanMinlength())
          return;
        if (requiredInUse && this.isValueMissing())
          return;
        if (emailErrorInUse && this.isValueTypeInvalid())
          return;
        this.updateErrorMessage('');
      }
    };
  }
  /**
   * Sets focus on input
   */
  async focusInput() {
    var _a;
    (_a = this.inputElement) === null || _a === void 0 ? void 0 : _a.focus();
  }
  componentWillLoad() {
    this.updateInputValue();
    this.updateErrorState();
  }
  componentWillUpdate() {
    this.updateErrorState();
  }
  componentDidRender() {
    // This check is for Stencil unit tests. Input element is mocked,
    // but setCustomValidity method is not. It is undefined.
    var _a, _b, _c;
    // eslint-disable-next-line @stencil/strict-boolean-conditions
    if (this.inputElement && ((_a = this.inputElement) === null || _a === void 0 ? void 0 : _a.setCustomValidity)) {
      (_b = this.inputElement) === null || _b === void 0 ? void 0 : _b.setCustomValidity(this.errorMessageState);
    }
    if (this.htmlForm) {
      (_c = this.inputElement) === null || _c === void 0 ? void 0 : _c.setAttribute('form', this.htmlForm);
    }
  }
  /**
   * Watch if value attributes changes after initial load.
   * Needed for prefilling functionality to work with input validations.
   * @param value value attribute
   */
  componentValueChanged(value) {
    this.inputValue = value;
    this.updateErrorState();
  }
  /**
   * This method is used to determine
   * if a 'valid icon' can be shown to the user.
   * Given the complexity of the validation logic
   * in this component, using this method
   * to determine 'validity' in a general sense
   * should be carefully considered and tested.
   */
  isValid() {
    return (!this.errorMessage &&
      !this.isValueMissing() &&
      !this.isValueLessThanMinlength() &&
      !this.isValueTypeInvalid() &&
      this.isValuePatternValid());
  }
  render() {
    const showError = this.touched && !!this.errorMessageState.length;
    const showAdditional = !!this.additional;
    const describedBy = stringCombiner({
      [this.additionalId]: showAdditional,
      [this.errorId]: this.errorMessageState.length,
    });
    const showValidIcon = this.showValidIcon && this.dirty && this.isValid();
    return (h("div", { class: "telia-text-input" },
      h("input", { class: {
          'telia-text-input__input': true,
          'telia-text-input__input--touched': this.touched,
          'telia-text-input__input--icon-shown': showValidIcon,
        }, placeholder: this.placeholder, type: this.type, id: this.inputId, "aria-describedby": describedBy, minlength: this.minlength, maxlength: this.maxlength, disabled: this.disabled, readonly: this.readonly, value: this.value, name: this.name, onChange: event => {
          /** valueChange is deprecated, will be removed in the future releases. */
          this.valueChange.emit(event);
        }, onInput: () => {
          this.dirty = true;
          this.updateInputValue();
          this.updateErrorState();
        }, inputmode: this.inputmode, list: this.list, autocomplete: this.autocomplete, required: this.required, onBlur: () => {
          this.touched = true;
          this.updateErrorState();
        }, ref: ref => (this.inputElement = ref), pattern: this.pattern, onInvalid: event => {
          event.preventDefault();
          this.touched = true;
          this.updateErrorState();
        }, form: this.htmlForm }),
      showValidIcon && (h("div", { class: "telia-text-input__valid-icon-container" },
        h("telia-field-valid", { class: "telia-text-input__valid-icon" }))),
      h("telia-label", { class: "telia-text-input__label", htmlFor: this.inputId },
        this.required && h("span", { "aria-hidden": "true" }, '* '),
        this.label),
      showAdditional && (h("telia-field-assistive-text", { class: "telia-text-input__additional", id: this.additionalId }, this.additional)),
      showError && (h("telia-field-error", { id: this.errorId, class: "telia-text-input__error" }, this.errorMessageState)),
      h("telia-vst", { dataTrackingId: this.dataTrackingId })));
  }
  static get is() { return "telia-text-input"; }
  static get originalStyleUrls() { return {
    "$": ["telia-text-input.scss"]
  }; }
  static get styleUrls() { return {
    "$": ["telia-text-input.css"]
  }; }
  static get properties() { return {
    "dataTestid": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Test id set for web component host"
      },
      "attribute": "data-testid",
      "reflect": false
    },
    "htmlForm": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "ID of the form this component belongs to. Should only be set If the component is not wrapped inside its form element."
      },
      "attribute": "html-form",
      "reflect": false
    },
    "type": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "TextFieldType",
        "resolved": "\"email\" | \"number\" | \"password\" | \"search\" | \"tel\" | \"text\"",
        "references": {
          "TextFieldType": {
            "location": "import",
            "path": "../../types/InputType"
          }
        }
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Type of input as a string"
      },
      "attribute": "type",
      "reflect": false,
      "defaultValue": "TextFieldTypes.text"
    },
    "label": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Label of input"
      },
      "attribute": "label",
      "reflect": false
    },
    "value": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Value of input"
      },
      "attribute": "value",
      "reflect": false,
      "defaultValue": "''"
    },
    "placeholder": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": "Placeholder text"
      },
      "attribute": "placeholder",
      "reflect": false
    },
    "name": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Name of the form control when submitted"
      },
      "attribute": "name",
      "reflect": false
    },
    "additional": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": "Additional description"
      },
      "attribute": "additional",
      "reflect": false
    },
    "additionalId": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Additional description id"
      },
      "attribute": "additional-id",
      "reflect": false,
      "defaultValue": "uniqueId('additional')"
    },
    "inputId": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Input element id"
      },
      "attribute": "input-id",
      "reflect": false,
      "defaultValue": "uniqueId('input')"
    },
    "errorId": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Error description id"
      },
      "attribute": "error-id",
      "reflect": false,
      "defaultValue": "uniqueId('error')"
    },
    "disabled": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Disabled state"
      },
      "attribute": "disabled",
      "reflect": false,
      "defaultValue": "false"
    },
    "minlength": {
      "type": "number",
      "mutable": false,
      "complexType": {
        "original": "number",
        "resolved": "number",
        "references": {}
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": "The minimum number of characters long the input can be and still be considered valid"
      },
      "attribute": "minlength",
      "reflect": false
    },
    "maxlength": {
      "type": "number",
      "mutable": false,
      "complexType": {
        "original": "number",
        "resolved": "number",
        "references": {}
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": "The maximum number of characters the input should accept"
      },
      "attribute": "maxlength",
      "reflect": false
    },
    "readonly": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Readonly state"
      },
      "attribute": "readonly",
      "reflect": false,
      "defaultValue": "false"
    },
    "inputmode": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "InputModeType",
        "resolved": "\"decimal\" | \"email\" | \"none\" | \"numeric\" | \"search\" | \"tel\" | \"text\" | \"url\"",
        "references": {
          "InputModeType": {
            "location": "import",
            "path": "../../types/InputMode"
          }
        }
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": "Input mode for defining specific virtual keyboard"
      },
      "attribute": "inputmode",
      "reflect": false
    },
    "list": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": "The id attribute of the datalist"
      },
      "attribute": "list",
      "reflect": false
    },
    "autocomplete": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "AutocompleteType",
        "resolved": "\"email\" | \"country\" | \"on\" | \"off\" | \"name\" | \"tel\" | \"url\" | \"honorific-prefix\" | \"given-name\" | \"additional-name\" | \"family-name\" | \"honorific-suffix\" | \"nickname\" | \"username\" | \"new-password\" | \"current-password\" | \"one-time-code\" | \"organization-title\" | \"organization\" | \"street-address\" | \"address-line1\" | \"address-line2\" | \"address-line3\" | \"address-level4\" | \"address-level3\" | \"address-level2\" | \"address-level1\" | \"country-name\" | \"postal-code\" | \"cc-name\" | \"cc-given-name\" | \"cc-additional-name\" | \"cc-family-name\" | \"cc-number\" | \"cc-exp\" | \"cc-exp-month\" | \"cc-exp-year\" | \"cc-type\" | \"transaction-currency\" | \"transaction-amount\" | \"language\" | \"bday\" | \"bday-day\" | \"bday-month\" | \"bday-year\" | \"sex\" | \"tel-country-code\" | \"tel-national\" | \"tel-area-code\" | \"tel-local\" | \"tel-extension\" | \"impp\" | \"photo\"",
        "references": {
          "AutocompleteType": {
            "location": "import",
            "path": "../../types/Autocomplete"
          }
        }
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": "Hint for form autofill feature"
      },
      "attribute": "autocomplete",
      "reflect": false
    },
    "required": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Field needs to be filled, so it can be submitted"
      },
      "attribute": "required",
      "reflect": false,
      "defaultValue": "false"
    },
    "requiredErrorMessage": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": "Error message for required"
      },
      "attribute": "required-error-message",
      "reflect": false
    },
    "emailErrorMessage": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": "Error message for email type input validation"
      },
      "attribute": "email-error-message",
      "reflect": false
    },
    "minlengthErrorMessage": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": "Error message for minlength"
      },
      "attribute": "minlength-error-message",
      "reflect": false
    },
    "showValidIcon": {
      "type": "boolean",
      "mutable": false,
      "complexType": {
        "original": "boolean",
        "resolved": "boolean",
        "references": {}
      },
      "required": false,
      "optional": false,
      "docs": {
        "tags": [],
        "text": "Show valid icon when value passes all validations. Use sparingly."
      },
      "attribute": "show-valid-icon",
      "reflect": false,
      "defaultValue": "false"
    },
    "pattern": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": "Valid text pattern"
      },
      "attribute": "pattern",
      "reflect": false
    },
    "patternErrorMessage": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": "Error message for pattern mismatch"
      },
      "attribute": "pattern-error-message",
      "reflect": false
    },
    "errorMessage": {
      "type": "string",
      "mutable": false,
      "complexType": {
        "original": "string",
        "resolved": "string",
        "references": {}
      },
      "required": false,
      "optional": true,
      "docs": {
        "tags": [],
        "text": "General error message, which overrides other error messages and is shown at initial render"
      },
      "attribute": "error-message",
      "reflect": false
    }
  }; }
  static get states() { return {
    "touched": {},
    "dirty": {},
    "inputValue": {},
    "errorMessageState": {}
  }; }
  static get events() { return [{
      "method": "valueChange",
      "name": "valueChange",
      "bubbles": true,
      "cancelable": true,
      "composed": true,
      "docs": {
        "tags": [],
        "text": "[DEPRECATED: 2022-02-18]: Use `input` event instead.\nCustom event for native input onChange event"
      },
      "complexType": {
        "original": "any",
        "resolved": "any",
        "references": {}
      }
    }]; }
  static get methods() { return {
    "focusInput": {
      "complexType": {
        "signature": "() => Promise<void>",
        "parameters": [],
        "references": {
          "Promise": {
            "location": "global"
          }
        },
        "return": "Promise<void>"
      },
      "docs": {
        "text": "Sets focus on input",
        "tags": []
      }
    }
  }; }
  static get watchers() { return [{
      "propName": "value",
      "methodName": "componentValueChanged"
    }]; }
}
