/*
  <select name="teste" id="teste" data-placeholder="Teste">
    <option value="1" data-img="image.jpg">Option 1</option>
    <option value="2" data-img="image.jpg">Option 2</option>
    <option value="3" data-img="image.jpg">Option 3</option>
    <option value="4" data-img="image.jpg">Option 4</option>
  </select>

  import SelectAutocomplete from './select-autocomplete';
  new SelectAutocomplete(document.getElementById('teste'), function() {
    console.log(this);
  });
*/

'use strict';
export default class SelectAutocomplete {
  constructor(select, itemSelectedFunction) {
    this.select = select;
    this.itemSelectedFunction = itemSelectedFunction;

    this.reference = select;
    this.parent = select.parentNode;

    this.value;
    this.state = {};
    this.component = {};
    this.hasInteraction = false;

    this.init();

    return this;
  }

  init() {
    const ID = this.select.id || '',
      NAME = this.select.name,
      CLASS = this.select.classList || '',
      PLACEHOLDER = this.select.dataset.placeholder || '',
      OPTIONS = this.select.children;

    let options = [];

    for (let i = 0; i < OPTIONS.length; i++) {
      options.push({
        label: OPTIONS.item(i).textContent.trim(),
        value: OPTIONS.item(i).value,
        image: OPTIONS.item(i).dataset.img || '',
        color: OPTIONS.item(i).dataset.color || '',
        stock: OPTIONS.item(i).dataset.stock === 'S',
        selected: OPTIONS.item(i).getAttribute('selected') !== null,
      });
    }

    this.state = {
      id: ID,
      name: NAME,
      class: CLASS,
      placeholder: PLACEHOLDER,
      options,
    };

    this.render();
  }

  interaction() {
    if (this.hasInteraction) return false;
    this.hasInteraction = true;

    document.body.addEventListener('click', event => {
      const { INPUT_SEARCH, LIST, ICON } = this.component;

      if ((INPUT_SEARCH !== event.target && ICON !== event.target) || !LIST.hidden) {
        this.render();
        return false;
      }

      if (!LIST.querySelector('.active')) LIST.children[0].classList.add('active');

      const HEIGHT_VIEWPORT = window.innerHeight,
        POS_HEIGHT_COMPONENT = INPUT_SEARCH.getBoundingClientRect().bottom + 224,
        ITEM_ACTIVE = LIST.querySelector('.active');

      if (POS_HEIGHT_COMPONENT > HEIGHT_VIEWPORT) {
        LIST.style.top = 'inherit';
        LIST.style.bottom = '42px';
      }

      LIST.hidden = false;
      LIST.scrollTop = ITEM_ACTIVE.offsetTop;

      INPUT_SEARCH.focus();
      INPUT_SEARCH.setSelectionRange(0, INPUT_SEARCH.value.length);
    });
  }

  handleItem(item) {
    const VALUE = item.dataset.value;

    if (this.itemSelectedFunction) {
      this.value = VALUE;
      this.itemSelectedFunction.call(this);
    }

    this.state.options.map(option => {
      option.selected = option.value === VALUE;
    });

    this.render();
  }

  search() {
    const { INPUT_SEARCH, LIST } = this.component,
      LIST_ARRAY = LIST.querySelectorAll('.item');

    for (let i = 0; i < LIST_ARRAY.length; i++) {
      LIST_ARRAY[i].classList.remove('active');
      LIST_ARRAY[i].hidden = LIST_ARRAY[i].textContent.toLowerCase().indexOf(INPUT_SEARCH.value.toLowerCase()) === -1;
    }

    const ITEM_ACTIVE = LIST.querySelector('.item:not([hidden])');
    if (ITEM_ACTIVE) ITEM_ACTIVE.classList.add('active');
  }

  ArrowUp(itemActive) {
    let prevSibling = itemActive.previousElementSibling;

    while (prevSibling && prevSibling.hidden) {
      prevSibling = prevSibling.previousElementSibling;
    }

    if (prevSibling) {
      prevSibling.classList.add('active');
      itemActive.classList.remove('active');
    } else {
      return;
    }

    const { LIST } = this.component,
      POS_PREV_SIBLING = prevSibling.offsetTop,
      POS_LIST = LIST.scrollTop;

    if (POS_LIST > POS_PREV_SIBLING) {
      const VARIATION = POS_LIST - POS_PREV_SIBLING;

      LIST.scroll(0, POS_LIST - VARIATION);
    }
  }

