/* globals _ */

import Component from 'ember-component';
import env from 'web-client/config/environment';
import computed from 'ember-computed';
import { keyboardListener } from 'web-client/utilities/keyboard';
import buildCategories from './navigation-search/utils/category';
import injectService from 'ember-service/inject';
import run from 'ember-runloop';
import $ from 'jquery';
import SearchRequest from 'web-client/utilities/navigation-search/search-request';
import { assign } from 'ember-platform';
import Ember from 'ember';

const { defaults } = _;
const { getOwner } = Ember;

// Distance (in pixels) to begin next infinite-scroll load
const SCROLL_BUFFER = 500;
const delayResults = env.delay.search.spinner;

const LONG_LENGTH = 900; // 15 minutes

export default Component.extend({
  search: injectService(),
  layoutService: injectService('layout'),
  experiments: injectService(),
  tracking: injectService(),
  scrollBuffer: SCROLL_BUFFER,

  init() {
    this._super(...arguments);
    this.userDidActivate = false;
    this.searches = {};
    this.currentCategory = null;
    this.categories = buildCategories();
    this.term = '';
    this.filterOptions = {};
    this.request = this.request || SearchRequest.create();
    this._didClickThrough = false;
    this.router = getOwner(this).lookup('router:main');

    defaults(this, {
      isActivated: false,
      onDeactivate: () => {},
      onActivate: () => {}
    });

    this.router.on('willTransition', this, 'deactivate');
  },

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

    if (this.get('isInHeader')) {
      this.addEventListener(window, 'resize', () => this.updateLeftPosition());
      run.schedule('afterRender', () => this.updateLeftPosition());
    }

    this.addEventListener(...keyboardListener({
      esc: this.keyboardDeactivate,
      find: this.keyboardActivate
    }));

    this.addEventListener(window, 'beforeunload', () => this.willUnloadPage());
  },

  willDestroy() {
    this.router.off('willTransition', this, 'deactivate');
    this.get('request').cancel();
    this._super(...arguments);
  },

  willUnloadPage() {
    if (this.get('isPanelOpen')) {
      this.searchInteractionDidEnd();
    }
  },

  didReceiveAttrs() {
    if (this.get('isActivated')) {
      this.activate();
    }
  },

  noResultsFound: computed('categories.@each.totalHitCount', function () {
    return this.get('categories').every(category => !category.get('totalHitCount'));
  }),

  isShowingFieldCategoryIcon: computed.and('currentCategory', 'isPanelOpen'),

  isPanelOpen: computed('userDidActivate', 'term', function () {
    return this.get('userDidActivate') && this.get('term');
  }),

  sortedCategories: computed('categories.@each.hasNoHits', function () {
    return this.get('categories').sortBy('hasNoHits');
  }),

  updateLeftPosition() {
    this.set('leftPosition', this.$('input').offset().left);
  },

  deactivate() {
    if (this.get('userDidActivate')) {
      this.get('onDeactivate')();
      this.set('userDidActivate', false);
      this.$('input').blur();
    }
  },

  searchInteractionDidEnd() {
    let term = this.get('term');
    let category = this.get('currentCategory');

    if (!term) {
      return;
    }

    // Give the click-through a chance to bubble
    run.next(() => {
      if (this._didClickThrough) {
        this.get('tracking').trackEvent({
          event: 'completed_search',
          data: {
            query: term,
            filter: category && category.id
          }
        });
      } else {
        this.get('tracking').trackEvent({
          event: 'abandoned_search',
          data: { query: term }
        });
      }
      this._didClickThrough = false;
    });
  },

  activate() {
    if (this.get('userDidActivate')) {
      return;
    }

    this.set('userDidActivate', true);
    run.schedule('afterRender', () => this.$('input').focus());
    this.get('onActivate')();
    this.get('layoutService').trigger('searchWasActivated');
  },

  keyboardActivate(e) {
    if (!this.get('userDidActivate')) {
      e.preventDefault();
      this.activate();
    }
  },

  keyboardDeactivate() {
    if (this.get('currentCategory')) {
      this.updateCurrentCategory(null);
    } else {
      this.deactivate();
    }
  },

  updateCurrentCategory(category) {
    if (this.get('currentCategory') !== category) {
      this.set('currentCategory', category);
      this.query({ delayResults });
    }
  },

  clearResults() {
    this.get('categories').forEach((category) => {
      category.set('search', []);
    });
  },

  // This event listener must live here instead of directly on the input
  // element. https://github.com/emberjs/ember.js/issues/12676
  focusIn() {
    this.activate();
  },

  actions: {
    loadMoreForType() {
      let page = this.get('currentCategory.nextPage');
      this.query({ page });
    },

    onClickOutsidePanel(e) {
      if (!$.contains(this.element, e.target)) {
        this.deactivate();
      }
    },

    activate() {
      this.activate();
    },

    updateTerm(event) {
      let searchWasEmpty = !this.get('term');
      let term = event.target.value;
      this.set('term', term);

      if (term && searchWasEmpty) {
        this.query({ delayResults });
      } else if (term) {
        this.query();
      } else {
        this.clearResults();
      }
    },

    updateCurrentCategory(category) {
      this.updateCurrentCategory(category);
    },

    didClickThrough() {
      this._didClickThrough = true;
    },

    searchInteractionDidEnd() {
      this.searchInteractionDidEnd();
    },

    searchInteractionDidBegin() {
      // HACK(mikeche): Update the position in the input was moved after initial render.
      // This is used in top nav, which may insert a premium link after initial render.
      if (this.get('isInHeader')) {
        this.updateLeftPosition();
      }

      this.get('tracking').trackEvent({
        event: 'began_search',
        data: { query: this.get('term') }
      });
    },

    updateFilterOptions(filterOptions) {
      this.set('filterOptions', filterOptions);
      this.query();
    }
  },

  query(options = {}) {
    let currentCategoryId = this.get('currentCategory.id');
    let page = options.page || 0;
    let term = this.get('term');
    let debounce = env.delay.search.updateTerm;

    this.get('request').start(assign(options, {
      debounce,

      request: () => {
        if (currentCategoryId) {
          let queryOptions = assign(toQueryOptions(this.get('filterOptions'), currentCategoryId), { page });
          return this.get('search').queryForType(currentCategoryId, term, queryOptions);
        }
        return this.get('search').queryTopResults(term);
      },

      success: (results) => {
        let totalHitCount = 0;
        this.get('categories').forEach((category) => {
          category.set('search', results[category.get('id')]);
          totalHitCount += category.get('totalHitCount');
        });

        this.get('tracking').trackEvent({
          event: 'search_query',
          data: {
            query: term,
            count: totalHitCount
          }
        });
      }
    }));
  }
});

function toQueryOptions(filterOptions, currentCategoryId) {
  if (currentCategoryId === 'videos') {
    let indexName = (filterOptions.sort === 'Newest') ? 'vod_by_created_at' : null;
    let facetFilters = null;
    let numericFilters = null;

    switch(filterOptions.type) {
      case 'Past Broadcasts':
        facetFilters = 'broadcast_type:archive';
        break;
      case 'Uploads':
        facetFilters = 'broadcast_type:upload';
        break;
      case 'Highlights':
        facetFilters = 'broadcast_type:highlight';
        break;
    }

    switch(filterOptions.duration) {
      case 'Short':
        numericFilters = `length<=${LONG_LENGTH}`;
        break;
      case 'Long':
        numericFilters = `length>${LONG_LENGTH}`;
        break;
    }

    return { indexName, facetFilters, numericFilters };
  }

  return {};
}
