import _extends from "@babel/runtime/helpers/extends";
import _defineProperty from "@babel/runtime/helpers/defineProperty";

/**
 * Web DatePicker Component
 *
 */
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { format, isSameDay, startOfDay, endOfDay, isSameMonth, subMonths, addMonths, differenceInCalendarDays } from 'date-fns';
import nbLocale from 'date-fns/locale/nb';
import { makeDayObject, toRange, getWeek, dayOffset, getCalendar } from './DatePickerCalc';
import Button from '../button/Button';
export const propTypes = {
  id: PropTypes.string,
  nr: PropTypes.number,
  month: PropTypes.instanceOf(Date),
  // What month will be displayed in the first calendar. Default: new Date()
  prevBtn: PropTypes.bool,
  nextBtn: PropTypes.bool,
  titleFormat: PropTypes.string,
  dayOfWeekFormat: PropTypes.string,
  firstDayOfWeek: PropTypes.string,
  hideNav: PropTypes.bool,
  hideDays: PropTypes.bool,
  onlyMonth: PropTypes.bool,
  onHover: PropTypes.func,
  onSelect: PropTypes.func,
  onPrev: PropTypes.func,
  onNext: PropTypes.func,
  locale: PropTypes.object,
  rtl: PropTypes.bool,
  range: PropTypes.bool,
  resetDate: PropTypes.bool,
  hoverDate: PropTypes.instanceOf(Date),
  startDate: PropTypes.instanceOf(Date),
  endDate: PropTypes.instanceOf(Date),
  minDate: PropTypes.instanceOf(Date),
  maxDate: PropTypes.instanceOf(Date),
  onKeyDown: PropTypes.func
};
export const defaultProps = {
  id: null,
  nr: null,
  month: null,
  prevBtn: true,
  nextBtn: true,
  titleFormat: 'MMMM YYYY',
  dayOfWeekFormat: 'dd',
  firstDayOfWeek: 'monday',
  hideNav: false,
  hideDays: false,
  onlyMonth: false,
  // locale
  locale: nbLocale,
  rtl: false,
  // events
  onHover: null,
  onSelect: null,
  onPrev: null,
  onNext: null,
  hoverDate: null,
  // dates
  range: null,
  resetDate: true,
  // reset start/end date once we already have them
  startDate: null,
  endDate: null,
  // Limit selection with minDate and maxDate
  minDate: null,
  maxDate: null,
  // addDays(new Date(), 45)
  onKeyDown: null
};
export default class DatePickerCalendar extends PureComponent {
  constructor(props) {
    super(props);

    _defineProperty(this, "onKeyDownHandler", event => {
      if (typeof this.props.onKeyDown === 'function') {
        this.props.onKeyDown(event, this._listRef, this.props.nr);
      }
    });

    _defineProperty(this, "buildClassNames", day => classnames({
      'dnb-date-picker__day--start-date': day.isStartDate,
      'dnb-date-picker__day--end-date': day.isEndDate,
      'dnb-date-picker__day--preview': day.isPreview,
      'dnb-date-picker__day--within-selection': day.isWithinSelection,
      'dnb-date-picker__day--selectable': !day.isLastMonth && !day.isNextMonth && !day.isDisabled,
      'dnb-date-picker__day--inactive': day.isLastMonth || day.isNextMonth || day.isDisabled,
      'dnb-date-picker__day--disabled': day.isDisabled,
      'dnb-date-picker__day--today': day.isToday,
      'dnb-date-picker__day--weekend': day.isWeekend,
      'dnb-date-picker__day--last-month': day.isLastMonth,
      'dnb-date-picker__day--next-month': day.isNextMonth
    }));

    this._listRef = React.createRef();
  }

  componentDidMount() {
    if (this.props.nr === 0 && this._listRef.current) {
      this._listRef.current.focus();
    }
  }

