import { htmlSafe } from 'ember-string';
import Component from 'ember-component';
import injectService from 'ember-service/inject';
import { keyboardListener, KEY_CODES } from 'web-client/utilities/keyboard';
import inRange from 'web-client/utilities/in-range';
import $ from 'jquery';
import computed from 'ember-computed';
import { copy } from 'ember-metal/utils';

const ACTIVE_CLASS = 'isActive';
const SELECTABLE = '[data-ts_selectable]';
export const FILTER_CONTAIN_ID = `lol_champ_filter`; // exported for tests

export default Component.extend({
  lolMetadataFilter: injectService(),

  serializedChampData: computed.readOnly('lolMetadataFilter.serializedChampData'),

  champQuery: '',
  isActivated: false,

  filteredChamps: computed('champQuery', 'serializedChampData', 'lolMetadataFilter.champTags', function () {
    if (!this.get('serializedChampData') || !this.get('lolMetadataFilter.champTags')) {
      return [];
    }

    let query = this.get('champQuery').toLowerCase();
    let tags = Object.keys(this.get('lolMetadataFilter.champTags'));
    let isQueryChampTag = tags.includes(query);
    let fuzzyRe = new RegExp(`.*${query.split('').join('.*')}`);
    let prefixRe = new RegExp(`^${query}`);

    let allChamps = copy(this.get('serializedChampData'), true);

    let filteredLists = {
      prefix: [],
      fuzzy: []
    };

    allChamps.forEach(champ => {
      champ['figureStyle'] = this._figureStyle(champ);
      champ['imgStyle'] = this._imgStyle(champ);

      if (champ.name.toLowerCase().match(prefixRe) || champ.key.toLowerCase().match(prefixRe)) {
        // queries prefix matches
        filteredLists.prefix.push(champ);
      } else if (isQueryChampTag && champ.tags[query]) {
        // eg. marksman, tank, etc
        filteredLists.fuzzy.push(champ);
      } else if (champ.name.toLowerCase().match(fuzzyRe) || champ.key.toLowerCase().match(fuzzyRe)) {
        // query matches the name or the key
        filteredLists.fuzzy.push(champ);
      }
    });

    return filteredLists.prefix.concat(filteredLists.fuzzy);
  }),

  didInsertElement() {
    this._super(...arguments);

    this.addEventListener('#lol-champion-filter-contain', 'clickoutside', () => {
      this.deactivate();
    });

    this.addEventListener(...keyboardListener({
      esc: this.deactivate,
      down: this.activateNext,
      enter: this.selectActive,
      up: this.activatePrevious
    }));
  },

  didRender() {
    this.shiftActiveFirst();
  },

  /* event listeners */

  mouseOver(e) {
    if (this._isKeyboardNavigating) {
      return;
    }

    let selectable = $(e.target).closest(SELECTABLE, this.$());
    if (!selectable) {
      return;
    }
    this.activateElement(selectable);
  },

  mouseMove() {
    this._isKeyboardNavigating = false;
  },

  focusIn() {
    if (this.get('champQuery') !== '') {
      this.activate();
    }
  },

  keyUp(e) {
    if (e.keyCode !== KEY_CODES.esc && e.keyCode !== KEY_CODES.enter && this.get('champQuery') !== '') {
      this.activate();
    }
  },

  /* css styles for navigating the filter */

  activate() {
    this.set('isActivated', true);
  },

  deactivate() {
    this.set('isActivated', false);
  },

  activateNext(e) {
    this.activate();
    this.shiftActive(e, 1);
  },

  activatePrevious(e) {
    this.shiftActive(e, -1);
  },

  selectActive(e) {
    e.preventDefault();
    e.stopPropagation();
    let focusedElement = this.$(`.${ACTIVE_CLASS}`);
    if (focusedElement.length) {
      focusedElement.click();
    }
  },

  shiftActive(e, shiftIndex) {
    this._isKeyboardNavigating = true;
    e.preventDefault();

    let searchElements = this.$(SELECTABLE);
    let activeElementIndex = searchElements.index(this.$(`.${ACTIVE_CLASS}`));
    let nextIndex = activeElementIndex + shiftIndex;

    if (inRange(nextIndex, 0, searchElements.length)) {
      let nextElement = searchElements.eq(nextIndex);
      this.activateElement(nextElement);
      this.scrollIntoView(nextElement);
    }
  },

  shiftActiveFirst() {
    let searchElements = this.$(SELECTABLE);

    let nextElement = searchElements.eq(0);
    this.activateElement(nextElement);
    this.scrollIntoView(nextElement);
  },

  activateElement(element) {
    if (!element.hasClass(ACTIVE_CLASS)) {
      this.removeActive();
      element.addClass(ACTIVE_CLASS);
    }
  },

  removeActive() {
    let activeElement = this.$(`.${ACTIVE_CLASS}`);
    activeElement.removeClass(ACTIVE_CLASS);
  },

  scrollIntoView(element) {
    if (!element.offset()) {
      return;
    }

    let elementTop = element.offset().top;
    let elementBottom = elementTop + element.height();

    let panelTop = $(`#${FILTER_CONTAIN_ID}`).offset().top;
    let panelBottom = panelTop + $(`#${FILTER_CONTAIN_ID}`).height();

    let scrollTop = $(`#${FILTER_CONTAIN_ID}`).scrollTop();

    if (elementTop < panelTop) {
      $(`#${FILTER_CONTAIN_ID}`).scrollTop(scrollTop - (panelTop - elementTop));
    } else if (elementBottom > panelBottom) {
      $(`#${FILTER_CONTAIN_ID}`).scrollTop(scrollTop + (elementBottom - panelBottom));
    }
  },

  /* inline styles for sprite positioning - must be sanitized to prevent warnings */

  _figureStyle(champion) {
    return htmlSafe(`width:${champion.spriteWidth}px; height:${champion.spriteHeight}px;
      margin: 2px; margin-right: 10px;`);
  },

  _imgStyle(champion) {
    return htmlSafe(`width:${champion.spriteWidth}px; height:${champion.spriteHeight}px;
      object-position: ${champion.spritePos}; object-fit: none;`);
  },

  /* actions */

  searchStreamsForChamp() {
    // TODO: Dead code
  },

  actions: {
    selectChamp(champ) {
      this.set('champQuery', champ.key);

      this.searchStreamsForChamp(champ.key);
      this.deactivate();
    }
  }
});
