import Component from 'ember-component';
import injectService from 'ember-service/inject';
import computed from 'ember-computed';
import { A as emberA } from 'ember-array/utils';
import on from 'ember-evented/on';

const DEFAULT_LIMIT = 100,
      DEFAULT_OFFSET = 0,
      CHECK_FOR_CONV_THRESHOLD = 10;

// String.prototype.includes does not exist in IE or PhantomJS.
// This function replaces usage of .includes in this file to fix tests and IE.
let stringInclude = function (haystack, needle) {
  return haystack.indexOf(needle) !== -1;
};

export default Component.extend({
  classNameBindings: [':conversations-search', 'searchString::hidden', ':scroll-container'],
  conversationResults: emberA(),
  isLoading: false,
  searchString: '',
  userResults: emberA(),

  focusedItemIndex: -1,
  offsetFocusedIndex: computed('focusedItemIndex', 'conversationResults.[]', function() {
    let resultCount = this.get('conversationResults').length;
    let currentFocus = this.get('focusedItemIndex');
    return (currentFocus >= resultCount) ? (currentFocus - resultCount) : -1;
  }),

  api: injectService(),
  conversations: injectService('twitch-conversations/conversations'),
  session: injectService(),
  store: injectService(),
  tracking: injectService(),

  actions: {
    hideList() {
      this._clearSearch();
      this.sendAction('hideList');
    },
    onSearchResultClicked(options={}) {
      let event = 'search_click';
      let data = {
        query: this.get('searchString'),
        source: 'conversation_list',
        login: this.get('session.userData.login'),
        rank: options.rank,
        is_conversation: options.isConversation
      };

      this.get('tracking').trackEvent({event, data});
    }
  },

  _onUpdateSearchString: on('didUpdateAttrs', function () {
    let searchString = this.get('searchString');
    let focusedItemIndex = this.get('focusedItemIndex');
    let offsetFocusedIndex = this.get('offsetFocusedIndex');

    if (!searchString) {
      return;
    }

    // We don't want to re-search if one of the focus indices change, unless the
    // change was due to the search string changing
    let shouldSearch = (
      ((focusedItemIndex && focusedItemIndex !== this._lastFocusedItemIndex) ||
      (offsetFocusedIndex && offsetFocusedIndex !== this._lastOffsetFocusedIndex)) &&
      searchString !== this._lastSearchString
    );

    this._lastSearchString = searchString;
    this._lastFocusedItemIndex = focusedItemIndex;
    this._offsetFocusedIndex = offsetFocusedIndex;

    if (!shouldSearch) {
      return;
    }

    searchString = searchString.trim();

    if (searchString === '') {
      this._clearSearch();
    } else {
      this.set('isLoading', true);
      this.set('conversationResults', emberA());
      this.set('userResults', emberA());
      this.debounceTask('_search', 500);

      let allParticipants = this.get('store').peekAll('participant');
      allParticipants.forEach(participant => {
        let displayName = participant.get('displayName') || '',
            username = participant.get('username');
        if (stringInclude(displayName, searchString) || stringInclude(username, searchString)) {
          let currentUserId = this.get('session.userData.id'),
              otherUserId = participant.get('id'),
              threadId = this.get('conversations').generateThreadId(currentUserId, otherUserId),
              maybeThread = this.get('store').peekRecord('thread', threadId);
          if (maybeThread) {
            let conversation = this.get('conversations').findConversationForThread(maybeThread);
            this._addToConversationResults(conversation);
          }
        }
      });
    }
  }),

  _search(limit=DEFAULT_LIMIT, offset=DEFAULT_OFFSET) {
    let q = this.get('searchString');

    if (q) {
      this.get('api').request('get', 'search/users', { q, limit, offset }).then(response => {
        if (this.isDestroyed) { return; }
        this.set('isLoading', false);
        response.users.forEach((user, index) => {
          this._displayUserResult(user, index);
        });

        let event = 'search_autocomplete';
        let data = {
          query: q,
          login: this.get('session.userData.login'),
          source: 'conversation_list',
          num_search_result: response._total,
          num_search_conversation: this.get('conversationResults.length')
        };
        this.get('tracking').trackEvent({event, data});
      });
    }
  },

  _clearSearch() {
    this.set('conversationResults', emberA());
    this.set('userResults', emberA());
    this.set('searchString', '');
    this.set('isLoading', false);
    this._lastSearchString = undefined;
    this._lastFocusedItemIndex = undefined;
    this._offsetFocusedIndex = undefined;
  },

  _displayUserResult(user, index) {
    let otherUserId = user._id,
        currentUserId = this.get('session.userData.id'),
        threadId = this.get('conversations').generateThreadId(currentUserId, otherUserId),
        maybeThread = this.get('store').peekRecord('thread', threadId);

    if (maybeThread) {
      let conversation = this.get('conversations').findConversationForThread(maybeThread);
      this._addToConversationResults(conversation);
    } else {
      if (!this.get('userResults').includes(user)) {
        this.get('userResults').addObject(user);
        if (index < CHECK_FOR_CONV_THRESHOLD) {
          this.get('conversations').findThread(threadId).then(thread => {
            let conversation = this.get('conversations').findConversationForThread(thread);
            if (this.get('userResults').includes(user)) {
              this.get('userResults').removeObject(user);
              this._addToConversationResults(conversation);
            }
          }, () => {
            // Mark error as handled to squelch it
            return true;
          });
        }
      }
    }
  },

  _addToConversationResults(conversation) {
    if (!this.get('conversationResults').includes(conversation)) {
      this.get('conversationResults').addObject(conversation);
    }
  }
});
