import {vlElement, define} from '/node_modules/vl-ui-core/dist/vl-core.js';
import {VlSelect} from '/node_modules/vl-ui-select/dist/vl-select.js';
import '/node_modules/vl-ui-icon/dist/vl-icon.js';
import '/node_modules/vl-ui-button/dist/vl-button.js';
import '/node_modules/vl-ui-input-field/dist/vl-input-field.js';

/**
 * Search change event analoog aan native change event.
 * @event VlSearch#change
 */

/**
 * VlSearch
 * @class
 * @classdesc Gebruik de vl-search component zodat een gebruiker zoekcriteria kan ingeven om specifieke content te vinden.
 *
 * @extends HTMLElement
 * @mixes vlElement
 *
 * @property {string} [data-vl-label='Zoekterm'] - Attribuut wordt gebruikt als label voor zoekcriteria.
 * @property {string} [data-vl-submit-label='Zoeken'] - Attribuut wordt gebruikt als label voor de submit knop.
 * @property {boolean} data-vl-block - Attribuut duidt aan dat een breed zoekveld met knop wordt getoond. Dit is de standaardweergave.
 * @property {boolean} data-vl-inline - Attribuut duidt aan dat een smal zoekveld met kleine knop wordt gebruikt.
 * @property {boolean} data-vl-alt - Attribuut bepaalt of de alternatieve weergave (witte achtergrond) wordt gebruikt. Alleen relevant in combinatie met data-vl-block.
 *
 * @example Breedte aanpassen:
 * <style>
    :root {
      --vl-search-width: 50%;
    }
   </style>
 *
 * @see {@link https://www.github.com/milieuinfo/webcomponent-vl-ui-search/releases/latest|Release notes}
 * @see {@link https://www.github.com/milieuinfo/webcomponent-vl-ui-search/issues|Issues}
 * @see {@link https://webcomponenten.omgeving.vlaanderen.be/demo/vl-search.html|Demo}
 */
export class VlSearch extends vlElement(HTMLElement) {
  static get _observedAttributes() {
    return ['label', 'submit-label'];
  }

  static get _observedChildClassAttributes() {
    return ['inline', 'block', 'alt'];
  }

  constructor() {
    super(`
      <style>
        @import '/src/style.css';
        @import '/node_modules/vl-ui-icon/dist/style.css';
        @import '/node_modules/vl-ui-button/dist/style.css';
        @import '/node_modules/vl-ui-input-field/dist/style.css';
      </style>
      <div class="vl-search">
        <slot name="input"></slot>
        <input is="vl-input-field" class="vl-search__input" type="search" id="search-input" value="" title="Zoekterm"/>
      </div>
    `);
  }

  connectedCallback() {
    if (!this._isInline && !this._isBlock) {
      this.setAttribute('data-vl-block', ''); // default to block if none set
    }
    this.__processInputSlot();
    this.__setupChangeEventTriggers();
  }

  disconnectedCallback() {
    if (this._observer) {
      this._observer.disconnect();
    }
  }

  /**
   * Geeft de zoekterm.
   *
   * @return {String}
   */
  get value() {
    return this.__inputElement.value;
  }

  get _isInline() {
    return this.hasAttribute('data-vl-inline');
  }

  get _isBlock() {
    return this.hasAttribute('data-vl-block');
  }

  get _classPrefix() {
    return 'vl-search--';
  }

  get __labelElement() {
    return this._element.querySelector('#search-label');
  }

  get __buttonElement() {
    return this._element.querySelector('#search-button');
  }

  get __inputElement() {
    return this._element.querySelector('#search-input');
  }

  get __inputSlotElement() {
    return this._element.querySelector('slot[name="input"]');
  }

  get __inputSlot() {
    return this.querySelector('[slot="input"]');
  }

  _inlineChangedCallback(oldValue, newValue) {
    this.toggleAttribute('data-vl-block', newValue == undefined);
    this.__render();
  }

  _blockChangedCallback(oldValue, newValue) {
    this.toggleAttribute('data-vl-inline', newValue == undefined);
    this.__render();
  }

  _labelChangedCallback() {
    this.__renderLabel();
  }

  _submitLabelChangedCallback() {
    this.__renderButton();
  }

  __setupChangeEventTriggers() {
    if (this.__inputElement) {
      this.__inputElement.addEventListener('change', (event) => {
        event.stopPropagation();
        this._submit();
      });
    }
  }

  _submit() {
    this.dispatchEvent(new Event('change'));
  }

  __render() {
    this.__renderLabel();
    this.__renderButton();
  }

  __renderLabel() {
    if (this.__labelElement) {
      this.__labelElement.remove();
    }
    this._element.prepend(this.__getLabelTemplate());
  }

  __renderButton() {
    if (this.__buttonElement) {
      this.__buttonElement.remove();
    }
    this._element.append(this.__getButtonTemplate());
  }

  __iconTemplate() {
    return `<span is="vl-icon" data-vl-icon="magnifier" aria-hidden="true"></span>`;
  }

  __getLabelTemplate() {
    const text = this.dataset.vlLabel || 'Zoekterm';
    const content = this._isInline ? `<span class="vl-u-visually-hidden">${text}</span> ${this.__iconTemplate()}` : text;
    return this._template(`
      <label id="search-label" class="vl-search__label" for="search-input">
        <slot name="label">
          ${content}
        </slot>
      </label>
    `);
  }

  __getButtonTemplate() {
    const content = this._isInline ? this.__iconTemplate() : ``;
    return this._template(`
      <button is="vl-button" id="search-button" class="vl-search__submit" type="submit">
        ${content}
        <slot name="submit-label">
          ${this.dataset.vlSubmitLabel || 'Zoeken'}
        </slot>
      </button>
    `);
  }

  __processInputSlot() {
    const slot = this.querySelector('[slot="input"]');
    if (!slot) {
      this.__inputSlotElement.remove();
    } else {
      customElements.whenDefined('vl-select').then(async () => {
        if (slot instanceof VlSelect) {
          this.setAttribute('data-vl-has-input-slot', '');
          await slot.ready();
          this.__observeInputSlot((mutations) => {
            const isOpen = (mutation) => mutation.target.classList.contains('is-open');
            const isFocused = (mutation) => mutation.target.classList.contains('is-focused');
            if (mutations.find((mutation) => isOpen(mutation) || isFocused(mutation)) || slot.value) {
              this.__inputSlotElement.classList.add('is-open');
            } else {
              this.__inputSlotElement.classList.remove('is-open');
            }
          });
          this.append(slot._wrapperElement);
        }
      });

      if (this.__inputElement) {
        this.__inputElement.remove();
      }
    }
  }

  __observeInputSlot(callback) {
    this._observer = new MutationObserver(callback);
    this._observer.observe(this.__inputSlot, {attributes: true, attributeFilter: ['class']});
  };
}

define('vl-search', VlSearch);