/*jshint browser:true, bitwise:false */
/*global console */

//= require rsvp
//= underscore

//= require ./index.js

(function (Twitch, $) {

  var ContextLoader = function (channel, streamUrl) {
    this.channel = channel;
    this.stream = streamUrl;
  };

  // NOTE that since we are using RSVP all() that if any of these methods fail then they all fail.
  // To hack around this we are currently no rejecting failures but rather providing defaults.
  var _loadDataAndTransform = function (endpoint, transformMap) {
    return new RSVP.Promise(function (resolve, reject) {
      Twitch.api.get(endpoint)
        .done(function (data) {
          resolve(_.reduce(transformMap, function (result, destKey, srcKey) {
            if (typeof destKey === "function") {
              var transformedKeyValue = destKey(data[srcKey] || "");
              if (transformedKeyValue) {
                result[transformedKeyValue.key] = transformedKeyValue.val;
              }
            } else {
              if (_.has(data, srcKey)) {
                result[destKey] = data[srcKey];
              }
            }
            return result;
          }, {}));
        })
        .fail(function (context) {
          resolve({});
        });
    });
  };

  var _loadChannelContext = function (channel) {
    return _loadDataAndTransform("/api/channels/" + channel, {
      "partner" : "partner",
      "name" : "channel",
      "broadcaster_software" : "broadcaster_software",
      "game" : function (game) {
        return {
          "key" : "game",
          "val" : game || "None"
        };
      }
    });
  };

  var _loadTeamInfo = function (channel) {
    // the teams info is only accessible via kraken...
    return _loadDataAndTransform("channels/" + channel, {
      "teams" : function (teams) {
        if (_.isArray(teams) && teams.length > 0 && _.has(teams[0], "name")) {
          return {
            "key" : "team",
            "val" : teams[0].name
          };
        }
      }
    });
  };

  var _loadViewerInfo = function () {
    return _loadDataAndTransform("/api/viewer/info.json", {
      "login" : function (value) {
        return {
          "key" : "login",
          "val" : value
        };
      },
      "turbo" : function (value) {
        return {
          "key" : "turbo",
          "val" : !!value
        };
      }
    });
  };

  var _loadChannelViewerInfo = function (channel) {
    return _loadDataAndTransform("/api/channels/" + channel + "/viewer", {
      "chansub" : function (value) {
        return {
          "key" : "subscriber",
          "val" : !!value
        };
      }
    });
  };

  var _loadStreamInfo = function (streamUrl) {
    return new RSVP.Promise(function (resolve, reject) {
      $.ajax({
        method : "GET",
        url : streamUrl,
        cache: false,
        headers: {
          'Client-ID': Twitch.api.config.clientID
        },
        success : function (data) {
          var clusterMatch = data.match(/nname=([^,&]+)[,&]/);
          if (clusterMatch.length > 1) {
            var nodeAndCluster = clusterMatch[1].split(".");
            if (nodeAndCluster.length > 1) {
              resolve({
                node : clusterMatch[1],
                cluster : nodeAndCluster[1]
              });
            }
          } else {
            console.warn("no match found for clusterPattern.");
            resolve({});
          }
        },
        error : function () {
          console.warn("error in fetching stream data");
          resolve({});
        }
      });
    });
  };

  ContextLoader.prototype.load = function (additionalProperties) {
    var promises = [],
        channel = this.channel,
        streamUrl = this.stream;
    console.info("pulling Context info");
    promises.push(_loadChannelContext(channel));
    promises.push(_loadTeamInfo(channel));
    promises.push(_loadViewerInfo());
    promises.push(_loadChannelViewerInfo(channel));
    promises.push(_loadStreamInfo(streamUrl));

    return RSVP.all(promises).then(function (properties) {
      var basicProperties = additionalProperties || {};
      console.info("Combining properties...");
      _.each(properties, function (property) {
        _.extend(basicProperties, property);
      });
      return basicProperties;
    }, function (error) { console.error(error); });
  };

  Twitch.player.ContextLoader = ContextLoader;

})(Twitch, jQuery);
