/* globals Twitch */
import RSVP from 'rsvp';
import computed from 'ember-computed';
import injectService from 'ember-service/inject';
import logApiFailure from 'web-client/utilities/log-api-failure';
import StoreModel from 'web-client/models/store';
import VideoPropertiesModel from 'web-client/models/video-properties';
import ChannelViewerModel from 'web-client/models/channel-viewer';
import ChannelModel from 'web-client/models/deprecated-channel';
import { normalizeVideoId } from 'web-client/utilities/normalize-video-id';
import { ALL_VIDEOS_PARAM, UPLOAD_TYPE_PARAM } from 'web-client/utilities/video/types';

const RESULT_START_LIMIT = 20;
const RESULT_LIMIT = 60;
const DEFAULT_PERIOD = '';
const WEEK_IN_MS = 60 * 60 * 24 * 7 * 1000;
const MONTH_IN_MS = 60 * 60 * 24 * 30 * 1000;

let DeprecatedVideo = StoreModel.defineModel({
  api: injectService(),
  community: injectService(),
  store: injectService(),

  relationships: {
    relatedVideos() { return DeprecatedVideo.find('related', { channel: this.get('channel.name') }); },
    similarVideos() { return DeprecatedVideo.find('similar', { video: this.get('id') }); },
    properties() { return VideoPropertiesModel.findOne(this.get('id')); },
    viewer() { return ChannelViewerModel.findOne(this.get('channel.name')); },
    owner() {
      return ChannelModel.find({ id: this.get('channel.name') });
    },
    tags() {
      let communityService = this.get('community');
      return communityService.extractFromTags(this.get('title'))
        .concat(communityService.extractFromTags(this.get('description')));
    }
  },

  unavailable: computed.readOnly('owner.unavailable'),
  wasUploaded: computed.equal('broadcast_type', UPLOAD_TYPE_PARAM),

  user: computed('channel.name', function() {
    let name = this.get('channel.name');
    return this.get('store').findRecord('user', name);
  }),

  deserialize(data) {
    if (data._id) {
      data.id = data._id;
      delete data._id;
    }

    data.descriptionHTML = data.description_html;
    delete data.description_html;
    data.descriptionMarkdown = data.description;
    delete data.description;

    data.gameUrl = Twitch.uri.gameVideos(data.game);
    data.gameBoxart = Twitch.uri.gameBoxArtJpg(data.game);
    data.gameBoxArt = data.gameBoxart;
    data.recordedDate = data.published_at || data.created_at;

    return data;
  },

  request() {
    return this.get('api').request('get', `videos/${this.get('id')}`);
  },

  afterSuccess(response) {
    DeprecatedVideo.create(response);
  },

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

  saveRemote(data) {
    data.description = data.descriptionMarkdown;
    delete data.descriptionMarkdown;

    let resp = this.get('api').request('put', `/api/vods/${normalizeVideoId(this.id)}`, data);
    return resp.then(function (payload) {
      return this.deserialize(payload);
    }.bind(this));
  },

  destroyRemote() {
    return this.get('api').request('del', `/kraken/videos/${normalizeVideoId(this.id)}`);
  }
});

DeprecatedVideo.defineCollection('channel', {
  api: injectService(),

  limit: RESULT_LIMIT,

  request() {
    let opts = {
      limit: this.limit,
      offset: this.get('content.length'),
      broadcasts: this.get('pastBroadcasts'),
      broadcast_type: this.get('broadcastType'),
      sort: this.get('sort')
    };
    return this.get('api').request('get', `channels/${this.get('channel')}/videos`, opts);
  },

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

  afterFail() {
    logApiFailure('channel videos');
  }
});

DeprecatedVideo.defineCollection('channel-uploads', {
  api: injectService(),

  limit: RESULT_LIMIT,

  request() {
    let opts = {
      limit: this.limit,
      offset: this.get('content.length'),
      broadcast_type: this.get('broadcastType')
    };
    return this.get('api').request('get', `channels/${this.get('channel')}/videos`, opts);
  },

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

  afterFail() {
    logApiFailure('channel uploaded videos');
  }
});

