import Component from 'ember-component';
import computed from 'ember-computed';
import $ from 'jquery';
import moment from 'moment';
import observer from 'ember-metal/observer';
import run from 'ember-runloop';

import { MONTHS_RESOLUTION, MONTH_FORMAT } from 'web-client/components/dashboards/revenue/date-picker/component';

export default Component.extend({
  classNames: ['flex__item'],

  /* Passed in property */
  updateDateFilter: null,

  /* Internal Properties */
  visible: false,
  years: null, // years array
  months: null, // months array
  selectedYear: null, // this is the year in the input field
  selectedMonth:  null, // should be a value between 0-11
  activeYear: null, // this is the year you're currently on
  parentInput: null, // parent input field
  pickerObject: null,
  monthDate: null,

  momentStartDate: null,
  momentEndDate: null,
  isDatepickerDisabled: null,

  $datepickerStart: null,
  $datepickerEnd: null,

  monthDifference: computed('momentStartDate', 'momentEndDate', function() {
    return this.get('momentEndDate').diff(this.get('momentStartDate'), MONTHS_RESOLUTION) + 1;
  }),

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

    let formattedStartDate = this.get('momentStartDate').startOf('month');
    let formattedEndDate = this.get('momentEndDate').endOf('month');

    this.set('momentStartDate', formattedStartDate);
    this.set('momentEndDate', formattedEndDate);

    this.set('years', this._generateYears());
    this.set('months', this._generateMonths());
    this.set('selectedYear', moment().year());
    this.set('selectedMonth', moment().month());
    this.set('activeYear', moment().year());
    this.set('monthDate', moment());
    this.set('pickerObject', {});
  },

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

    let _this = this;
    let momentStartDate = this.get('momentStartDate');
    let momentEndDate = this.get('momentEndDate');

    this.$datepickerStart = this.$().find('input.js-datepicker-start');
    this.$datepickerEnd = this.$().find('input.js-datepicker-end');

    this.$datepickerStart.val(momentStartDate.format(MONTH_FORMAT));
    this.$datepickerEnd.val(momentEndDate.format(MONTH_FORMAT));

    this._appendToPage();

    // Bind to datepicker start
    this.$datepickerStart.on('focus', function () {
      run(() => {
        _this.set('parentInput', this);
        _this._show();
      });
    });

    // Bind to datepicker end
    this.$datepickerEnd.on('focus', function () {
      run(() => {
        _this.set('parentInput', this);
        _this._show();
      });
    });

    // When an area not in the modal is clicked, close it
    // See http://stackoverflow.com/a/7385673
    $(document).click(e => {
      run(() => {
        let clickAreas = $('.js-monthpicker, input.js-datepicker-start, input.js-datepicker-end');
        if (this.get('visible') && // if the picker is visible...
          !clickAreas.is(e.target) && // ... if the target of the click isn't the container...
          clickAreas.has(e.target).length === 0) { // ... nor a descendant of the container
          this._hide();
        }
      });
    });

    let updateDateObject = {
      startDate: momentStartDate,
      endDate: momentEndDate,
      resolution: MONTHS_RESOLUTION
    };

    run.once(this, 'updateDateFilter', updateDateObject);
  },

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

    let pickerObject = this.get('pickerObject');

    // Hide
    this._hide();

    // Remove listeners
    $(pickerObject).off('click', '.ui-datepicker-next');
    $(pickerObject).off('click', '.ui-datepicker-prev');
    $(pickerObject).off('click', 'a.ui-state-default--month:not(.tw-ui-monthpicker-month--disabled)');
    $(pickerObject).on('mousemove', 'a.ui-state-default--month:not(.tw-ui-monthpicker-month--disabled)');
    $(pickerObject).on('mouseleave', 'a.ui-state-default--month:not(.tw-ui-monthpicker-month--disabled)');
    $(document).off('click');
  },

  updateStartAndEndMonths: observer('momentStartDate', 'momentEndDate', function() {
    let momentStartDate = this.get('momentStartDate');
    let momentEndDate = this.get('momentEndDate');

    let updateDateObject = {
      startDate: momentStartDate,
      endDate: momentEndDate,
      resolution: MONTHS_RESOLUTION
    };

    run.once(this, 'updateDateFilter', updateDateObject);
  }),

  _generateYears() {
    // Get the current year and generate all years from 2011 to the current year
    let selectedYear = moment().year();
    let returnArray = [];
    for (let i = 2011; i <= selectedYear; i++) {
      returnArray.push(i);
    }

    return returnArray;
  },

  _generateMonths() {
    // get a list of months by and populate. this just sets the standard 12 calendar months right now
    let monthArray = [];
    for (let i = 0; i < 12; i++) {
      monthArray.push(moment().month(i).format('MMM'));
    }

    // return [i18n('Jan'), i18n('Feb'), i18n('Mar'), i18n('Apr'), i18n('May'), i18n('Jun'), i18n('Jul'), i18n('Aug'), i18n('Sep'), i18n('Oct'), i18n('Nov'), i18n('Dec')]
    return monthArray;
  },

  _goToNextYear() {
    // go to the next year
    let nextYearIndex = this._getYearIndex(this.get('activeYear')) + 1;
    let years = this.get('years');
    if (nextYearIndex >= years.length) {
      nextYearIndex = years.length - 1;
    }
    this._goToYear(years[nextYearIndex]);
  },

  _goToPrevYear() {
    // go to the prev year
    let prevYearIndex = this._getYearIndex(this.get('activeYear')) - 1;
    if (prevYearIndex <= 0) {
      prevYearIndex = 0;
    }
    this._goToYear(this.years[prevYearIndex]);
  },

  _goToYear(year) {
    // go to the given year - must be in the year array
    let yearIndex = this._getYearIndex(year);
    let years = this.get('years');
    let activeYear = years[yearIndex];
    let pickerObject = this.get('pickerObject');
    this.set('activeYear', activeYear);

    // Re-render the month table
    let newTable = this._renderMonthsForYear(activeYear);
    $(pickerObject).find('table.ui-datepicker-calendar').remove();
    pickerObject.appendChild(newTable);

    // Update year text
    $(pickerObject).find('.ui-datepicker-year').text(activeYear.toString());
  },

  _getMonthIndex(monthString) {
    let months = this.get('months');
    let monthIndex = months.indexOf(monthString);
    if (monthIndex < 0) {
      monthIndex = 0;
    }
    return monthIndex;
  },

  _getYearIndex(yearInt) {
    yearInt = parseInt(yearInt);
    let years = this.get('years');
    let yearIndex = years.indexOf(yearInt);
    if (yearIndex < 0) {
      yearIndex = 0;
    }
    return yearIndex;
  },

  _show() {
    let parentInput = this.get('parentInput');

    let el = $(parentInput);
    let x = el.offset().left;
    let y = el.offset().top + el.outerHeight();

    let inputValue = parentInput.value.toString();
    let inputMonthIndex = moment().month(inputValue).month();
    let inputYear = inputValue.slice(Math.max(inputValue.length - 4, 1));

    // set month to the month in the input field
    this.set('selectedMonth', inputMonthIndex);
    this.set('selectedYear', inputYear);
    this.set('monthDate', moment().month(inputValue).year(inputYear));

    // set year to the year in the input field
    this._goToYear(inputYear);

    // position & show the picker
    $(this.get('pickerObject')).css({
      top: `${ y }px`,
      left: `${ x }px`,
      display: 'block'
    });

    // Indicate it's visible
    this.set('visible', true);
  },

  _hide() {
    $(this.get('pickerObject')).css({
      display: 'none'
    });
    // Indicate it's hidden
    this.set('visible', false);
  },

  _renderMonthsForYear(forYear) {
    let CURRENT_YEAR = moment().year();
    let maxMonth = moment().month();
    let selectedYear = this.get('selectedYear');
    let selectedMonth = this.get('selectedMonth');
    let months = this.get('months');

    let parentInput = this.get('parentInput');

    // If rendering the date picker for start date, then set the max to the end month
    if (parentInput && $(parentInput).hasClass('js-datepicker-start')) {
      let endMonth = moment(this.get('momentEndDate')).month();
      maxMonth = Math.min(maxMonth, endMonth);
    }

    // Render the months as nodes & return the parent tbody object
    let table = document.createElement('table');
    let tbody = document.createElement('tbody');

    table.className = 'ui-datepicker-calendar';

    for (let i = 0; i < this.months.length; i += 4) { // we want 4 items per row...
      let tr = document.createElement('tr');
      for (let j = i; j < i + 4; j++) {
        let td = document.createElement('td');
        let link = document.createElement('a');

        // if the month is selected, highlight it
        link.href = '#';
        link.className = 'ui-state-default ui-state-default--month';
        link.textContent = months[j];

        // if the month is the selected month...
        if (selectedYear === forYear && j === selectedMonth) {
          link.className = 'ui-state-active ui-state-default ui-state-default--month';
        }

        td.className = 'tw-ui-monthpicker-month';

        // disable months that are in the future or greater than the end month
        if (forYear >= CURRENT_YEAR && j > maxMonth) {
          td.className = 'tw-ui-monthpicker-month tw-ui-monthpicker-month--disabled';
          let dateSpan = document.createElement('span');
          dateSpan.className = 'ui-state-default';
          dateSpan.textContent = months[j];
          td.appendChild(dateSpan);
          tr.appendChild(td);
        } else {
          td.appendChild(link);
          tr.appendChild(td);
        }
      }
      tbody.appendChild(tr);
    }

    table.appendChild(tbody);

    return table;
  },

  _renderTitleForYear(forYear) {
    let titleNode = document.createElement('div');
    let prevLinkNode = document.createElement('a');
    let nextLinkNode = document.createElement('a');
    let prevLinkSpan = document.createElement('span');
    let nextLinkSpan = document.createElement('span');
    let titleSpan = document.createElement('span');

    // Set classnames
    titleNode.className = 'ui-datepicker-title';
    prevLinkNode.className = 'ui-datepicker-prev';
    prevLinkSpan.className = 'ui-icon ui-icon-circle-triangle-w';
    nextLinkNode.className = 'ui-datepicker-next';
    nextLinkSpan.className = 'ui-icon ui-icon-circle-triangle-e';
    titleSpan.className = 'ui-datepicker-year';

    // Set text
    titleSpan.textContent = forYear.toString();

    // Make parent/child relationships
    prevLinkNode.appendChild(prevLinkSpan);
    nextLinkNode.appendChild(nextLinkSpan);
    titleNode.appendChild(prevLinkNode);
    titleNode.appendChild(nextLinkNode);
    titleNode.appendChild(titleSpan);

    return titleNode;
  },

  _stitchNodes() {
    let activeYear = this.get('activeYear');
    let rootNode = document.createElement('div');
    let titleNode = this._renderTitleForYear(activeYear);
    let tableBodyNode = this._renderMonthsForYear(activeYear);

    rootNode.className = 'ui-datepicker tw-ui-datepicker--monthpicker js-monthpicker';
    rootNode.appendChild(titleNode);
    rootNode.appendChild(tableBodyNode);
    return rootNode;
  },

  _appendToPage() {
    // Get nodes
    let nodeToAppend = this._stitchNodes();
    $('body').append(nodeToAppend);
    this.set('pickerObject', nodeToAppend);
    this._bindClickEventListeners();
  },

  _bindClickEventListeners() {
    let pickerObject = this.get('pickerObject');
    let _this = this;

    $(pickerObject).on('click', '.ui-datepicker-next', e => {
      if (this.isDestroyed) { return; }
      e.preventDefault();
      run(() => this._goToNextYear());
    });

    $(pickerObject).on('click', '.ui-datepicker-prev', e => {
      if (this.isDestroyed) { return; }
      e.preventDefault();
      run(() => this._goToPrevYear());
    });

    $(pickerObject).on('click',
      'a.ui-state-default--month:not(.tw-ui-monthpicker-month--disabled)',
      function(e) {
        if (this.isDestroyed) { return; }

        e.preventDefault();

        run(() => {
          let parentInput = _this.get('parentInput');
          let monthString = $(this).text();
          let yearString = $(pickerObject).find('.ui-datepicker-year').text();
          let momentDate = moment().month(monthString).year(parseInt(yearString));

          // set the appropriate start or end month
          if ($(parentInput).hasClass('js-datepicker-start')) {
            momentDate.startOf('month');
            _this.set('momentStartDate', momentDate);
          } else {
            momentDate.endOf('month');
            _this.set('momentEndDate', momentDate);

            // if new end date is before start date, shift start date to same month
            if (_this.get('momentStartDate').month() > momentDate.month()) {
              momentDate.endOf('month');
              _this.set('momentStartDate', moment(momentDate).startOf('month'));
              $('.js-datepicker-start').val(momentDate.format(MONTH_FORMAT));
            }
          }

          _this.set('selectedMonth', momentDate.month());
          _this.set('selectedYear', momentDate.year());
          parentInput.value = momentDate.format(MONTH_FORMAT);
          _this.set('parentInput', parentInput);

          _this._hide();
        });
      });

    $(pickerObject).on('mousemove',
      'a.ui-state-default--month:not(.tw-ui-monthpicker-month--disabled)',
      function(e) {
        if (this.isDestroyed) { return; }
        e.preventDefault();
        run(() => $(this).addClass('ui-state-hover'));
      });

    $(pickerObject).on('mouseleave',
      'a.ui-state-default--month:not(.tw-ui-monthpicker-month--disabled)',
      function(e) {
        if (this.isDestroyed) { return; }
        e.preventDefault();
        run(() => $(this).removeClass('ui-state-hover'));
      });
  }
});