  render() {
    const {
      id,
      nr,
      rtl,
      month,
      range,
      titleFormat,
      locale,
      firstDayOfWeek,
      dayOfWeekFormat,
      hideNav,
      hideDays,
      onlyMonth,
      onPrev,
      onNext,
      onSelect,
      resetDate,
      onHover,
      prevBtn,
      nextBtn,
      maxDate,
      minDate,
      hoverDate
    } = this.props;
    const {
      startDate,
      endDate
    } = this.props;
    this.days = getCalendar(month || new Date(), dayOffset(firstDayOfWeek), {
      onlyMonth
    }).map(date => makeDayObject(date, {
      startDate,
      endDate,
      hoverDate,
      minDate,
      maxDate,
      month
    }));
    return React.createElement("div", {
      className: classnames('dnb-date-picker__calendar', rtl && 'rtl')
    }, !hideNav && React.createElement("div", {
      className: "dnb-date-picker__header"
    }, React.createElement("div", {
      className: "dnb-date-picker__header__nav"
    }, React.createElement(PrevButton, {
      nr: nr,
      minDate: minDate,
      month: month,
      prevBtn: prevBtn,
      onPrev: onPrev,
      locale: locale,
      onKeyDown: this.onKeyDownHandler
    })), React.createElement("label", {
      id: "".concat(id, "--title"),
      className: "dnb-date-picker__header__title",
      "aria-hidden": true
    }, format(month, titleFormat, {
      locale
    })), React.createElement("div", {
      className: "dnb-date-picker__header__nav"
    }, React.createElement(NextButton, {
      nr: nr,
      maxDate: maxDate,
      month: month,
      nextBtn: nextBtn,
      onNext: onNext,
      locale: locale,
      onKeyDown: this.onKeyDownHandler
    }))), React.createElement("table", {
      role: "grid",
      className: "dnb-no-focus",
      tabIndex: "0",
      "aria-labelledby": "".concat(id, "--title"),
      onKeyDown: this.onKeyDownHandler,
      ref: this._listRef
    }, !hideDays && React.createElement("thead", {
      "aria-hidden": true
    }, React.createElement("tr", {
      role: "row",
      className: "dnb-date-picker__labels"
    }, getWeek(dayOffset(firstDayOfWeek)).map((day, i) => React.createElement("th", {
      key: i,
      role: "columnheader",
      className: "dnb-date-picker__labels__day"
    }, format(day, dayOfWeekFormat, {
      locale
    }))))), React.createElement("tbody", null, React.createElement("tr", {
      role: "row",
      className: "dnb-date-picker__days"
    }, this.days.map((day, i) => {
      const title = format(day.date, 'dddd, Do MMMM YYYY', {
        locale
      });
      const isDisabled = day.isLastMonth || day.isNextMonth || day.isDisabled;
      const isInactive = day.isLastMonth || day.isNextMonth; // cell params

      const paramsCell = {};

      if (isInactive) {
        paramsCell['aria-hidden'] = true;
      } else {
        paramsCell.tabIndex = '-1';

        if (day.isStartDate) {
          paramsCell.id = id + '--button-start';
        } else if (day.isEndDate) {
          paramsCell.id = id + '--button-end';
        }
      } // button params


      const paramsButton = {};

      if (nr === 0 ? day.isStartDate : day.isEndDate) {
        paramsButton['aria-current'] = 'date';
        paramsButton['aria-selected'] = true;
      }

      return React.createElement("td", _extends({
        key: 'day' + i,
        role: "gridcell",
        className: classnames('dnb-date-picker__day', 'dnb-no-focus', this.buildClassNames(day))
      }, paramsCell), React.createElement(Button, _extends({
        size: "medium",
        variant: "secondary",
        text: format(day.date, 'D', {
          locale
        }),
        title: title,
        bounding: true,
        disabled: isDisabled,
        tabIndex: "-1",
        "aria-hidden": isInactive,
        "aria-label": title,
        "aria-disabled": isDisabled
      }, paramsButton, {
        onClick: () => !day.isLastMonth && !day.isNextMonth && !day.isDisabled && onSelectRange({
          day,
          range,
          startDate,
          endDate,
          onSelect,
          resetDate
        }),
        onMouseOver: () => onHoverDay({
          day,
          hoverDate,
          onHover
        }),
        onFocus: () => onHoverDay({
          day,
          hoverDate,
          onHover
        })
      })));
    })))));
  }

}

