import run from 'ember-runloop';
import $ from 'jquery';
import Component from 'ember-component';
import computed from 'ember-computed';
import injectService from 'ember-service/inject';

const HOVER_TIME = 500; // in milliseconds
const HOVER_EXIT_TIME = 250;
const DEFAULT_ARROW_POS = 6; // pixels down from the top of the card
const CARD_WIDTH = 400;

export default Component.extend({
  tagName: 'div',
  classNames: ['js-username-hover-tip', 'pin-l-1', 'profile-card--balloon'],
  attributeBindings: ['style'],
  layoutName: 'components/username-hover',

  layout: injectService(),

  userHoverId: null,
  positioning: null,

  isVisible: false,
  didSetUser: false,
  cardHeight: 0,

  balloonPos: 'right',

  style: computed('positioning', function() {
    let positioning = this.get('positioning');

    if (!positioning) {
      return;
    }
    return `top:${positioning.topPos}px;left:${positioning.leftPos}px;`;
  }),

  didInsertElement() {
    this._initTip();
    this.get('layout').on('dismissProfileCard', this, '_dismissProfileCard');
  },

  _initTip: function () {
    $(document).on('mouseenter', '.js-username-hover', (e) => {
      let el = $(e.currentTarget);
      let id = el.attr('data-id');
      let login = el.attr('data-login');
      let topPos, leftPos;

      if (el.attr('data-position')) {
        this.set('balloonPos', el.attr('data-position'));
      }

      this.setClass(this.get('balloonPos'));

      run.cancel(this.get('hoverEnterClear'));

      // If the profile card is hidden, set the user id/login so it
      // will be rendered in the background, and the height of the
      // card can be used to set the correct position.
      if (!this.get('isVisible') && !this.get('didSetUser')) {
        run.cancel(this.get('hoverExitClear'));
        this._setUser(id, login);
        this.set('cardHeight', this.$().outerHeight());
      }

      this.set('hoverEnterClear', run.later(this, function() {
          this.set('isVisible', true);
          this._setActionVars(el);
          let elBoundingBox = e.currentTarget.getBoundingClientRect();
          let cardHeight = this.get('cardHeight');

          if (!cardHeight) {
            cardHeight = this.$().outerHeight();
          }

          let cardPos = this._calculateCardPosition(elBoundingBox, cardHeight);
          let balloonPos = this.get('balloonPos');
          // This should ideally be refactored to support all our modal styles
          if (balloonPos === 'right') {
            topPos = cardPos.top;
            leftPos = elBoundingBox.right;
          } else if (balloonPos === 'down') {
            topPos = elBoundingBox.bottom;
            leftPos = elBoundingBox.left;
          } else if (balloonPos === 'left') {
            topPos = cardPos.top;
            leftPos = elBoundingBox.left - CARD_WIDTH - DEFAULT_ARROW_POS;
          }

          this.set('cardHeight', cardHeight);
          this.set('positioning', { topPos, leftPos });

          // Show arrow at correct username position
          this._setCardArrowPosition(cardPos.arrow);

          this._setUser(id, login);
        }, HOVER_TIME)
      );
    });

    $(document).on('mouseenter', '.js-username-hover-tip', () => {
      run.cancel(this.get('hoverExitClear'));
    });

    $(document).on('mouseleave', '.js-username-hover, .js-username-hover-tip', this._hideTip.bind(this));
    $(document).on('click', '.js-username-hover', this._hideTip.bind(this));
  },

  _hideTip() {
    run.cancel(this.get('hoverEnterClear'));
    run.cancel(this.get('hoverExitClear'));
    this.set('balloonPos', this.get('layout.isSocialColumnEnabled') ? 'left' : 'right');
    this.set('hoverExitClear', run.later(this, function() {
        this.set('userHoverId', null);
        this.set('isVisible', false);
        this.set('didSetUser', false);
      }, HOVER_EXIT_TIME)
    );
  },

  setClass(position) {
    let pos = `balloon--${position}`;
    this.set('balloon_pos', pos);
  },

  willDestroyElement() {
    run.cancel(this.get('hoverExitClear'));
    run.cancel(this.get('hoverEnterClear'));
    this.get('layout').off('dismissProfileCard', this, '_dismissProfileCard');

    $(document).off('mouseenter', '.js-username-hover');
    $(document).off('click', '.js-username-hover');
    $(document).off('mouseenter', '.js-username-hover-tip');
    $(document).off('mouseleave', '.js-username-hover, .js-username-hover-tip');

    $('.js-username-hover').off();
    $('.js-username-hover-tip').off();
  },

  _calculateCardPosition(targetElementBoundingBox, cardHeight) {
    let top = targetElementBoundingBox.top;
    let cardPosition = {
      top: top,
      arrow: DEFAULT_ARROW_POS
    };

    // Don't show the card below or above the browser window
    if (top + cardHeight > window.innerHeight) {
      cardPosition.top = window.innerHeight - cardHeight;
      cardPosition.arrow = DEFAULT_ARROW_POS + top - cardPosition.top;
    } else if (top < 0) {
      cardPosition.top = 0;
    }

    return cardPosition;
  },

  _setCardArrowPosition(arrowPos) {
    let tipStyle = $('.js-username-hover-tip style');

    // Cannot target the ':after' CSS property using JavaScript.
    // Need to create a new <style> element and modify the HTML in there.
    if (tipStyle.length > 0) {
      tipStyle.html(`.balloon--right:after{top: ${arrowPos}px;}`);
    } else {
      $('.js-username-hover-tip').append(`<style>.balloon--left:after{top: ${arrowPos}px;}</style>`);
    }
  },

  _setUser(id, login) {
    this.set('userHoverId', id);
    this.set('userHoverLogin', login);
    this.set('didSetUser', true);
  },

  _setActionVars(el) {
    this.set('showFriend', (el.attr('data-hidefriend') === 'true' ? false : true));
    this.set('showFollow', (el.attr('data-hidefollow') === 'true' ? false : true));
    this.set('showWhisper', (el.attr('data-hidewhisper') === 'true' ? false : true));
  },

  _dismissProfileCard() {
    run.cancel(this.get('hoverExitClear'));
    run.cancel(this.get('hoverEnterClear'));
    this.set('userHoverId', null);
    this.set('isVisible', false);
    this.set('didSetUser', false);
  }
});
