/* globals Twitch, _ */

import Ember from 'ember';
import StoreModel from 'web-client/models/store';
import computed from 'ember-computed';
import logApiFailure from 'web-client/utilities/log-api-failure';
import env from 'web-client/config/environment';

const { run, $, RSVP, inject } = Ember;
export const API_VERSION = 4;

let StreamModel = StoreModel.defineModel({
  api: inject.service(),
  community: inject.service(),
  store: inject.service(),
  /* configuration & hooks */

  expiration: 60000, // 1 minute

  relationships: {
    tags() {
      return this.get('community').extractFromTags(this.get('channel.status'));
    }
  },

  user: computed('id', function() {
    return this.get('store').findRecord('user', this.get('id'));
  }),

  deserialize(data) {
    if (data.user) {
      data.channel = data.user;
      delete data.user;
    }
    data.id = data.channel.name;
    data.gameUrl = Twitch.uri.game(data.game);
    data.gameBoxart = Twitch.uri.gameBoxArtJpg(data.game);
    // Skill Image should be URL must always end with a 2-digit number
    // If Skill is a one image number prepend 0 to it
    data.csGoSkill = Twitch.uri.csGoSkillImg((`0${data.skill}`).slice(-2));
    return data;
  },

  request() {
    return this.get('api').request('get', `streams/${this.get('id')}`, {stream_type: "all"}, {version: API_VERSION});
  },

  afterSuccess(response) {
    // If response.stream is null, stream is not live
    if (response.stream) {
      StreamModel.create(response.stream);
    }
  },

  afterFail() {
    logApiFailure('stream');
  },

  /* computed properties */

  channelHref: computed('id', function () {
    return Twitch.uri.channel(this.get('id'));
  })
});

StreamModel.defineCollection('bygame', {
  api: inject.service(),
  game: '',
  broadcaster_language: '',

  /* configuration & hooks */

  startLimit: 20,
  limit: 60,

  request() {
    let limit = !this.get('content.length') ? this.startLimit : this.limit;
    let opts = {limit: limit, offset: this.get('content.length'), game: this.get('game'), broadcaster_language: this.get('broadcaster_language')};
    return this.get('game') === 'Creative' ?
      this.get('api').request('get', '/api/aggregates/Creative', opts, {version: API_VERSION, host: env.creative.aggregator.host}) :
      this.get('api').request('get', 'streams', opts, {version: API_VERSION});
  },

  afterSuccess(response) {
    if(this.get('game') === 'Creative') {
      this.setContent(response.aggregate.streams);
      this.set('total', response.aggregate._total);
    } else {
      this.set('total', response._total);
      this.setContent(response.streams);
    }
  },

  afterFail() {
    logApiFailure('game streams');
  }
});

StreamModel.defineCollection('gameWithCommunity', {
  api: inject.service(),
  game: '',
  broadcaster_language: '',

  /* configuration & hooks */
  startLimit: 20,
  limit: 60,

  request() {
    // Game is forced to creative and community is set to game that way we can
    // this is a step in the migration towards deprecating music as a game.
    let community = this.get('game').toLowerCase();
    let game = 'creative';
    let limit = this.get('content.length') ? this.get('startLimit') : this.get('limit');
    let offset = this.get('content.length');
    let broadcasterLanguage = this.get('broadcasterLanguage');
    let opts = { game, limit, offset, broadcaster_language: broadcasterLanguage };
    return this.get('api').request('get', `/kraken/streams/communities/${community}/with_game`, opts, {version: API_VERSION});
  },

  afterSuccess(response) {
    this.set('total', response._total);
    this.setContent(response.streams);
  },

  afterFail() {
    logApiFailure('creative streams');
  }
});

StreamModel.defineCollection('csgo', {
  api: inject.service(),
  cs_map: '',
  order: '',

  /* configuration & hooks */

  startLimit: 20,
  limit: 60,

  request() {
    let limit = !this.get('content.length') ? this.startLimit : this.limit;
    let opts = {
      limit,
      offset: this.get('content.length'),
      "csgo.map": this.get('cs_map'),
      order: this.get('order')
    };
    return this.get('api').request('get', '/api/cs', opts);
  },

  afterSuccess(response) {
    this.setContent(response.streams);
  },

  afterFail() {
    logApiFailure('csgo streams');
  }
});

StreamModel.defineCollection('community', {
  api: inject.service(),

  startLimit: 20,
  limit: 10,
  offset: 0,

  request() {
    let community = this.get('community');
    let limit = this.get('content.length') ? this.get('startLimit') : this.get('limit');
    let offset = this.get('offset');
    let game = this.get('game');
    let broadcasterLanguage = this.get('broadcasterLanguage');
    let opts = { game, limit, offset, broadcaster_language: broadcasterLanguage };
    return this.get('api').request('get', `/kraken/streams/communities/${community}`, opts, {version: API_VERSION});
  },

  afterSuccess(response) {
    this.offset += response.streams.length;
    this.setContent(response.streams);
  },

  afterFail() {
    logApiFailure('creative streams');
  }
});