_defineProperty(DatePickerCalendar, "defaultProps", defaultProps);

DatePickerCalendar.propTypes = process.env.NODE_ENV !== "production" ? propTypes : {};

const PrevButton = (_ref) => {
  let {
    nr,
    minDate,
    month,
    prevBtn,
    onPrev,
    locale,
    onKeyDown
  } = _ref;

  if (!prevBtn) {
    return React.createElement(React.Fragment, null);
  }

  const disabled = minDate && isSameMonth(month, minDate);

  const onClick = () => onPrev && !disabled && onPrev({
    nr
  });

  const title = format(subMonths(month, 1), 'MMMM YYYY', {
    locale
  });
  return React.createElement(Button, {
    className: classnames('dnb-date-picker__prev', {
      disabled
    }),
    icon: "chevron-left",
    size: "small",
    "aria-label": title,
    title: title,
    onClick: onClick,
    onKeyDown: onKeyDown
  });
};

PrevButton.propTypes = process.env.NODE_ENV !== "production" ? {
  nr: PropTypes.number.isRequired,
  minDate: PropTypes.instanceOf(Date),
  month: PropTypes.object.isRequired,
  locale: PropTypes.object.isRequired,
  prevBtn: PropTypes.bool.isRequired,
  onPrev: PropTypes.func.isRequired,
  onKeyDown: PropTypes.func
} : {};
PrevButton.defaultProps = {
  minDate: null,
  onKeyDown: null
};

const NextButton = (_ref2) => {
  let {
    nr,
    maxDate,
    month,
    nextBtn,
    onNext,
    locale,
    onKeyDown
  } = _ref2;

  if (!nextBtn) {
    return React.createElement(React.Fragment, null);
  }

  const disabled = maxDate && isSameMonth(month, maxDate);

  const onClick = () => onNext && !disabled && onNext({
    nr
  });

  const title = format(addMonths(month, 1), 'MMMM YYYY', {
    locale
  });
  return nextBtn && React.createElement(Button, {
    className: classnames('dnb-date-picker__next', {
      disabled
    }),
    icon: "chevron-right",
    size: "small",
    "aria-label": title,
    title: title,
    onClick: onClick,
    onKeyDown: onKeyDown
  });
};

NextButton.propTypes = process.env.NODE_ENV !== "production" ? {
  nr: PropTypes.number.isRequired,
  maxDate: PropTypes.instanceOf(Date),
  month: PropTypes.object.isRequired,
  locale: PropTypes.object.isRequired,
  nextBtn: PropTypes.bool.isRequired,
  onNext: PropTypes.func.isRequired,
  onKeyDown: PropTypes.func
} : {};
NextButton.defaultProps = {
  maxDate: null,
  onKeyDown: null
};

const onSelectRange = (_ref3) => {
  let {
    day,
    range,
    startDate,
    endDate,
    onSelect,
    resetDate
  } = _ref3;

  if (onSelect) {
    if (!range) {
      // set only date
      onSelect({
        startDate: startOfDay(day.date),
        endDate: endOfDay(day.date)
      }); // for setting date new on every selection, do this here
    } else if (!startDate || resetDate && startDate && endDate) {
      // set startDate
      // user is selecting startDate
      onSelect({
        startDate: startOfDay(day.date),
        endDate: null
      });
    } else {
      const hasEndDate = endDate; // set either startDate or endDate

      const daysToStartDate = Math.abs(differenceInCalendarDays(startDate, day.date));
      const daysToEndDate = Math.abs(differenceInCalendarDays(endDate, day.date));
      let range = toRange(startDate, day.date);

      if (hasEndDate && !resetDate && daysToStartDate < daysToEndDate) {
        range = toRange(endDate, day.date);
      }

      onSelect({
        startDate: startOfDay(range.startDate),
        endDate: endOfDay(range.endDate)
      });
    }
  }
};

const onHoverDay = (_ref4) => {
  let {
    day,
    hoverDate,
    onHover
  } = _ref4;

  if (!isSameDay(day.date, hoverDate)) {
    onHover && onHover(day.date);
  }
};