/* globals uuid, PromiseThrottle */
import Service from 'ember-service';
import injectService from 'ember-service/inject';
import { parseTotalBits } from '../utilities/bits/parse-total-bits';
import RSVP from 'rsvp';

const WEB_CLIENT_CLIENT_ID = 'jzkbprff40iqj646a697cyrvl0zt2m6';

/*
  Bits Service.
  Responsible for loading, storing, and using the logged in user's Bits balance.
  Also loads the Bits parsing configuration and provides helper methods for use in parsing Bits messages.
*/
export default Service.extend({
  session: injectService(),
  api: injectService(),
  tracking: injectService(),
  ajax: injectService(),
  crypto: injectService(),
  globals: injectService(),
  bitsEmotes: injectService(),

  balance: null,
  channelTotal: 0,
  promoAmount: 500,
  promoProduct: 'B01LZ42ZK9',

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

    this._sendBitsThrottler = new PromiseThrottle({
      requestsPerSecond: 1,
      promiseImplementation: RSVP.Promise
    });
  },

  _trackLatency(event, promise) {
    let startTime = new Date().getTime();

    promise.then(() => {
      if (this.isDestroyed) { return; }
      let endTime = new Date().getTime();
      this.get('tracking').trackEvent({
        event,
        data: { latency: endTime - startTime }
      });
    });
  },

  loadBalance(channelId) {
    return this.get('session').getCurrentUser()
      .then(userData => {
        if (this.isDestroyed) { return; }
        let apiPromise = this.get('api').request('get', `/bits/balance/${userData.id}?channel=${channelId}`);
        this._trackLatency('bits_balance_latency', apiPromise);
        return apiPromise;
      })
      .then(response => {
        if (this.isDestroyed) { return; }
        this.set('balance', response.balance);
        this.set('channelTotal', response.channel_total);
        let data = {
          balance: response.balance,
          bundles: response.bundles,
          channelTotal: response.channel_total,
          inventoryLimit: response.inventory_limit,
          highestEntitledBadge: response.highest_entitled_badge
        };

        return data;
      });
  },

  sendBits(recipient, message) {
    return this._sendBitsThrottler.add(() => {
      let amount = parseTotalBits(message, this.get('bitsEmotes.regexes'));

      return this.get('session').getCurrentUser()
        .then(user => {
          if (this.isDestroyed) { return; }
          let data = {
            user_id: user.id.toString(), // API expects strings
            channel_id: recipient.toString(),
            amount: amount,
            message: message,
            event_id: uuid()
          };

          let jsonData = JSON.stringify(data);
          let options = {
            contentType: 'application/json; charset=UTF-8',
            processData: false
          };

          return this.get('api').request('post', '/bits/events', jsonData, options)
            .then(transactionResponse => {
              if (this.isDestroyed) { return; }
              this.set('channelTotal', this.get('channelTotal') + amount);
              this.set('balance', transactionResponse.balance);
              return transactionResponse.balance;
            });
        });
    });
  },

  loadRecipientEligibility(channelId) {
    return this.get('api').request('get', `/bits/channels/${channelId}`)
      .then(response => {
        let data = {
          eligible: response.eligible,
          minBits: response.min_bits,
          minBitsEmote: response.min_bits_emote,
          hashtags: response.hashtags,
          enabledBadgeTiers: response.enabled_bits_badge_tiers,
          pinnedCheersEnabled: response.pin_recent_cheers || response.pin_top_cheers,
          pinnedCheersMinimum: response.recent_cheer_min,
          pinnedCheersTimeout: response.recent_cheer_timeout
        };

        return data;
      });
  },

  loadSenderEligibility(userId) {
    return this.get('api').request('get', `/bits/users/${userId}`)
      .then(response => response.eligible);
  },

  getPrices(asins){
    return this.get('session').getCurrentUser()
      .then(user => {
        if (this.isDestroyed) { return; }
        let url = `/bits/prices?user_id=${user.id}`;
        url += asins.map((asin) => `&asins=${asin}`).join('');
        return this.get('api').request('get', url);
      }).then(response => {
        if (this.isDestroyed) { return; }
        return response.prices;
      });
  },

  getBadgeTiers(channelId) {
    return this.get('api').request('get', `/bits/badges/${channelId}/tiers`);
  },

  setBadgeTiers(channelId, tiers) {
    let jsonData = JSON.stringify(tiers);
    let options = {
      contentType: 'application/json; charset=UTF-8',
      processData: false
    };

    return this.get('api').request('put', `/bits/badges/${channelId}/tiers`, jsonData, options);
  },

  getChannelSettings(channelId) {
    return this.get('api').request('get', `/bits/channels/${channelId}/settings`);
  },

  setChannelSettings(channelId, settings) {
    let jsonData = JSON.stringify(settings);
    let options = {
      contentType: 'application/json; charset=UTF-8',
      processData: false
    };

    return this.get('api').request('put', `/bits/channels/${channelId}/settings`, jsonData, options);
  },

  getHashtags(channelId) {
    return this.get('api').request('get', `/bits/hashtags/${channelId}`);
  },

  setHashtags(channelId, hashtags) {
    let jsonData = JSON.stringify(hashtags);
    let options = {
      contentType: 'application/json; charset=UTF-8',
      processData: false
    };

    return this.get('api').request('put', `/bits/hashtags/${channelId}`, jsonData, options);
  },

  setOnboarded(channelId) {
    let jsonData = JSON.stringify({});
    let options = {
      contentType: 'application/json; charset=UTF-8',
      processData: false
    };
    return this.get('api').request('put', `/bits/channels/${channelId}/onboarded`, jsonData, options);
  },

  entitleAdBits(userId, engagement) {
    let data = {
      user_id: userId,
      engagement_receipt: engagement
    };

    let jsonData = JSON.stringify(data);
    let options = {
      contentType: 'application/json; charset=UTF-8',
      processData: false
    };
    return this.get('api').request('post', `/bits/ads`, jsonData, options);
  },

  bitsAdsAvailable(userId) {
    let tuid = this.get('crypto').SHA1(`${userId}`);
    let key = this.get('globals.truexPartnerHash');
    let path = this.get('globals.truexApiUrl');
    return this.get('ajax').request(`${path}?placement.key=${key}&user.uid=${tuid}&max_activites=1`);
  },

  getMostRecentPinnedCheer(channelId) {
    return this.get('api').request('get', `/bits/channels/${channelId}/events/recent`);
  },

  dismissPinnedCheer({ channelId, userId, messageId, type, timestamp }) {
    let dismissal = {
      user_id : String(userId),
      messageId : messageId,
      type: type,
      timestamp: timestamp
    };

    let jsonData = JSON.stringify(dismissal);

    let options = {
      contentType: 'application/json; charset=UTF-8',
      processData: false
    };

    //TODO: when we change this endpoint to .../events/pinned in Payday, this function will make a lot more sense
    return this.get('api').request('delete', `/bits/channels/${channelId}/events/recent`, jsonData, options);
  },

  getActions() {
    // TODO when bits-rendering-config is removed, just return the API request (no caching)
    return this.getEmoteConfig();
  },

  // TODO: when bits-rendering-config is removed, remove this
  getEmoteConfig() {
    let cachedPromise = this.get('cachedEmoteConfigPromise');
    if (cachedPromise) {
      return cachedPromise;
    }

    return this._loadEmotesConfig();
  },

  // TODO: when bits-rendering-config is removed, remove this
  _loadEmotesConfig() {
    let cachedPromise = this.get('api').request('get', 'bits/actions', null, {
      version: 5,
      headers: {'Client-ID': WEB_CLIENT_CLIENT_ID}
    });

    this.set('cachedEmoteConfigPromise', cachedPromise);
    return cachedPromise;
  }
});