DeprecatedVideo.defineCollection('following', {
  api: injectService(),
  globals: injectService(),
  session: injectService(),

  broadcastType: ALL_VIDEOS_PARAM,
  startLimit: RESULT_START_LIMIT,
  limit: RESULT_LIMIT,

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

    /** Under super heavy load, you can disable this heavy API request. */
    if (!isAuthenticated || disableFollowingDirectory) {
      return RSVP.resolve({videos: []});
    }

    let limit = this.get('content.length') ? this.limit : this.startLimit;
    let opts = {
      limit,
      offset: this.get('content.length'),
      language: this.get('language'),
      broadcast_type: this.get('broadcastType'),
      sort: this.get('sort')
    };
    return this.get('api').request('get', 'videos/followed', opts);
  },

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

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

DeprecatedVideo.defineCollection('game', {
  api: injectService(),
  experiments: injectService(),
  game: '',
  period: DEFAULT_PERIOD,
  broadcastType: ALL_VIDEOS_PARAM,

  startLimit: RESULT_START_LIMIT,
  limit: RESULT_LIMIT,
  useHigherLimit: false,

  request() {
    let limit = (this.get('content.length') || this.get('useHigherLimit')) ? this.limit : this.startLimit;
    let opts = {
      limit,
      offset: this.get('content.length'),
      game: this.get('game'),
      period: this.get('period'),
      language: this.get('language'),
      broadcast_type: this.get('broadcastType'),
      sort: this.get('sort')
    };

    return this.get('api').request('get', 'videos/top', opts);
  },

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

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

DeprecatedVideo.defineCollection('related', {
  api: injectService(),

  request() {
    return this.get('api').request('get', `/api/users/${this.get('channel')}/related_videos`);
  },

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

  afterFail() {
    logApiFailure('channel videos');
  }
});

DeprecatedVideo.defineCollection('similar', {
  api: injectService(),

  request() {
    return this.get('api').request('get', `/kraken/videos/similar/${this.get('video')}`);
  },

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

  afterFail() {
    logApiFailure('similar videos');
  }
});

DeprecatedVideo.defineCollection('tags', {
  nextPage: 0,

  request() {
    let now = new Date();
    let periodInSeconds = {
      all: 0,
      week: now.getTime() - WEEK_IN_MS,
      month: now.getTime() - MONTH_IN_MS
    };
    let createdAfter = parseInt(periodInSeconds[this.get('period')] / 1000);

    return this.get('search').queryVodsByTag(
      `#${this.get('tag')}`,
      this.get('game'),
      this.nextPage,
      createdAfter
    ).then(resp => {
      return resp.get('firstObject.hits').map(vod => {
        return {
          _id: `v${vod.objectID}`,
          title: vod.title,
          description: vod.description,
          views: vod.views,
          created_at: vod.created_at,
          recordedDate: vod.published_at || vod.created_at,
          game: vod.game,
          length: vod.length,
          preview: vod.thumbnail,
          thumbnails: [
            {
              url: vod.thumbnail,
              type: 'generated'
            }
          ],
          url: `https://www.twitch.tv/videos/${vod.objectID}`,
          channel: {
            name: vod.broadcaster_login,
            display_name: vod.broadcaster_name
          }
        };
      });
    });
  },

  afterSuccess(response) {
    this.nextPage += 1;
    this.setContent(response);
  },

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

DeprecatedVideo.defineCollection('top', {
  api: injectService(),

  startLimit: RESULT_START_LIMIT,
  limit: RESULT_LIMIT,
  period: DEFAULT_PERIOD,
  broadcastType: ALL_VIDEOS_PARAM,

  request() {
    let limit = this.get('content.length') ? this.limit : this.startLimit;
    let opts = {
      limit,
      offset: this.get('content.length'),
      period: this.get('period'),
      language: this.get('language'),
      broadcast_type: this.get('broadcastType'),
      sort: this.get('sort')
    };
    return this.get('api').request('get', 'videos/top', opts);
  },

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

  afterFail() {
    logApiFailure('top videos');
  }
});

export default DeprecatedVideo;
