import Component from 'ember-component';
import computed from 'ember-computed';
import injectService from 'ember-service/inject';
import { filterEmotes } from 'web-client/helpers/filter-emotes';
import { KEY_CODES } from 'web-client/utilities/keyboard';
import { A as emberA } from 'ember-array/utils';
import { htmlSafe } from 'ember-string';
import $ from 'jquery';

/* Removing backslashes for characters regex doesn't care about,
 * and then replacing HTML entities. <textarea/> used for security concerns:
 * http://stackoverflow.com/a/1395954 */
let _preprocessRegex = function (regexString) {
  let regexRegex = /[\|\\\^\$\*\+\?\:\#]/; // characters indicative of regex: | \ ^ $ * + ? : #
  if (!regexRegex.test(regexString)) {
    return regexString;
  }
  let pattern = regexString.replace(/\\(?=[&;:])/g, '');
  pattern = `^${pattern}$`;
  return $("<textarea/>").html(pattern).text();
};

export default Component.extend({
  classNames: ['js-emoticon-selector', 'ember-emoticon-selector', 'emoticon-selector'],

  campaign: 'emoticon-selector-subscribe-button',

  //public things
  channelProduct: null,
  isSubscribed: null,
  subscribeToUnlockText: null, //i18n'ed version of 'Subscribe to unlock Emoticons'
  subscribeText: null, //i18n'ed version of 'Subscribe'
  enableTabs: true,
  allEmotes: null,
  filter: '',

  feeds: injectService(),

  didInsertElement() {
    this._super(...arguments);
    this.$('.js-filter-input').focus();
  },

  // Channel
  subscribePrice: computed('channelProduct.price', function () {
    return this.get('channelProduct.price');
  }),

  subscribeProductUrl: computed('channelProduct.product_url', 'campaign', function () {
    return `${this.get('channelProduct.product_url')}?ref=${this.get('campaign')}`;
  }),

  channelDisplayedEmotes: computed.map('_activeEmoticons', function (emoticon) {
    let defaultStyle = htmlSafe(`background-image: url("https://static-cdn.jtvnw.net/emoticons/v1/${emoticon.id}/1.0");`);
    return {
      displayName: emoticon.displayName || emoticon.regex,
      style: emoticon.style || defaultStyle
    };
  }),

  _activeEmoticons: computed('channelProduct.emoticons', 'filter', function () {
    let channelEmotes = this.get('channelProduct.emoticons') || [];
    channelEmotes = channelEmotes.filter((emoticon) => emoticon.state === 'active');
    channelEmotes = filterEmotes([channelEmotes], {filter: this.get('filter')});
    return emberA(channelEmotes);
  }),

  showChannelEmotes: computed('hasChannelEmotes', function() {
    // If all emotes populates without channel emotes, default to All tab
    if (!this.get('hasChannelEmotes')) {
      return false;
    }
    return true;
  }),

  // All Emotes
  _formatEmoteSet: function (set) {
    set = emberA(set);
    return set.sortBy('id').map(emote => {
      let defaultStyle = htmlSafe(`background-image: url("https://static-cdn.jtvnw.net/emoticons/v1/${emote.id}/1.0");`);
      let regex = _preprocessRegex(emote.code);

      return {
        style: emote.style || defaultStyle,
        displayName: emote.displayName || this.REGEX_EMOTE_MAP[regex] ? this.REGEX_EMOTE_MAP[regex] : regex
      };
    });
  },

  hasChannelEmotes: computed.notEmpty('_activeEmoticons'),
  hasAllEmotes: computed.notEmpty('allEmotes.emoticon_sets'),

  allDisplayedEmotes: computed('allEmotes.emoticon_sets', 'filter', function () {
    let filter = this.get('filter');
    let emoticonSets = this.get('allEmotes.emoticon_sets');
    let emoticonSetsList = [];
    if (emoticonSets) {
      Object.keys(emoticonSets).forEach(setId => {
        // Special case global and turbo emotes and put them at the bottom
        if (!this.EMOTE_SETS_TO_BOTTOM.includes(setId)) {
          emoticonSetsList.push(this._formatEmoteSet(filterEmotes([emoticonSets[setId]], {filter})));
        }
      });

      this.EMOTE_SETS_TO_BOTTOM.forEach(setId => {
        if (emoticonSets[setId]) {
          emoticonSetsList.push(this._formatEmoteSet(filterEmotes([emoticonSets[setId]], {filter})));
        }
      });
    }

    return emoticonSetsList;
  }),

  selectEmoticon (emote) {
    this.sendAction('action', emote);

    let $parents = this.$().parents();
    let location;
    if ($parents.is('.js-conversation-window')) {
      location = 'whisper';
    } else if ($parents.is('.js-chat-container')) {
      location = 'chat';
    } else if ($parents.is('.js-activity-add-comment')) {
      location = 'comment';
    } else if ($parents.is('.js-activity-card')) {
      location = 'reactions';
    }

    let feeds = this.get('feeds');
    if (feeds) {
      feeds.trackEvent('chat_emote_click', {
        location, // 'chat' || 'reactions' || 'whisper' || 'comment'

        emote,
        emote_search_input: this.get('filter') || null
      });
    }
  },

  keyDown (evt) {
    if (evt.which === KEY_CODES.esc) {
      this.sendAction('hideAction');
    }
  },

  actions: {
    selectChannelEmoticon: function (emoticon) {
      if (this.get('isSubscribed')) {
        this.selectEmoticon(emoticon);
      }
    },
    selectOtherEmoticon: function (emoticon) {
      this.selectEmoticon(emoticon);
    },
    viewChannel: function () {
      this.set('showChannelEmotes', true);
    },
    viewAll: function () {
      this.set('showChannelEmotes', false);
    },
    onFilterChange: function () {
      $('.tipsy.tipsy-n').remove();
    }
  },

  EMOTE_SETS_TO_BOTTOM: emberA(['457', '33', '42', '0']),

  // When we move away from regexes for emoticons, we should stop using this - ai 2015/4/15
  REGEX_EMOTE_MAP: {
    '^B-?\\)$': 'B)',
    '^:-?[z|Z|\\|]$': ':|',
    '^:-?\\)$': ':)',
    '^:-?\\($': ':(',
    '^:-?(p|P)$': ':P',
    '^;-?(p|P)$': ';P',
    '^:-?[\\\\/]$': ':/',
    '^;-?\\)$': ';)',
    '^R-?\\)$': 'R)',
    '^:>$':':>',
    '^[oO](_|\\.)[oO]$': 'O_o',
    '^:-?D$': ':D',
    '^:-?(o|O)$': ':O',
    '^>\\($': '>(',
    '^:-?(?:7|L)$': ':7',
    '^:-?(S|s)$': ':S',
    '^#-?[\\\\/]$': '#/',
    '^<\\]$': '<]',
    '^<3$': '<3'
  }
});
