/* globals Twitch, window */

import $ from 'jquery';
import observer from 'ember-metal/observer';
import Model from 'web-client/models/core/model';
import ChannelSerializer from 'web-client/models/core/serializers/channel-serializer';
import ChannelViewerModel from 'web-client/models/channel-viewer';
import RoomModel from 'web-client/models/room';
import PanelModel from 'web-client/models/panel';
import StreamModel from 'web-client/models/deprecated-stream';
import TicketProductModel from 'web-client/models/ticket-product';
import DeprecatedVideo from 'web-client/models/deprecated-video';
import computed from 'ember-computed';
import injectService from 'ember-service/inject';
import on from 'ember-evented/on';
import run from 'ember-runloop';
import logApiFailure from 'web-client/utilities/log-api-failure';
import { htmlSafe } from 'ember-string';
import { ALL_VIDEOS_TYPE } from 'web-client/mixins/video-type';

let ChannelModel = Model.extend({
  tmiService: injectService('tmi'),
  globals: injectService(),
  api: injectService(),
  store: injectService(),

  expiration: 60000, // 1 minute

  /** relations */
  room: computed(function () {
    return RoomModel.findOne(this.get('id'));
  }),

  highlights: computed(function () {
    return DeprecatedVideo.find('channel', {channel: this.get('id')});
  }),

  pastBroadcasts: computed(function () {
    return DeprecatedVideo.find('channel', {channel: this.get('id'), pastBroadcasts: true});
  }),

  videos: computed(function () {
    return DeprecatedVideo.find('channel', {channel: this.get('id'), broadcastType: ALL_VIDEOS_TYPE });
  }),

  stream: computed(function () {
    return StreamModel.findOne(this.get('id'));
  }),

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

  newChannel: computed('isLoading', function() {
    if (this.get('isLoading')) {
      return null;
    }
    return this.get('store').findRecord('channel', this.get('name'));
  }),

  followersTotal: computed.readOnly('newChannel.followersTotal'),

  relatedChannels: computed(function () {
    return StreamModel.find('related', {channel: this.get('id')});
  }),

  panels: computed(function () {
    return PanelModel.find('user', {user: this.get('id')});
  }),

  product: computed(function () {
    return TicketProductModel.findOne(this.get('id'));
  }),

  /** public methods */
  serializer: ChannelSerializer.create(),

  apiLoad() {
    return this.get('api').request('get', `/api/channels/${this.get('id')}/ember`).then(data => {
      if (!this.isDestroyed) {
        let store = this.get('store');
        let serializer = store.serializerFor('channel');
        store.push(serializer.normalizeFindRecordResponse(store, 'channel', data, data._id));
      }
      return data;
    });
  },

  afterFail: on('loadFail', function (e) {
    if (e.status === 422 && e.responseText.match(/.is unavailable/gi)) {
      this.set('unavailable', true);
    } else if (e.status === 422 && e.responseText.match(/.*not available on Twitch/gi)) {
      this.set('nonGaming', true);
    } else if (e.status === 301) {
      this.set('redirectChannel', JSON.parse(e.responseText).message);
    } else {
      logApiFailure('stream');
    }
  }),

  /*
    The saving mixin implicitly requires a $.Deferred (expects .done to be available)
    The writeback in the saving mixin will clobber properties if data is not filtered here.

    TODO: Because this is a temporary fix while CSRF issues are investigated,
    this needs to be removed once those issues are resolved.
  */
  apiSave(data) {
    let ALLOWED_WRITEBACK_PROPERTIES = ['status', 'game', 'broadcaster_language'];
    let channelResponse;

    return this.get('api')
      .request('put', `channels/${this.get('id')}`, {channel: data})
      .then(response => {
        if (this.isDestroyed) { return; }
        channelResponse = response;
        // TODO: Is this an Ember.RSVP.Promise?
        return this.get('tmiService.tmiSession');
      })
      .then(tmiSession => {
        if (this.isDestroyed) { return; }
        return tmiSession.updateChannel(this.get('id'),
          {broadcaster_language_enabled: this.get('isLanguageRestricted')});
      })
      .then(() => {
        if (this.isDestroyed) { return; }
        return ALLOWED_WRITEBACK_PROPERTIES.reduce(function (memo, val) {
          memo[val] = channelResponse[val];
          return memo;
        }, {});
      });
  },

  /** computed properties */
  displayName: computed.alias('display_name'),

  broadcasterLanguage: computed.alias('broadcaster_language'),

  teamHref: computed(function () {
    // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
    if (this.primary_team_name) {
      return Twitch.uri.team(this.primary_team_name);
    }
    // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
  }),

  gameUrl: computed('game', function () {
    return Twitch.uri.game(this.get('game'));
  }),

  gameBoxart: computed('game', function () {
    return Twitch.uri.gameBoxArtJpg(this.get('game'));
  }),

  viewer: computed(function() {
    // TODO: Want to revisit loading to ensure this is in a sane place
    let v = ChannelViewerModel.findOne(this.get('name'));
    run.scheduleOnce('afterRender', this, '_loadViewer', v);
    return v;
  }),

  _loadViewer(channelViewer) {
    channelViewer.load();
  },

  _hostModeLoaded: observer('hostModeTargetLoading', 'hostModeTargetLoading.isLoading',
    'hostModeTargetLoading.isLoaded', function () {
    if (this.get('hostModeTargetLoading.isLoaded')) {
      this.set('hostModeTarget', this.get('hostModeTargetLoading'));
      this.set('hostModeTargetLoading', undefined);
    }
  }),

  /** public interface */

  destroy() {
    run.cancel(this._setHostModeTimeout);
    this._super();
  },

  isHostMode: computed.bool('hostModeTarget'),

  // Enables Broadcaster Language Chat, which restricts chat to viewers of the same language as the broadcast
  isLanguageRestricted: computed('broadcaster_language', function() {
    let langCode = this.get('broadcaster_language');
    return this._isDefaultBLCLanguage(langCode);
  }),

  isLanguageOther: computed('broadcaster_language', function() {
    let isOther = this.get('broadcaster_language') === 'other';
    return htmlSafe(isOther.toString());
  }),

  _isDefaultBLCLanguage: function (langCode) {
    let globals = this.get('globals'),
        defaultBLCLanguages = globals.get('defaultBLCLanguages');

    return $.inArray(langCode, defaultBLCLanguages) >= 0;
  }
});

export default ChannelModel;
