/* globals Twitch */

import Service from 'ember-service';
import injectService from 'ember-service/inject';
import computed from 'ember-computed';
import RSVP from 'rsvp';
import { copy } from 'ember-metal/utils';

const RECOMMENDED_VODS_URL = '/api/vods/recommended';
const RECOMMENDED_VODS_LIMIT = 20;

export default Service.extend({
  api: injectService(),
  store: injectService(),
  experiments: injectService(),
  // NOTICE: The login service is deprecated, plesase use the session service.
  // See app/services/SESSION.md for more details.
  login: injectService(),

  vods: [],
  filteredVods: null,
  isLoggedIn: computed.alias('login.isLoggedIn'),
  isFollowingAboveHost: false,
  areVodsViewable: computed.notEmpty('recommendedVods'),
  hadRecs: computed.notEmpty('vods'),
  numRecsWatched: 0,
  numRecsPrefiltered: 0,
  varietyVods: [],

  // api group experiment properties
  apiGroupParam: null,

  checkExperiment() {
    let experiments = this.get('experiments');
    let promises = {
      placement: experiments.getExperimentValue("VOD_COVIEWS"),
      apiGroup: experiments.getExperimentValue("VOD_COVIEWS_AB")
    };

    return RSVP.hash(promises).then((experimentValues) => {
      if (this.isDestroyed) { return; }

      let isFollowingAboveHost = (experimentValues.placement === 'following_above_host');
      this.set('isFollowingAboveHost', isFollowingAboveHost);

      let apiGroupParam;
      if (experimentValues.apiGroup === 'control') {
        apiGroupParam = 'a';
      } else {
        apiGroupParam = experimentValues.apiGroup;
      }

      this.set('apiGroupParam', apiGroupParam);
    });
  },

  findVodCoviews() {
    return this._loadVodCoviews().then(data => {
      let vods = this._deserialize(data);
      this.set('vods', vods);
    });
  },

  recommendedVods: computed('vods', function() {
    this._filterVods();
    this._enforceMaxChannelVariety();
    return this.get('varietyVods');
  }),

  dismissRecommendation(vodId) {
    this._dismissVods(vodId, true);
  },

  undoDismissRecommendation(vodId) {
    this._dismissVods(vodId, false);
  },

  // TODO: this logic can be completely removed once all of coviews is using carousels
  _dismissVods(vodId, dismiss) {
    let dismissedVods = Twitch.storage.getObject('dismissedCoviewVods') || {};
    let recommendedVods = this.get('recommendedVods');
    let vodToDismiss = recommendedVods.find(vod => {
      return vod.id === vodId;
    });
    let index = recommendedVods.indexOf(vodToDismiss);


    if (dismiss) {
      dismissedVods[vodId] = true;
      recommendedVods[index].dismissed = true;
    } else {
      delete dismissedVods[vodId];
      delete recommendedVods[index].dismissed;
    }

    Twitch.storage.setObject('dismissedCoviewVods', dismissedVods);
  },

  _filterVods() {
    let vods = this.get('vods');
    let history = Twitch.storage.getObject('vodResumeWatcheds') || {};
    let visitedVods = Twitch.storage.getObject('visitedVods') || {};
    let dismissedVods = Twitch.storage.getObject('dismissedCoviewVods') || {};

    let filteredVods = vods.filter(vod => {
      return !visitedVods[vod.id.toString().replace('v', '')] && !history[vod.id] && !dismissedVods[vod.id];
    });

    this.set('numRecsWatched', vods.length - filteredVods.length);
    this.set('filteredVods', filteredVods);
  },

  _loadVodCoviews() {
    let deviceId = Twitch.idsForMixpanel.getOrCreateUniqueId();

    let opts = {
      device_id: deviceId,
      limit: RECOMMENDED_VODS_LIMIT,
      group: this.get('apiGroupParam'),
      offset: 0
    };

    return this.get('api').request('get', RECOMMENDED_VODS_URL, opts, {version: 3}).then(
      (response) => {
        return response.videos;
      }
    ).catch((error) => {
      if (typeof error === 'object' && error.status >= 400) {
        return [];
      }
      throw error;
    });
  },

    // promote channels to the front to enforce at most two channels
  _enforceMaxChannelVariety() {
    let vods = copy(this.get('filteredVods'));
    let channelCount = {};
    let staleVods = [];

    this.get('filteredVods').forEach((rec, index) => {
      let currentCount = channelCount[rec.channel.name];
      channelCount[rec.channel.name] = currentCount ?  currentCount + 1 : 1;
      if (channelCount[rec.channel.name] > 2) {
        vods.splice(index - staleVods.length, 1);
        staleVods.push(rec);
      }
    });

    this.set('forcedVarietyMaxChannelsBoundary', vods.length);
    this.set('varietyVods', vods.concat(staleVods));
  },

  // copied from video model
  _deserialize(vodData) {
    return vodData.map((data, index) => {
      data.id = data._id;
      delete data._id;
      data.gameUrl = Twitch.uri.game(data.game);
      data.gameBoxart = Twitch.uri.gameBoxArtJpg(data.game);
      data.gameBoxArt = data.gameBoxart;
      data.prefilteredIndex = index;
      data.recordedDate = data.published_at || data.created_at;

      data.isRecommended = true;
      return data;
    });
  }
});
