/*global chrome */
(function (Twitch, $) {
  var chromecast = {};
  chromecast.player = null;

  var pausedFor = null;
  var currentMedia = null;
  var session = null;
  var initSuccess = false;
  var devicesAvailable = false;

  var initializeCastApi = function () {
    if (initSuccess && devicesAvailable && session) {
      chromecast.player.showChromecast(true);
      chromecast.player.setChromecastConnected(true, session.receiver.friendlyName);
    } else {
      var sessionRequest = new chrome.cast.SessionRequest('358E83DC');
      var apiConfig = new chrome.cast.ApiConfig(sessionRequest,
        sessionListener,
        receiverListener,
        chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED
      );

      chrome.cast.initialize(apiConfig, onInitSuccess, onError);
    }
  };

  var onInitSuccess = function () {
    initSuccess = true;
    if (initSuccess && devicesAvailable) {
      chromecast.player.showChromecast(true);
    }
  };

  var onError = function (e) {
    if (e.code === 'session_error') {
      disconnectChromecast();
    }
  };

  var sessionListener = function (s) {
    // Connecting to a pre-existing chromecast session
    session = s;
    session.addUpdateListener(sessionUpdateListener);

    if (session.media.length !== 0) {
      onMediaDiscovered('sessionListener', session.media[0]);
    }

    chromecast.player.setChromecastConnected(true, session.receiver.friendlyName);
  };

  var receiverListener = function (availability) {
    if (availability === chrome.cast.ReceiverAvailability.AVAILABLE) {
      devicesAvailable = true;
      if (initSuccess && devicesAvailable) {
        chromecast.player.showChromecast(true);
      }
    } else {
      devicesAvailable = false;
      chromecast.player.showChromecast(false);
    }
  };

  var sessionUpdateListener = function (isAlive) {
    if (!isAlive) {
      disconnectChromecast();
    }
  };

  var disconnectChromecast = function () {
    if (session) {
      session.removeUpdateListener(sessionUpdateListener);
    }
    if (currentMedia) {
      currentMedia.removeUpdateListener(mediaUpdateListener);
    }

    session = null;
    currentMedia = null;
    chromecast.player.setChromecastConnected(false);
  };

  var onRequestSessionSuccess = function (s) {
    session = s;
    session.addUpdateListener(sessionUpdateListener);
    chromecast.player.setChromecastConnected(true, session.receiver.friendlyName);
  };

  var onMediaDiscovered = function (how, media) {
    currentMedia = media;
    currentMedia.addUpdateListener(mediaUpdateListener.bind(this, media));
  };

  var mediaUpdateListener = function (media, isAlive) {
    if (!isAlive) {
      media.removeUpdateListener(mediaUpdateListener);

      if (media.media.customData.channel.toUpperCase() === window.location.pathname.substring(1).toUpperCase()) {
        // Two cases:
        // 1. resumed same channel, killing old media. This shouldn't resume local playback.
        // 2. another channel was launched on chromecast, killing local media. This should resume local playback.
        if (pausedFor && pausedFor === media.media.customData.channel) {
          pausedFor = "";
          chromecast.player.togglePlayPause(false);
        } else {
          chromecast.player.setChromecastConnected(false);
        }
      }
    } else if (session.media.length && media === session.media[0]) {
      if (media.playerState === chrome.cast.media.PlayerState.PAUSED) {
        pausedFor = media.media.customData.channel;
        chromecast.player.togglePlayPause(true);
      } else if (media.playerState === chrome.cast.media.PlayerState.PLAYING) {
        chromecast.player.togglePlayPause(false);
      }
    }
  };

  chromecast.initialize = function (player) {
    player.on('videoPlaying', _.once(function () {
      if (typeof chrome !== 'undefined' && chrome.cast && chrome.cast.isAvailable) {
        chromecast.player = player;
        initializeCastApi();
      }
    }));

    player.on('chromecastSessionRequested', function () {
      chrome.cast.requestSession(onRequestSessionSuccess, onError);
    });

    player.on('chromecastMediaSet', function (data) {
      // Don't restart playback if already playing stream remotely
      if (session.media.length !== 0 && currentMedia &&
          currentMedia.media.customData.channel &&
          currentMedia.media.customData.channel.toUpperCase() === data.channel.toUpperCase()) {
        return;
      }

      var mediaInfo = new chrome.cast.media.MediaInfo(data.url, 'application/x-mpegurl');
      mediaInfo.streamType = chrome.cast.media.StreamType.LIVE;
      var metadata = new chrome.cast.media.GenericMediaMetadata();

      Twitch.api.get('streams/' + data.channel).then(function (response) {
        if (response.stream) {
          var stream = response.stream;
          if (stream.game) {
            metadata.subtitle = stream.game;
          }
          if (stream.channel) {
            if (stream.channel.display_name) {
              metadata.title = stream.channel.display_name;
            }
            if (stream.channel.logo) {
              metadata.images = [new chrome.cast.Image(stream.channel.logo)];
            } else {
              metadata.images = [new chrome.cast.Image(stream.preview.medium)];
            }
          }

          mediaInfo.metadata = metadata;
          mediaInfo.customData = {
            'channel': data.channel,
            'analytics': data.analytics
          };

          var request = new chrome.cast.media.LoadRequest(mediaInfo);
          request.autoplay = true;
          session.loadMedia(request, onMediaDiscovered.bind(this, 'loadMedia'), onError);
        }
      });
    });

    player.on('chromecastVolumeUpdated', function (data) {
      if (session) {
        session.setReceiverVolumeLevel(data.volume, null, onError);
      }
    });

    player.on('pauseChromecastSession', function () {
      if (currentMedia) {
        pausedFor = currentMedia.media.customData.channel;
        currentMedia.pause(new chrome.cast.media.PauseRequest(), null, null);
        currentMedia = null;
      }
    });
  };

  Twitch.mixin({
    chromecast: chromecast
  });

})(Twitch, jQuery);
