/* globals Twitch */
import Service from 'ember-service';
import injectService from 'ember-service/inject';
import { libs } from 'web-client/utilities/presence-util';
import { parsePubSubPayload, unmarshallPinnedCheerPayload } from '../utilities/bits/parse-pinned-cheers';
import RSVP from 'rsvp';
import { PINNED_CHEER_TYPES } from 'web-client/utilities/bits/constants-config';

export default Service.extend({
  globals: injectService(),
  bits: injectService(),
  session: injectService(),
  tracking: injectService(),
  tmi: injectService(),

  isEnabled: false,
  channelMinimum: 0,
  channelCheerTimeout: 0,

  recentPinnedCheerA: null,
  recentPinnedCheerB: null,
  recentPinnedCheer: null,
  showRecentCheerA: null,

  topPinnedCheerA: null,
  topPinnedCheerB: null,
  topPinnedCheer: null,
  showTopCheerA: null,

  _messageHandler: null,

  init() {
    this._super(...arguments);
    this._channelId = '';
    this._channelName = '';
  },

  setupService({ channelId, channelName, isChannelEnabled, channelMinimum, channelCheerTimeout }) {
    this._channelId = channelId;
    this._channelName = channelName;

    let isEnabled = isChannelEnabled && this.get('globals.pCheerEnabled');

    this.set('isEnabled', isEnabled);
    this.set('channelMinimum', channelMinimum);
    this.set('channelCheerTimeout', channelCheerTimeout);
    return this._getMostRecentPinnedCheer();
  },

  _getMostRecentPinnedCheer() {
    let channelId = this._channelId;

    if (channelId && this.get('isEnabled')) {

      return this.get('bits').getMostRecentPinnedCheer(channelId).then((data) => {
        if (this.isDestroyed) { return; }

        let isIgnoredPromise = this.get('tmi').isIgnored(data.username);
        return RSVP.all([data, isIgnoredPromise]);
      }).then(([pinnedCheerData, isIgnored]) => {
        if (this.isDestroyed || isIgnored) { return; }

        let messageData = unmarshallPinnedCheerPayload(pinnedCheerData);

        this._updatePinnedCheerData(messageData);

        this._listenForPinnedCheers();
      }).catch((err) => {
        if (this.isDestroyed) { return; }

        return RSVP.reject(err);
      });
    }
    return RSVP.reject();
  },

  _listenForPinnedCheers() {
    let channelId = this._channelId;

    if (this.get('isEnabled') && channelId && libs.pubsub) {
      this._messageHandler = (data) => {
        if (this.isDestroyed) { return; }

        let pubSubMessage = parsePubSubPayload(data);

        this.get('tmi').isIgnored(pubSubMessage.username).then((isIgnored) => {
          if (this.isDestroyed || isIgnored) { return; }

          if (pubSubMessage.channel_id !== String(this._channelId)) {
            this._trackPubSubErrorEvent(channelId, 'mismatch_channels');
            return;
          }

          let messageData = unmarshallPinnedCheerPayload(pubSubMessage);

          this._updatePinnedCheerData(messageData);
        });
      };

      libs.pubsub.Listen({
        topic: `channel-bit-events-public.${channelId}`,
        message: this._messageHandler,
        failure: () => {
          this.set('isEnabled', false);
          this._trackPubSubErrorEvent(channelId, 'listen');
        }
      });
    }
  },

  _unlistenForPinnedCheers(channelId) {
    if (this.get('isEnabled') && channelId && libs.pubsub) {
      libs.pubsub.Unlisten({
        topic: `channel-bit-events-public.${channelId}`,
        message: this._messageHandler,
        failure: () => {
          this._trackPubSubErrorEvent(channelId, 'unlisten');
        }
      });
    }
  },

  _updatePinnedCheerData(dataPayload) {
    if (!this.get('showTopCheerA')) {
      this.set('topPinnedCheerA', dataPayload.top);
      this.set('showTopCheerA', true);
    } else {
      this.set('topPinnedCheerB', dataPayload.top);
      this.set('showTopCheerA', false);
    }

    this.set('topPinnedCheer', dataPayload.top);

    if (dataPayload.top && dataPayload.recent && (dataPayload.top.message_id === dataPayload.recent.message_id)) {
      this._setRecentPinnedCheer(null);
    } else {
      this._setRecentPinnedCheer(dataPayload.recent);
    }
  },

  _setRecentPinnedCheer(newMessage) {
    let currentMessage = this.get('recentPinnedCheer');

    if (currentMessage && newMessage && newMessage.payday_timestamp <= currentMessage.payday_timestamp) {
      return;
    }

    // getting back an expired cheer
    if (newMessage && newMessage.duration === 0 && newMessage.totalDuration !== 0) {
      this.set('recentPinnedCheer', null);
      return;
    }

    if (!this.get('showRecentCheerA')) {
      this.set('recentPinnedCheerA', newMessage);
      this.set('showRecentCheerA', true);
    } else {
      this.set('recentPinnedCheerB', newMessage);
      this.set('showRecentCheerA', false);
    }

    this.set('recentPinnedCheer', newMessage);
  },

  //The settings page's 'Reset Top Cheer' button calls this function, so we need the channelId overwritable.
  //All other instances call this from the channel page, so the channelId is instantiated by bits-room
  dismissMessage(userId, type, channelId = this._channelId) {
    let messageId = '';
    let timeStamp = undefined;

    if (type === PINNED_CHEER_TYPES.TOP) {
      messageId = this.get('topPinnedCheer.message_id');
    } else if (type === PINNED_CHEER_TYPES.RECENT) {
      messageId = this.get('recentPinnedCheer.message_id');
      timeStamp = this.get('recentPinnedCheer.payday_timestamp');
    }

    return this.get('bits').dismissPinnedCheer({
      channelId,
      messageId,
      type,
      timeStamp,
      userId: String(userId)
    });
  },

  canDismissPinnedCheer(userId, isModeratorOrHigher, type) {
    if (!this.get('isEnabled') || (!this.get('recentPinnedCheer') && !this.get('topPinnedCheer')) || !userId) {
      return false;
    }

    let currentMessageId = type === 'recent' ? this.get('recentPinnedCheer.id') : this.get('topPinnedCheer.id');
    return (String(userId) === currentMessageId) || isModeratorOrHigher;
  },

  //Here so that BTTV and FFZ can allow users to dismiss pinned cheers locally
  dismissLocalMessage() {
    let context;
    let paydayTimestamp;
    let messageId;

    if (this.get('recentPinnedCheer')) {
      messageId = this.get('recentPinnedCheer.message_id');
      context = 'recent';
      paydayTimestamp = this.get('recentPinnedCheer.payday_timestamp');
      this.set('recentPinnedCheer', null);
    } else {
      messageId = this.get('topPinnedCheer.message_id');
      context = 'top';
      this.set('topPinnedCheer', null);
    }

    let event = 'bits_pin_hide';
    let data = {
      login: this.get('session.userData.login'),
      user_id: this.get('session.userData.id'),
      channel: this._channelName,
      channel_id: this._channelId,
      transaction_id: messageId,
      pinned_payday_time: paydayTimestamp,
      context
    };

    this.get('tracking').trackEvent({ event, data });
  },

  expireRecentMessage(message) {
    let currentRecentCheer = this.get('recentPinnedCheer');

    if (currentRecentCheer && message.payday_timestamp === currentRecentCheer.payday_timestamp) {
      this.set('recentPinnedCheer', null);
    }
  },

  _trackPubSubErrorEvent(channelId, type) {
    let session = this.get('session');
    let login = '';
    let loginId = '';

    if (session.isAuthenticated && session.userData) {
      login = session.userData.name;
      loginId = session.userData.id;
    }

    let eventData = {
      device_id: Twitch.idsForMixpanel.getOrCreateUniqueId(),
      login: login,
      login_id: loginId,
      channel_id: channelId,
      type: type
    };

    this.get('tracking').trackEvent({
      event: 'bits_pin_cheer_pubsub_error',
      data: eventData
    });
  },

  reset() {
    this._unlistenForPinnedCheers(this._channelId);
    this._channelId = '';
    this._channelName = '';
    this._messageHandler = null;
    this.set('isEnabled', false);
    this.set('channelMinimum', 0);
    this.set('channelCheerTimeout', 0);

    this.set('recentPinnedCheerA', null);
    this.set('recentPinnedCheerB', null);
    this.set('recentPinnedCheer', null);
    this.set('showRecentCheerA', null);

    this.set('topPinnedCheerA', null);
    this.set('topPinnedCheerB', null);
    this.set('topPinnedCheer', null);
    this.set('showTopCheerA', null);
  }
});
