/*global adnxs, googletag, console*/
/*jshint bitwise:false*/

(function (Twitch, $) {
  var asyncAds = {enabled: false};

  asyncAds.ready = Twitch.ads.ready;

  asyncAds.enable = function () {
    this.enabled = true;
  };

  asyncAds.megatag = function () {
    if (!this._megatagPromise) {
      this._megatagPromise = new RSVP.Promise(function (resolve) {
        $.getScript('/javascripts/libs/megatag.js', function () {
          if (typeof adnxs !== 'undefined') {
            resolve(adnxs.megatag);
          }
        });
      });
    }
    return this._megatagPromise;
  };

  asyncAds.metadata = {
    game: '',
    dfpPageType: '',
    campaign: '',
    kuid: ''
  };

  asyncAds.setMetadata = function (key, value) {
    switch (key) {
    case 'game':
      value = (value || '').replace(/[^A-Za-z0-9]+/g, '_'); // Keep regex in sync with game_list_report
      Twitch.asyncAds.metadata.game = value;
      break;
    case 'chan':
      Twitch.asyncAds.metadata.chan = value;
      break;
    case 'dfpPageType':
      Twitch.asyncAds.metadata.pagetype = value;
      break;
    case 'campaign':
      Twitch.asyncAds.metadata.campaign = value;
      break;
    case 'kuid':
      Twitch.asyncAds.metadata.kuid = value;
      break;
    }
  };

  var getAdSlots = _.memoize(function () {
    return {
      'dfp-directory-banner':     {sizes: [[970, 66], [728, 90], [970, 250]], unitName: '/' + Twitch.ads.dfpNetworkCode + '/twitch/directory'},
      'dfp-directory-rectangle':  {sizes: [[300, 250]], unitName: '/' + Twitch.ads.dfpNetworkCode + '/twitch/directory'},
      'google_companion_300x250': {sizes: [[300, 250]], unitName: '/' + Twitch.ads.dfpNetworkCode + '/twitch/channels'},
      'dfp-channel-adlight': {sizes: [[239, 80]], unitName: '/' + Twitch.ads.dfpNetworkCode + '/twitch/ad_light'}
    };
  });

  asyncAds.fetchAds = function (options) {
    var ads = Twitch.ads._readyData;
    $('#dfp-directory-banner, .ad_contain').hide();
    if (this.enabled && ads && ads.enabled) {
      var slots = ['dfp-directory-banner'];
      if (!options || !options.singleOnly) slots.push('dfp-directory-rectangle');
      Twitch.asyncAds.sra({slots: slots})
      .then(function (slots) {
        if (slots[0]) {
          $('#dfp-directory-banner').show();
        }
        if (slots[1]) {
          // override !important hiding style to show this element
          $('.ad_contain').show().attr('style', 'display: block !important');
        }
      });
    }
  };

  asyncAds.resetGoogletag = function () {
    if (googletag) {
      googletag.destroySlots();
      var pubads = googletag.pubads();
      pubads.getTargetingKeys().forEach(function(key) {
        pubads.clearTargeting(key);
      });
    }

    return RSVP.resolve();
  };

  asyncAds.prepareCompanionAds = function (options) {
    return new RSVP.Promise(function (resolve, reject) {
      Twitch.ads.ready(function(adData) {
        if (asyncAds.enabled && adData && adData.enabled) {

          asyncAds.resetGoogletag().then(function () {
            // set up the slots
            var adSlots = getAdSlots();
            googletag.cmd.push(function () {
              options.slots.forEach(function (slotId) {
                googletag.defineSlot(
                  adSlots[slotId].unitName,
                  adSlots[slotId].sizes,
                  slotId).addService(googletag.companionAds()
                );
              });
              // todo: this doesn't really belong in companionads
              // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
              if (SiteOptions.dfp_sidebar_channel_ad) {
                googletag.defineSlot(
                  adSlots['dfp-channel-adlight'].unitName,
                  adSlots['dfp-channel-adlight'].sizes,
                  'dfp-channel-adlight').addService(googletag.pubads()
                );
              }
              googletag.pubads().collapseEmptyDivs();
              googletag.enableServices();
            });
            resolve();
          }, resolve);

        } else {
          resolve();
        }
      })
    });
  };

  asyncAds.displayAdLight = function () {
    googletag.cmd.push(function () {
      googletag.pubads().clearTargeting();
      googletag.pubads().setTargeting("game", Twitch.asyncAds.metadata.game);
      googletag.pubads().setTargeting("chan", Twitch.asyncAds.metadata.chan);
      googletag.pubads().setTargeting("pagetype", Twitch.asyncAds.metadata.pagetype);
      googletag.pubads().setTargeting("campaign", Twitch.asyncAds.metadata.campaign);
      googletag.pubads().setTargeting("kuid", Twitch.asyncAds.metadata.kuid);
      googletag.pubads().setTargeting("server", Twitch.deployFlavor);
      googletag.pubads().setTargeting("salt", window.location.protocol === 'https:' ? 'true' : 'false');
      googletag.pubads().setTargeting("loggedin", Twitch.user.isLoggedIn() ? 'true' : 'false');
      googletag.display('dfp-channel-adlight');
    });
  };

  asyncAds.afterCompanionAdsRendered = function (provider) {
    if ($('.js-new-channel-ad').length) {
      if (provider === "google") {
        $(".new_advertisement").hide();
        $("#google_companion_300x250").hide();

        if (!$("#google_companion_300x250").is(":empty")) {
          $("#google_companion_300x250").show();
        }

      }
      $('.js-ad-actions').show();
      $(".new_advertisement").show();
      Twitch.asyncAds.resizeForCompanionAds(10);
    }
  };

  asyncAds.resizeForCompanionAds = function(retries) {
    // let the rendering finish
    // Some ads take longer to render, but the close button will appear
    // if we are less than our shortest companion, wait and check again
    setTimeout(function () {
      var h = $('.js-new-channel-ad').outerHeight();
      // if the height is too short, or we've run out of retries
      if (retries > 0 && h < 60) {
        Twitch.asyncAds.resizeForCompanionAds(retries - 1);
      } else {
        $('.js-rightcol-content').css('top', h);
      }
    }, 100);
  }

  asyncAds.sra = function (options) {

    var getScope = function () {
      // resets the slots for this ad call
      if (this.slots) this.slots.forEach(function (slot) { if (slot.el) slot.el.empty(); });
      var self = this,
          slots = this.slots = [];
      // returns a function which transforms fn to a function that executes only if it's for current slots
      return function (fn) {
        return function () {
          if (slots === self.slots) return fn.apply(this, arguments);
        };
      };
    };

    var events = function () {
      // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
      if (googletag.debug_log._events) return googletag.debug_log._events;
      // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
      var oldLog = googletag.debug_log.log,
          events = RSVP.EventTarget.mixin({});
      // todo: investigate a better way to detect gpt ad events
      // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
      googletag.debug_log.log = function (level, message, service, slot, reference) {
        // messageId 6 is "Completed rendering ad for slot ..."
        // reference: https://github.com/mcountis/dfp-events/issues/4
        if (message.getMessageId() === 6) { events.trigger('gpt-slot_rendered'); }
        return oldLog.apply(this, arguments);
      };
      // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
      googletag.debug_log._events = events;
      return events;
    };

    var display = function (options) {
      var self = this,
          scope = getScope();
      return new RSVP.Promise(function (resolve, reject) {
        asyncAds.resetGoogletag().then(scope(function () {
          var adSlots = getAdSlots();
          // set up the slots
          googletag.cmd.push(function () {
            options.slots.forEach(function (slotId) {
              self.slots.push({id: slotId, el: $('#' + slotId)});
              googletag.defineSlot(
                adSlots[slotId].unitName,
                adSlots[slotId].sizes,
                slotId).addService(googletag.pubads()
              );
            });

            // wait for the event gpt-slot_rendered the correct number of times
            events().on('gpt-slot_rendered', _.after(options.slots.length, function () {
              resolve(_.map(self.slots, function (slot) {
                return slot.el.css('display') !== 'none';
              }));
            }));

            // Set metadata
            googletag.pubads().clearTargeting();
            googletag.pubads().setTargeting("game", Twitch.asyncAds.metadata.game);
            googletag.pubads().setTargeting("pagetype", Twitch.asyncAds.metadata.pagetype);
            googletag.pubads().setTargeting("campaign", Twitch.asyncAds.metadata.campaign);
            googletag.pubads().setTargeting("kuid", Twitch.asyncAds.metadata.kuid);
            googletag.pubads().setTargeting("server", Twitch.deployFlavor);
            googletag.pubads().setTargeting("salt", window.location.protocol === 'https:' ? 'true' : 'false');
            googletag.pubads().setTargeting("loggedin", Twitch.user.isLoggedIn() ? 'true' : 'false');

            // trigger the SRA ad call
            googletag.pubads().enableSingleRequest();
            googletag.pubads().collapseEmptyDivs();
            googletag.enableServices();
            _.each(options.slots, function(slot) {
              googletag.display(slot);
            });
          });

        }), reject);
      });
    };
    return display(options);
  };

  Twitch.mixin({
    asyncAds: asyncAds
  });

})(Twitch, jQuery);