  ArrowDown(itemActive) {
    let nextSibling = itemActive.nextElementSibling;

    while (nextSibling && nextSibling.hidden) {
      nextSibling = nextSibling.nextElementSibling;
    }

    if (nextSibling) {
      nextSibling.classList.add('active');
      itemActive.classList.remove('active');
    } else {
      return;
    }

    const { LIST } = this.component,
      POS_NEXT_SIBLING = nextSibling.offsetTop + nextSibling.offsetHeight,
      POS_LIST = LIST.scrollTop + LIST.offsetHeight;

    if (POS_NEXT_SIBLING > POS_LIST) {
      LIST.scroll(0, POS_NEXT_SIBLING - LIST.offsetHeight);
    }
  }

  handleKeyPress() {
    const { INPUT_SEARCH, LIST } = this.component;

    INPUT_SEARCH.onkeyup = event => {
      event.preventDefault();
      const ITEM_ACTIVE = LIST.querySelector('.active');
      switch (event.key) {
        case 'Enter':
          this.handleItem.call(this, ITEM_ACTIVE);
          break;
        case 'Escape':
          this.render();
          break;
        case 'ArrowUp':
          INPUT_SEARCH.selectionStart = INPUT_SEARCH.selectionEnd = INPUT_SEARCH.value.length;
          this.ArrowUp(ITEM_ACTIVE);
          break;
        case 'ArrowDown':
          this.ArrowDown(ITEM_ACTIVE);
          break;
        default:
          this.search();
          break;
      }
    };
  }

  render() {
    const CONTAINER = document.createElement('div');
    CONTAINER.classList.add('select-autocomplete');
    if (this.state.id) CONTAINER.id = this.state.id;
    if (this.state.class) {
      for (let i = 0; i < this.state.class.length; i++) {
        CONTAINER.classList.add(this.state.class[i]);
      }
    }

    const ICON = document.createElement('i');
    /* ie não aceita classList.add multiplos */
    ICON.classList.add('fas');
    ICON.classList.add('fa-angle-down');
    ICON.classList.add('field-icon');
    ICON.classList.add('field-icon-right');
    ICON.classList.add('cursor-pointer');
    CONTAINER.appendChild(ICON);

    const SELECTED_ITEM = this.state.options.reduce((optionSelected, option) =>
      option.selected ? option : optionSelected
    );

    const INPUT_SEARCH = document.createElement('input');
    INPUT_SEARCH.type = 'text';
    INPUT_SEARCH.placeholder = this.state.placeholder;
    INPUT_SEARCH.classList.add('field-entry');
    INPUT_SEARCH.value = typeof SELECTED_ITEM !== 'undefined' && SELECTED_ITEM.selected ? SELECTED_ITEM.label : '';

    const INPUT_VALUE = document.createElement('input');
    INPUT_VALUE.name = this.state.name;
    INPUT_VALUE.type = 'hidden';
    INPUT_VALUE.classList.add('field-value');
    INPUT_VALUE.value = typeof SELECTED_ITEM !== 'undefined' && SELECTED_ITEM.selected ? SELECTED_ITEM.value : '';

    const LIST = document.createElement('div');
    LIST.classList.add('list');
    LIST.hidden = true;

    for (let i = 0; i < this.state.options.length; i++) {
      const OPTION = this.state.options[i],
        ITEM = document.createElement('div');

      ITEM.classList.add('item');
      ITEM.dataset.value = OPTION.value;
      ITEM.addEventListener('click', () => this.handleItem.call(this, ITEM));

      if (OPTION.image) {
        const IMAGE = document.createElement('img');
        IMAGE.src = OPTION.image;
        ITEM.appendChild(IMAGE);
      }


      if (OPTION.color) {
        let colors = OPTION.color.split(',');
        const BACKGROUND = document.createElement('div');
        BACKGROUND.style.background  = (colors[1].trim())  ? 'linear-gradient(135deg,'+ colors[0]+' 0%,'+ colors[0] +' 50%,'+ colors[1] +' 50%,'+ colors[1]  +' 100%)' : colors[0];
        BACKGROUND.classList.add('bg-colors');
        ITEM.appendChild(BACKGROUND);
      }

      const TEXT = OPTION.stock ? document.createElement('span') : document.createElement('s');
      TEXT.appendChild(document.createTextNode(OPTION.label));

      if (OPTION.selected) {
        ITEM.classList.add('active');
      }

      ITEM.appendChild(TEXT);
      LIST.appendChild(ITEM);
    }

    CONTAINER.appendChild(INPUT_SEARCH);
    CONTAINER.appendChild(INPUT_VALUE);
    CONTAINER.appendChild(LIST);

    this.component = {
      CONTAINER,
      ICON,
      INPUT_SEARCH,
      INPUT_VALUE,
      LIST,
    };

    this.interaction();
    this.handleKeyPress();
    this.appendDocument();
  }

  appendDocument() {
    const { CONTAINER } = this.component;

    this.parent.insertBefore(CONTAINER, this.reference);
    this.parent.removeChild(this.reference);
    this.reference = CONTAINER;
  }
}
