import PropTypes from '../../../_util/vue-types';
import { getOptionProps } from '../../../_util/props-util';
import cx from 'classnames';
import DateConstants from './DateConstants';
import { getTitleString, getTodayTime } from '../util/';
function noop() {}
function isSameDay(one, two) {
  return one && two && one.isSame(two, 'day');
}

function beforeCurrentMonthYear(current, today) {
  if (current.year() < today.year()) {
    return 1;
  }
  return current.year() === today.year() && current.month() < today.month();
}

function afterCurrentMonthYear(current, today) {
  if (current.year() > today.year()) {
    return 1;
  }
  return current.year() === today.year() && current.month() > today.month();
}

function getIdFromDate(date) {
  return `rc-calendar-${date.year()}-${date.month()}-${date.date()}`;
}

const DateTBody = {
  name: 'DateTBody',
  inheritAttrs: false,
  props: {
    contentRender: PropTypes.func,
    dateRender: PropTypes.func,
    disabledDate: PropTypes.func,
    prefixCls: PropTypes.string,
    selectedValue: PropTypes.oneOfType([PropTypes.any, PropTypes.arrayOf(PropTypes.any)]),
    value: PropTypes.object,
    hoverValue: PropTypes.any.def([]),
    showWeekNumber: PropTypes.bool,
  },

  render() {
    const props = getOptionProps(this);
    const {
      contentRender,
      prefixCls,
      selectedValue,
      value,
      showWeekNumber,
      dateRender,
      disabledDate,
      hoverValue,
    } = props;
    const { onSelect = noop, onDayHover = noop } = this.$attrs;
    let iIndex;
    let jIndex;
    let current;
    const dateTable = [];
    const today = getTodayTime(value);
    const cellClass = `${prefixCls}-cell`;
    const weekNumberCellClass = `${prefixCls}-week-number-cell`;
    const dateClass = `${prefixCls}-date`;
    const todayClass = `${prefixCls}-today`;
    const selectedClass = `${prefixCls}-selected-day`;
    const selectedDateClass = `${prefixCls}-selected-date`; // do not move with mouse operation
    const selectedStartDateClass = `${prefixCls}-selected-start-date`;
    const selectedEndDateClass = `${prefixCls}-selected-end-date`;
    const inRangeClass = `${prefixCls}-in-range-cell`;
    const lastMonthDayClass = `${prefixCls}-last-month-cell`;
    const nextMonthDayClass = `${prefixCls}-next-month-btn-day`;
    const disabledClass = `${prefixCls}-disabled-cell`;
    const firstDisableClass = `${prefixCls}-disabled-cell-first-of-row`;
    const lastDisableClass = `${prefixCls}-disabled-cell-last-of-row`;
    const lastDayOfMonthClass = `${prefixCls}-last-day-of-month`;
    const month1 = value.clone();
    month1.date(1);
    const day = month1.day();
    const lastMonthDiffDay = (day + 7 - value.localeData().firstDayOfWeek()) % 7;
    // calculate last month
    const lastMonth1 = month1.clone();
    lastMonth1.add(0 - lastMonthDiffDay, 'days');
    let passed = 0;
    for (iIndex = 0; iIndex < DateConstants.DATE_ROW_COUNT; iIndex++) {
      for (jIndex = 0; jIndex < DateConstants.DATE_COL_COUNT; jIndex++) {
        current = lastMonth1;
        if (passed) {
          current = current.clone();
          current.add(passed, 'days');
        }
        dateTable.push(current);
        passed++;
      }
    }
    const tableHtml = [];
    passed = 0;

    for (iIndex = 0; iIndex < DateConstants.DATE_ROW_COUNT; iIndex++) {
      let isCurrentWeek;
      let weekNumberCell;
      let isActiveWeek = false;
      const dateCells = [];
      if (showWeekNumber) {
        weekNumberCell = (
          <td key={`week-${dateTable[passed].week()}`} role="gridcell" class={weekNumberCellClass}>
            {dateTable[passed].week()}
          </td>
        );
      }
      for (jIndex = 0; jIndex < DateConstants.DATE_COL_COUNT; jIndex++) {
        let next = null;
        let last = null;
        current = dateTable[passed];
        if (jIndex < DateConstants.DATE_COL_COUNT - 1) {
          next = dateTable[passed + 1];
        }
        if (jIndex > 0) {
          last = dateTable[passed - 1];
        }
        let cls = cellClass;
        let disabled = false;
        let selected = false;

        if (isSameDay(current, today)) {
          cls += ` ${todayClass}`;
          isCurrentWeek = true;
        }

        const isBeforeCurrentMonthYear = beforeCurrentMonthYear(current, value);
        const isAfterCurrentMonthYear = afterCurrentMonthYear(current, value);

        if (selectedValue && Array.isArray(selectedValue)) {
          const rangeValue = hoverValue.length ? hoverValue : selectedValue;
          if (!isBeforeCurrentMonthYear && !isAfterCurrentMonthYear) {
            const startValue = rangeValue[0];
            const endValue = rangeValue[1];
            if (startValue) {
              if (isSameDay(current, startValue)) {
                selected = true;
                isActiveWeek = true;
                cls += ` ${selectedStartDateClass}`;
              }
            }
            if (startValue || endValue) {
              if (isSameDay(current, endValue)) {
                selected = true;
                isActiveWeek = true;
                cls += ` ${selectedEndDateClass}`;
              } else if (
                (startValue === null || startValue === undefined) &&
                current.isBefore(endValue, 'day')
              ) {
                cls += ` ${inRangeClass}`;
              } else if (
                (endValue === null || endValue === undefined) &&
                current.isAfter(startValue, 'day')
              ) {
                cls += ` ${inRangeClass}`;
              } else if (current.isAfter(startValue, 'day') && current.isBefore(endValue, 'day')) {
                cls += ` ${inRangeClass}`;
              }
            }
          }
        } else if (isSameDay(current, value)) {
          // keyboard change value, highlight works
          selected = true;
          isActiveWeek = true;
        }

        if (isSameDay(current, selectedValue)) {
          cls += ` ${selectedDateClass}`;
        }

        if (isBeforeCurrentMonthYear) {
          cls += ` ${lastMonthDayClass}`;
        }
        if (isAfterCurrentMonthYear) {
          cls += ` ${nextMonthDayClass}`;
        }

        if (
          current
            .clone()
            .endOf('month')
            .date() === current.date()
        ) {
          cls += ` ${lastDayOfMonthClass}`;
        }

        if (disabledDate) {
          if (disabledDate(current, value)) {
            disabled = true;

            if (!last || !disabledDate(last, value)) {
              cls += ` ${firstDisableClass}`;
            }

            if (!next || !disabledDate(next, value)) {
              cls += ` ${lastDisableClass}`;
            }
          }
        }

        if (selected) {
          cls += ` ${selectedClass}`;
        }

        if (disabled) {
          cls += ` ${disabledClass}`;
        }

        let dateHtml;
        if (dateRender) {
          dateHtml = dateRender({ current, today: value });
        } else {
          const content = contentRender ? contentRender({ current, today: value }) : current.date();
          dateHtml = (
            <div
              key={getIdFromDate(current)}
              class={dateClass}
              aria-selected={selected}
              aria-disabled={disabled}
            >
              {content}
            </div>
          );
        }

        dateCells.push(
          <td
            key={passed}
            onClick={disabled ? noop : onSelect.bind(null, current)}
            onMouseenter={disabled ? noop : onDayHover.bind(null, current)}
            role="gridcell"
            title={getTitleString(current)}
            class={cls}
          >
            {dateHtml}
          </td>,
        );

        passed++;
      }

      tableHtml.push(
        <tr
          key={iIndex}
          role="row"
          class={cx({
            [`${prefixCls}-current-week`]: isCurrentWeek,
            [`${prefixCls}-active-week`]: isActiveWeek,
          })}
        >
          {weekNumberCell}
          {dateCells}
        </tr>,
      );
    }
    return <tbody class={`${prefixCls}-tbody`}>{tableHtml}</tbody>;
  },
};

export default DateTBody;