StreamModel.defineCollection('featured', {
  api: inject.service(),

  /* configuration & hooks */

  request() {
    let limit = this.get('limit') || 3;
    let params = { limit };

    let geo = this.get('geo');
    if (geo) {
      params.geo = geo;
    }

    let lang = this.get('lang');
    if (lang) {
      params.lang = lang;
    }

    return this.get('api').request('get', 'streams/featured', params, {version: API_VERSION});
  },

  afterSuccess(response) {
    this.setContent(_.map(response.featured, function (item) {
      let stream = item.stream;
      stream.scheduled = item.scheduled;
      stream.title = item.title;
      stream.text = item.text;
      stream.sponsored = item.sponsored;
      stream.featured_image = item.image;
      stream.featured_priority = item.priority;
      return stream;
    }));
  },

  afterFail() {
    logApiFailure('featured streams');
  }
});


StreamModel.defineCollection('live', {
  globals: inject.service(),
  api: inject.service(),
  session: inject.service(),

  limit:         24,
  expiration: 30000, // 30 seconds

  request() {
    let globals = this.get('globals');
    let disableFollowingDirectory = globals.get('disableFollowingDirectory');

    /** Under super heavy load, you can disable this heavy API request. */
    if (!Twitch.user.isLoggedIn() || disableFollowingDirectory) {
      return RSVP.resolve({_total: 0, streams: []});
    }

    let opts = {limit: this.limit, offset: this.get('content.length')};
    if (this.get('streamType')) {
      opts.stream_type = this.get('streamType');
    }
    return this.get('session').getCurrentUser().then(userData => {
      if (this.isDestroyed) { return; }
      let headers = {};
      headers.Authorization = `OAuth ${userData.chat_oauth_token}`;
      return this.get('api').request('get', 'streams/followed', opts, {
        version: API_VERSION,
        headers
      });
    });
  },

  afterSuccess(response) {
    this.set('total', response._total);
    this.setContent(response.streams);
  },

  afterFail() {
    logApiFailure('following channels');
  }
});


StreamModel.defineCollection('psFour', {
  api: inject.service(),

  /* configuration & hooks */

  expiration: 120000, // 2 minutes
  limit: 60,
  request() {
    let opts = {
      limit: this.limit,
      offset: this.get('content.length'),
      sce_platform: 'PS4'};
    return this.get('api').request('get', 'streams', opts, {version: API_VERSION});
  },

  afterSuccess(response) {
    this.setContent(response.streams);
  },

  afterFail() {
    logApiFailure('playstation 4 streams');
  }
});


StreamModel.defineCollection('random', {
  api: inject.service(),

  /* configuration & hooks */

  expiration: 120000, // 2 minutes
  limit: 60,
  request() {
    let opts = {limit: this.limit, offset: this.get('content.length')};
    return this.get('api').request('get', 'beta/streams/random', opts, {version: API_VERSION});
  },

  afterSuccess(response) {
    this.setContent(response.streams);
  },

  afterFail() {
    logApiFailure('random streams');
  }
});


StreamModel.defineCollection('related', {
  /* configuration & hooks */

  request() {
    let self = this;
    let promise = new RSVP.Promise(function (resolve, reject) {
      $.get(`/${self.get('channel')}/related.json`)
      .done(function (data) {
        run(null, resolve, data);
      })
      .fail(function (data) {
        run(null, reject, data);
      });
    });
    return promise;
  },

  afterSuccess(response) {
    let channels = response.channels.map(function (data) {
      return StreamModel.create({
        id: data.name,
        channel: {
          name: data.name,
          display_name: data.name,
          logo: data.image || "//static-cdn.jtvnw.net/jtv_user_pictures/xarth/404_user_150x150.png",
          game: data.game
        }
      }, true);
    });
    this.set('content', channels);
  },

  afterFail() {
    logApiFailure('related streams');
  }
});


StreamModel.defineCollection('top', {
  api: inject.service(),

  init() {
    this._super();
    this.set('broadcaster_language', this.get('broadcaster_language') || '');
  },

  /* configuration & hooks */

  startLimit: 20,
  limit: 60,

  request() {
    let limit = !this.get('content.length') ? this.startLimit : this.limit;
    let opts = {
      limit,
      offset: this.get('content.length'),
      broadcaster_language: this.get('broadcaster_language')
    };
    return this.get('api').request('get', 'streams', opts, {version: API_VERSION});
  },

  afterSuccess(response) {
    this.set('total', response._total);
    this.setContent(response.streams);
  },

  afterFail() {
    logApiFailure('streams');
  }
});


StreamModel.defineCollection('xbOne', {
  api: inject.service(),

  /* configuration & hooks */

  expiration: 120000, // 2 minutes
  limit: 24,
  request() {
    let opts = {
      limit: this.limit,
      offset: this.get('content.length'),
      xbox_heartbeat: true
    };
    return this.get('api').request('get', 'streams', opts, {version: API_VERSION});
  },

  afterSuccess(response) {
    this.setContent(response.streams);
  },

  afterFail() {
    logApiFailure('xbox one streams');
  }
});


export default StreamModel;
