/* globals URI, Twitch */

import $ from 'jquery';
import run from 'ember-runloop';
import computed from 'ember-computed';
import Component from 'ember-component';
import injectService from 'ember-service/inject';
import Mousetrap from 'mousetrap';
import { assert } from 'ember-metal/utils';
import { isPresent } from 'ember-utils';

const RECOMMENDATION_TYPE_RECENT = 'recent';

/*
 *  Optional:
 *    channel object
 *    shouldStartPaused
 *    isTheatreMode
 *    canGenerateClips
 */

export default Component.extend({
  classNames: ['js-twitch-player-2'],
  layout: injectService(),
  playerRegistry: injectService(),
  tracking: injectService(),
  vodChatService: injectService('vod-chat-service'),
  playerRemoteControl: injectService(),

  canGenerateClips: null,
  channel: null,
  hasMiniControls: false,
  player: null,
  playerIsPersistent: false,
  showCompanionAds: true,
  userSetPlayerToPause: false,
  video: null,

  onPlayerInit() { },

  init() {
    this._super(...arguments);

    // Allow Player injection
    if (!this.Player) {
      this.Player = Twitch.video.Player;
    }

    this.get('playerRegistry').add(this);
  },

  click(e) {
    let classList = e.target.classList;
    let pauseButton = 'js-control-playpause-button';
    for (let i = 0; i < classList.length; i++) {
      if (classList[i] === pauseButton) {
        this.set('userSetPlayerToPause', true);
      }
    }
  },

  didReceiveAttrs() {
    this._super(...arguments);

    assert(`${this} requires argument "canGenerateClips"`, isPresent(this.get('canGenerateClips')));

    this._hostChannelName = this.get('hostChannel.hostModeTarget') ? this.get('hostChannel.name') : undefined;

    let newChannelId = this.get('channel.id');
    let newVideoId = this.get('video');
    let player = this.get('player');

    if (player) {
      if (newVideoId === null && newChannelId !== this.previousChannelId) {
        player.setChannel(newChannelId);
      }

      if (newVideoId === null && this.previousVideoId !== null) {
        player.setChannel(newChannelId);
      } else if (newVideoId !== this.previousVideoId) {
        player.setVideo(newVideoId);
      }

      player.setTrackingProperties({ host_channel: this._hostChannelName });

      if (this.get('playerIsPersistent')) {
        player.setMiniPlayerMode(this.get('hasMiniControls'));

        if (player.getTheatre() === true) {
          player.setTheatre(!this.get('hasMiniControls'));
        }
      }
    }

    // Stash values for next hook call
    this.previousChannelId = newChannelId;
    this.previousVideoId = newVideoId;
  },

  benchmarkId: computed(function() {
    return this.get('tracking.benchmark') ? this.get('tracking.benchmark').getSession() : null;
  }),

  didInsertElement() {
    let queryParams = new URI().query(true);

    // Only set the host_channel tracking property if hosting is currently happening
    let playerObject = {
      branding: false,
      player: this.get('playerType') || 'site',
      tracking: { host_channel: this._hostChannelName },
      autoplay: !this.get('shouldStartPaused'),
      channelInfo: false,
      controls: true,
      height: '100%',
      width: '100%',
      showtheatre: this.get('showTheatre') || false,
      showInfo: this.get('showInfo') || false,
      t: queryParams.t,
      benchmarkId: this.get('benchmarkId')
    };

    if (this.get('video')) {
      playerObject.video = this.get('video');
    } else {
      playerObject.channel = this.get('channel.id');
    }

    if (this.get('collection')) {
      playerObject.collection = this.get('collection');
    }

    this.attachPlayer(playerObject);
  },

  attachPlayer(playerObject) {
    let player = new this.Player('player', playerObject);
    this.set('player', player);

    this.get('tracking.benchmark').track('player_rendered');

    this.attachEventListeners();
    this.setupCompanionAds();
    this.postPlayerSetup();
    this.shortcutSetup();

    this.get('onPlayerInit')(this);
    this.get('playerRemoteControl').attachPlayer(player);
  },

  willDestroyElement() {
    if (this.get('channel')) {
      this.set('channel.playerIsLive', undefined);
      this.set('channel.playerIsPlaylist', undefined);
    }

    let player = this.get('player');
    if (player) {
      player.destroy();
    }

    let layout = this.get('layout');
    layout.off('searchWasActivated', this, '_exitTheatreModeWhenSearching');

    Mousetrap.unbind('alt+t');
    Mousetrap.unbind('esc');
    Mousetrap.unbind('alt+x');

    layout.setTheatreMode(false);
  },

  willDestroy() {
    this._super(...arguments);
    this.get('playerRegistry').remove(this);
  },

  _exitTheatreModeWhenSearching() {
    let player = this.get('player');
    if (player && player.getTheatre() === true) {
      player.setTheatre(false);
    }
  },

  setupCompanionAds() {
    if (this.get('showCompanionAds')) {
      let companionAdsPrepared = Twitch.asyncAds.prepareCompanionAds({
        slots: ['google_companion_300x250']
      });

      companionAdsPrepared.then(() => {
        Twitch.asyncAds.setMetadata('chan', this.get('channel.name'));
        Twitch.asyncAds.setMetadata('game', this.get('channel.game'));
        Twitch.asyncAds.displayAdLight();
        $('.advertisement.new_advertisement .a300').hide();
      });
    }
  },

  trackMiniPlayerAction(action, reason) {
    let player = this.get('player');

    if (player) {
      player.trackMiniPlayerAction(action, reason);
    }
  },

  attachEventListeners() {
    let layout = this.get('layout');
    let player = this.get('player');

    let addRunLoopedEventListener = (name, callback) => {
      player.addEventListener(name, run.bind(this, callback));
    };

    addRunLoopedEventListener('viewerschange', () => {
      if (this.get('channel.stream')) {
        this.set('channel.stream.viewers', player.viewers);
      }
    });

    addRunLoopedEventListener('timeupdate', () => {
      if (player.getVideo()) {
        this.get('vodChatService').tick(player.getCurrentTime() * 1000);
      }
    });

    addRunLoopedEventListener('seeking', () => {
      this.get('vodChatService').seek(player.getCurrentTime() * 1000);
    });

    addRunLoopedEventListener('online', () => {
      this.set('channel.playerIsLive', true);
    });

    addRunLoopedEventListener('ended', () => {
      this.set('channel.playerIsLive', false);
    });

    addRunLoopedEventListener('offline', () => {
      this.set('channel.playerIsLive', false);
    });

    addRunLoopedEventListener('isspectre', (e) => {
      this.set('channel.playerIsPlaylist', e);
    });

    addRunLoopedEventListener('adcompanionrendered', function() {
      Twitch.asyncAds.afterCompanionAdsRendered('google');
    });

    addRunLoopedEventListener('theatrechange', () => {
      /**
        This is non obvious but the internals of the player actually emit this
        event before the state is changed, so we must negate the current value.

        self.setTheatre = function(value) {
            onTheatreToggle();
            theatre = value;
        };

        can remove the `!` after https://twitchtv.atlassian.net/browse/VP-696
      */
      layout.setTheatreMode(!player.getTheatre());
    });

    addRunLoopedEventListener('pause', () => {
      this.sendAction('videoPaused');
    });

    addRunLoopedEventListener('play', () => {
      this.set('userSetPlayerToPause', false);
      this.sendAction('videoPlayed');
    });

    addRunLoopedEventListener('fullscreenchange', () => {
      if (!player.fullscreen) {
        this.sendAction('handleExitFullscreen');
      }
    });

    addRunLoopedEventListener('transitiontovod', (video) => {
      video = video[0];
      video.id = video._id;
      video.isPlayerRecommendation = true;
      video.playerRecommendationType = RECOMMENDATION_TYPE_RECENT;
      let applicationRoute = this.container.lookup('route:application');
      let actionHandler = applicationRoute.actions['handleVideoClick'];
      actionHandler.call(applicationRoute, video);
    });

    addRunLoopedEventListener('contentShowing', () => {
      this.sendAction('videoPlayerContentShowing');
    });

    addRunLoopedEventListener('persistentPlayerEnableToggle', () => {
      this.get('persistenceUpdateHandler')();
    });

    layout.on('searchWasActivated', this, '_exitTheatreModeWhenSearching');
  },

  postPlayerSetup() {
    if (this.get('channel')) {
      this.set('channel.playerIsLive', undefined);
      this.set('channel.playerIsPlaylist', undefined);
    }
  },

  shortcutSetup() {
    let player = this.get('player');
    if (player) {
      Mousetrap.bind('alt+t', () => {
        player.setTheatre(!player.getTheatre());
        return false;
      });

      Mousetrap.bind('esc', () => {
        let activeElement = document.activeElement;
        if (player.getTheatre() && activeElement.tabIndex !== 2) {
          player.setTheatre(false);
        }
      });

      Mousetrap.bind('alt+x', () => {
        run(() => {
          if (this.get('canGenerateClips') && typeof player.recordClip === 'function') {
              player.recordClip();
          }
        });
      });
    }
  },

  shouldDynamicTargetPlayer: computed('hostChannel.hostModeTarget', 'layout.isTheatreMode', function() {
    return !!this.get('hostChannel.hostModeTarget') && !this.get('layout.isTheatreMode');
  }),

  pause() {
    this.get('player').pause();
  },

  play() {
    this.get('player').play();
  },

  getCurrentTime() {
    return this.get('player').getCurrentTime();
  },

  getEnded() {
    return this.get('player').getEnded();
  },

  getPaused() {
    return this.get('player').getPaused();
  },

  setCurrentTime(time) {
    this.get('player').setCurrentTime(time);
  }
});
