/* globals Twitch, i18n */

import $ from 'jquery';
import run from 'ember-runloop';
import get from 'ember-metal/get';
import Component from 'ember-component';
import retry, { CancelledRetryError } from 'ember-graceful-retry/retry';
import computed from 'ember-computed';
import InteractivityDeferredComponent from 'web-client/mixins/interactivity-deferred-component';
import LoadingViewMixin from 'web-client/mixins/loading-view';
import StreamModel from 'web-client/models/deprecated-stream';
import injectController from 'web-client/utilities/inject-controller';
import injectService from 'ember-service/inject';
import observer from 'ember-metal/observer';


export default Component.extend(InteractivityDeferredComponent, LoadingViewMixin, {
  globals: injectService(),
  store: injectService(),
  paginator: injectService(),
  disableFollowsSidePanel: computed.alias('globals.disableFollowsSidePanel'),

  // Injected components and their dependencies
  applicationController: injectController('application'),
  // NOTICE: The login service is deprecated, plesase use the session service.
  // See app/services/SESSION.md for more details.
  login: injectService(),
  disableFollowingDirectory: computed.readOnly('applicationController.disableFollowingDirectory'),
  currentPath: computed.readOnly('applicationController.currentPath'),
  isLoggedIn: computed.readOnly('login.isLoggedIn'),
  // End Injected components and their dependencies

  currentFilter: '',

  page: null,
  channels: computed.readOnly('page.items'),
  channelsTotal: computed.readOnly('page.total'),

  init() {
    this._super(...arguments);
    let streams = StreamModel.find('live', {streamType: "all"}).load();
    this.set('streams', streams);
  },

  followingPlaceholder: i18n("Filter by name or game"),

  hasFollows: computed('channelsTotal', function () {
    /** Followed channels can be disabled using an OptionSwitch in times of heavy API load. This is a temp flag. */
    this.set('disableFollowsSidePanel', this.get('disableFollowsSidePanel') === true);
    return this.get('channelsTotal') || this.get('disableFollowsSidePanel');
  }),

  playlistStreams: computed.filterBy('streams', 'is_playlist'),
  onlineStreams: computed.filterBy('streams', 'is_playlist', false),
  streamNames: computed.mapBy('streams.content', 'channel.name'),

  offlineChannels: computed('channels.[]', 'streamNames.[]', 'streams.isLoading', function () {
    // about to compare channel names to stream names, so return [] until both are loaded
    // otherwise we see channels jump from the offline to online|playlist sections while
    // streams are loading.
    if (this.get('streams.isLoading')) { return []; }
    let streamNames = this.get('streamNames');
    return this.get('channels').reject(channel => streamNames.includes(get(channel, 'name')));
  }),

  filteredPlaylistChannels: computed('playlistStreams.[]', 'currentFilter', function () {
    let playlist = this.get('playlistStreams');
    let filter = this.get('currentFilter');
    if (!filter) { return playlist; }
    return playlist.filter(stream => this.channelFilter(stream.get('channel')));
  }),

  filteredOfflineChannels: computed('offlineChannels.[]', 'currentFilter', function () {
    let offline = this.get('offlineChannels');
    let filter = this.get('currentFilter');
    if (!filter) { return offline; }
    return offline.filter(channel => this.channelFilter(channel));
  }),

  filteredOnlineChannels: computed('onlineStreams.[]', 'currentFilter', function () {
    let online = this.get('onlineStreams');
    let filter = this.get('currentFilter');
    if (!filter) { return online; }
    return online.filter(stream => this.channelFilter(stream.get('channel')));
  }),

  channelFilter(channel) {
    let queryRegex = new RegExp(this.get('currentFilter').replace(/\s+/g, ''), 'i');
    let name = get(channel, 'name');
    let game = get(channel, 'game');
    let nameContainsQuery = queryRegex.test(name);
    let gameContainsQuery = game && queryRegex.test(game.replace(/\s+/g, ''));

    return nameContainsQuery || gameContainsQuery;
  },

  retryer: computed('disableFollowsSidePanel', function() {
    /*
     * Followed channels can be disabled using an OptionSwitch in times of
     * heavy API load.
     */
    if (this.get('disableFollowsSidePanel') || !Twitch.user.isLoggedIn()) {
      return null;
    }

    let retryer = retry(() => {
      let login = this.get('login.userData.login');
      let store = this.get('store');

      return store.findRecord('channel', login).then(channel => {
        if (this.isDestroyed) { return; }
        let page = this.get('paginator').paginatorFor({
          model: channel,
          relationshipName: 'sidebarFollowing',
          pageFactory: 'follow'
        });
        this.set('page', page);
        return page.fetchNextPage();
      });
    }, {
      isRepeating: true,
      intervals: [0, 3, 6, 12, 30, 30, 30, 120]
    });

    retryer.then(page => {
      if (this.isDestroyed) { return; }
      this.set('page', page);
    }, e => {
      if (e instanceof CancelledRetryError) {
        /* Swallow the cancellation error */
        return;
      }
      throw e;
    });

    return retryer;
  }),

  willDestroyElement() {
    this._super();
    let retryer = this.get('retryer');
    if (retryer) {
      retryer.destroy();
    }

    if ($('#right_col .scroll').data('plugin_TrackpadScrollEmulator')) {
      $('#right_col .scroll').TrackpadScrollEmulator('destroy');
    }
    $('.js-search-input').off(`blur.${this.elementId}`);
  },

  didInsertElement() {
    this._super();
    this.setupSearchListener();
    this._handleLoadMore();
    this._initScroller();
    run.scheduleOnce('afterRender', this, this.reportInteractive);
  },

  setupSearchListener() {
    $('.js-search-input').on(`blur.${this.elementId}`, run.bind(() => {
      if (this.isDestroyed) { return; }
      this.set('searchFocus', false);
    }));
  },

  _handleLoadMore: observer('currentFilter', function () {
    this.initLoading({
      buttonSelector: '.js-following-offline .js-load-more',
      sectionSelector: '.js-section-loading.offline-load',
      isLoadingProperty: 'channels.isLoading',
      hideMoreProperty: 'channels.hideMore'
    });
  }),

  _initScroller() {
    run.schedule('afterRender', function() {
      $('#right_col .scroll').TrackpadScrollEmulator({
        wrapContent: false,
        scrollbarHideStrategy: 'rightAndBottom'
      });
    });
  },

  showSearchBox: computed('searchFocus', 'currentFilter', function () {
    return this.get('searchFocus') || !!this.get('currentFilter.length');
  }),

  isFiltering: computed('currentFilter', function () {
    return !!this.get('currentFilter.length');
  }),

  actions: {
    followingLoadMore() {
      this.get('page').fetchNextPage();
    },

    searchClick() {
      this.set('searchFocus', true);
      this.runTask(() => {
        $('.js-search-input').focus();
      }, 200);
    },

    searchClear() {
      this.set('searchFocus', true);
      $('.js-search-input').focus();
      this.set('currentFilter', '');
    }
  }
});
