import React, { useCallback, useEffect, useMemo, useState } from "react";
import classnames from "classnames";
import moment from "moment";
import { DatePickerForm } from "./DatePickerForm";
import { SelectDateTarget } from "./SelectDateTarget";
import { StyledConfirmDialog, StyledSelectDate, StyledSelectDateButton } from "./Styles";
import { formatDate } from "../../utils/dateUtils";
import { useLocalization } from "../Localization";
import { Menu } from "../Menu/Menu";
import { Tooltip } from "../Tooltip/Tooltip";
const getUtcTimestampFromDate = date => {
  return moment.utc([date.getFullYear(), date.getMonth(), date.getDate()]).unix();
};
const isDayInRange = (day, data) => {
  if (data.repeating) {
    const from = new Date(day.getFullYear(), data.from.getMonth(), data.from.getDate());
    const to = new Date(day.getFullYear(), data.to.getMonth(), data.to.getDate());
    return day >= from && day <= to;
  }
  return day >= data.from && day <= data.to;
};
export const SelectDate = _ref => {
  let {
    changeMode: mode = "instant",
    trigger: labelType = "text",
    saveButtonText = "Save",
    cancelButtonText = "Cancel",
    clearButtonText = "Clear",
    modalHeaderText = "Discard changes?",
    modalDiscardMessage = "All unsaved changes will be lost.",
    modalDiscardBtnText = "OK",
    modalCancelBtnText = "Cancel",
    onDayClick,
    onSave,
    onCancel,
    onToggleDatePicker,
    required: dateRequired = false,
    defaultTimezoneAware = false,
    longDateFormat = false,
    defaultShowDatePicker = false,
    firstDayOfWeek = 0,
    selectedDays,
    selectionMode = "custom",
    menuClassName,
    targetClassName,
    icon,
    defaultLabelText = "Set...",
    targetTextClassName,
    targetIconClassName,
    backgroundElementClass,
    dateFormat: passedDateFormat,
    defaultMonth,
    daysToModify = [],
    weekends = [],
    weekendLabel = "Weekend",
    nonWorkingDaysOfWeek = [],
    nonWorkingDaysOfWeekLabel = "Unavailable",
    weekendIsSelectable = false,
    tooltipText,
    popperTooltipClassName,
    popperClassName,
    popperTooltipStyle,
    position,
    disableDaysBefore
  } = _ref;
  const [timezoneAware, setTimezoneAware] = useState(defaultTimezoneAware);
  const localization = useLocalization();
  const dateFormat = passedDateFormat ? passedDateFormat : localization.dateFormat;
  const labelText = useMemo(() => {
    if (!selectedDays) {
      return defaultLabelText;
    } else {
      const endDate = timezoneAware ? moment.unix(selectedDays.to).local() : moment.unix(selectedDays.to).utc();
      const startDate = timezoneAware ? moment.unix(selectedDays.from).local() : moment.unix(selectedDays.from).utc();
      const formattedEndDate = formatDate(endDate, dateFormat, longDateFormat);
      const formattedStartDate = formatDate(startDate, dateFormat, longDateFormat);
      if (selectedDays.from === selectedDays.to) {
        return formattedEndDate;
      }
      return formattedStartDate + " - " + formattedEndDate;
    }
  }, [selectedDays, dateFormat, timezoneAware, defaultLabelText, longDateFormat]);
  const modifiedDates = useMemo(() => {
    if (typeof selectedDays === "object" && !!selectedDays.from && !!selectedDays.to) {
      if (timezoneAware) {
        return {
          from: moment.unix(selectedDays.from).toDate(),
          to: moment.unix(selectedDays.to).toDate()
        };
      }
      const offsetFrom = moment.unix(selectedDays.from).utcOffset() * 60;
      const offsetTo = moment.unix(selectedDays.to).utcOffset() * 60;
      return {
        from: new Date((selectedDays.from - offsetFrom) * 1000),
        to: new Date((selectedDays.to - offsetTo) * 1000)
      };
    }
  }, [selectedDays, timezoneAware]);
  const handleModifiedSave = useCallback(selectedDates => {
    setTimezoneAware(false);
    if (typeof onSave === "function") {
      if (typeof selectedDates === "object" && Object.prototype.hasOwnProperty.call(selectedDates, "from") && Object.prototype.hasOwnProperty.call(selectedDates, "to")) {
        onSave({
          from: getUtcTimestampFromDate(selectedDates.from),
          to: getUtcTimestampFromDate(selectedDates.to)
        });
      } else {
        onSave(undefined);
      }
    }
  }, [onSave]);
  const getDefaultMonth = useCallback(() => {
    let date = new Date();
    if (typeof selectedDays === "object" && !!selectedDays.from) {
      date = timezoneAware ? new Date(selectedDays.from * 1000) : new Date((selectedDays.from - moment.unix(selectedDays.from).utcOffset() * 60) * 1000);
    } else if (defaultMonth) {
      date = defaultMonth;
    }

    // forcing second day in month
    return new Date(date.getFullYear(), date.getMonth(), 2);
  }, [defaultMonth, selectedDays, timezoneAware]);
  const [month, setMonth] = useState(getDefaultMonth);
  const handleMonthChange = useCallback(month => {
    setMonth(month);
  }, [setMonth]);
  const [newDates, setNewDates] = useState(modifiedDates);
  const [showDiscardModal, setShowDiscardModal] = useState(false);
  const [showDatePicker, setShowDatePicker] = useState(defaultShowDatePicker);
  const disabledSaveButton = useMemo(() => {
    return (modifiedDates == null ? void 0 : modifiedDates.from) === (newDates == null ? void 0 : newDates.from) && (modifiedDates == null ? void 0 : modifiedDates.to) === (newDates == null ? void 0 : newDates.to);
  }, [modifiedDates, newDates]);
  useEffect(() => {
    setShowDatePicker(defaultShowDatePicker);
  }, [defaultShowDatePicker]);
  useEffect(() => {
    setNewDates(modifiedDates);
  }, [modifiedDates]);
  useEffect(() => {
    typeof onToggleDatePicker === "function" && onToggleDatePicker(showDatePicker);
  }, [showDatePicker, onToggleDatePicker]);
  useEffect(() => {
    if (!showDatePicker) {
      setMonth(getDefaultMonth());
    }
  }, [showDatePicker, getDefaultMonth]);
  const handleSave = useCallback(() => {
    handleModifiedSave(newDates);
    setShowDatePicker(false);
  }, [newDates, handleModifiedSave]);
  const handleChange = useCallback(dates => {
    if (mode !== "atomic") {
      handleModifiedSave(dates);
    }
    setNewDates(dates);
  }, [mode, handleModifiedSave]);
  const handleBeforeCloseMenu = useCallback(() => {
    let result = true;
    if (modifiedDates && !newDates || !modifiedDates && newDates) {
      result = false;
    }
    const selectedDaysFrom = modifiedDates == null ? void 0 : modifiedDates.from;
    const selectedDaysTo = modifiedDates == null ? void 0 : modifiedDates.to;
    const newDatesFrom = newDates == null ? void 0 : newDates.from;
    const newDatesTo = newDates == null ? void 0 : newDates.to;
    if (selectedDaysFrom && newDatesFrom && selectedDaysTo && newDatesTo && (moment(selectedDaysFrom).format("DD-MM-YYYY") !== moment(newDatesFrom).format("DD-MM-YYYY") || moment(selectedDaysTo).format("DD-MM-YYYY") !== moment(newDatesTo).format("DD-MM-YYYY"))) {
      result = false;
    }
    if (!result) {
      setShowDiscardModal(true);
    }
    return result;
  }, [modifiedDates, newDates]);
  const handleClose = useCallback(() => {
    if (mode !== "atomic" || handleBeforeCloseMenu()) {
      typeof onCancel === "function" && onCancel();
      setShowDatePicker(false);
    }
  }, [mode, onCancel, handleBeforeCloseMenu]);
  const handleCancel = useCallback(event => {
    event && event.preventDefault();
    return handleClose();
  }, [handleClose]);
  const handleShowDatePicker = useCallback(() => {
    setShowDatePicker(!showDatePicker);
  }, [showDatePicker]);
  const handleCloseDiscardModal = useCallback(() => {
    setShowDiscardModal(false);
  }, []);
  const handleClear = useCallback(() => {
    if (!dateRequired) {
      setNewDates(undefined);
      if (mode === "instant") {
        handleModifiedSave(undefined);
      }
    }
  }, [mode, dateRequired, handleModifiedSave]);
  const handleSaveDiscardModal = useCallback(() => {
    setNewDates(modifiedDates);
    setShowDiscardModal(false);
    setShowDatePicker(false);
  }, [modifiedDates]);
  const modifiers = useMemo(() => {
    const userAvailabilities = daysToModify.filter(data => data.type === "user_day_off");
    const globalDaysOff = daysToModify.filter(data => data.type === "global_day_off");
    const selectableGlobalDaysOff = daysToModify.filter(data => data.type === "selectable_global_day_off");
    return {
      userAvailability: day => {
        // construct new date because react-day-picker returns date with hours set
        const currentDay = new Date(day.getFullYear(), day.getMonth(), day.getDate());
        return userAvailabilities.some(data => isDayInRange(currentDay, data));
      },
      weekend: day => {
        return weekends.some(value => day.getDay() === value);
      },
      nonWorkingDay: day => {
        // return true if day is weekend day
        if (weekends.some(value => value === day.getDay())) {
          return true;
        }
        const nonWorkingDays = [...selectableGlobalDaysOff, ...globalDaysOff];
        const currentDay = new Date(day.getFullYear(), day.getMonth(), day.getDate());
        return nonWorkingDays.some(data => isDayInRange(currentDay, data));
      },
      day_disabled: day => {
        if (disableDaysBefore) {
          if (day.toJSON().slice(0, 10) < disableDaysBefore.toJSON().slice(0, 10)) {
            return true;
          }
        }
        // return true if day is weekend day
        if (!weekendIsSelectable && weekends.some(value => value === day.getDay())) {
          return true;
        }
        // construct new date because react-day-picker returns date with hours set
        const currentDay = new Date(day.getFullYear(), day.getMonth(), day.getDate());
        return globalDaysOff.some(data => isDayInRange(currentDay, data));
      },
      nonWorkingDaysOfWeek: {
        dayOfWeek: nonWorkingDaysOfWeek
      }
    };
  }, [daysToModify, nonWorkingDaysOfWeek, weekends, disableDaysBefore, weekendIsSelectable]);
  const renderDay = useCallback(props => {
    const titles = [];
    if (weekends.some(value => props.date.getDay() === value)) {
      titles.push(weekendLabel);
    }
    if (nonWorkingDaysOfWeek.includes(props.date.getDay())) {
      titles.push(nonWorkingDaysOfWeekLabel);
    }

    // construct new date because react-day-picker returns date with hours set
    const currentDay = new Date(props.date.getFullYear(), props.date.getMonth(), props.date.getDate());
    daysToModify.forEach(data => {
      if (isDayInRange(currentDay, data)) {
        titles.push(data.title);
      }
    });
    const child = /*#__PURE__*/React.createElement("div", {
      className: "c-DayPicker-Day-Number"
    }, props.date.getDate());
    if (titles.length) {
      const title = /*#__PURE__*/React.createElement("div", {
        key: "title-wrapper-" + props.date.getDate()
      }, titles.map((title, index) => /*#__PURE__*/React.createElement("div", {
        key: "title-text-" + index
      }, title)));
      return /*#__PURE__*/React.createElement(Tooltip, {
        title: title,
        popperTooltipClassName: popperTooltipClassName,
        popperTooltipStyle: popperTooltipStyle
      }, child);
    }
    return child;
  }, [weekends, nonWorkingDaysOfWeek, daysToModify, weekendLabel, nonWorkingDaysOfWeekLabel, popperTooltipClassName, popperTooltipStyle]);
  const renderDatePickerForm = useCallback(() => {
    return /*#__PURE__*/React.createElement(DatePickerForm, {
      onMonthChange: handleMonthChange,
      month: month,
      mode: mode,
      selectionMode: selectionMode,
      dateRequired: dateRequired,
      selectedDays: newDates,
      firstDayOfWeek: firstDayOfWeek,
      saveButtonText: saveButtonText,
      cancelButtonText: cancelButtonText,
      clearButtonText: clearButtonText,
      onDayClick: onDayClick,
      onSave: handleSave,
      onChange: handleChange,
      onCancel: handleCancel,
      onClear: handleClear,
      disabledSaveButton: disabledSaveButton,
      modifiers: modifiers,
      renderDay: renderDay
    });
  }, [handleMonthChange, month, mode, selectionMode, dateRequired, newDates, firstDayOfWeek, saveButtonText, cancelButtonText, clearButtonText, onDayClick, handleSave, handleChange, handleCancel, handleClear, disabledSaveButton, modifiers, renderDay]);
  const renderTargetEl = useMemo(() => {
    if (labelType === "icon" && icon) {
      return /*#__PURE__*/React.createElement(SelectDateTarget, {
        icon: icon,
        title: tooltipText,
        targetIconClassName: targetIconClassName,
        forceHideTooltip: showDatePicker,
        popperTooltipClassName: popperTooltipClassName,
        popperTooltipStyle: popperTooltipStyle,
        active: showDatePicker
      });
    }
    if (typeof labelType === "function") {
      return labelType(labelText);
    }
    return /*#__PURE__*/React.createElement(StyledSelectDateButton, {
      type: "button",
      className: classnames("date-picker-target", targetClassName)
    }, /*#__PURE__*/React.createElement("span", {
      className: targetTextClassName
    }, labelText));
  }, [icon, labelText, labelType, popperTooltipClassName, popperTooltipStyle, showDatePicker, targetClassName, targetIconClassName, targetTextClassName, tooltipText]);
  return /*#__PURE__*/React.createElement(StyledSelectDate, {
    className: "select-date"
  }, labelType !== "inline" ? /*#__PURE__*/React.createElement(Menu, {
    target: renderTargetEl,
    open: showDatePicker,
    onOpen: handleShowDatePicker,
    onBeforeClose: handleBeforeCloseMenu,
    onClose: handleClose,
    position: position,
    menuClassName: menuClassName,
    popperClassName: popperClassName,
    backgroundElementClass: backgroundElementClass
  }, renderDatePickerForm()) : renderDatePickerForm(), mode === "atomic" ? /*#__PURE__*/React.createElement(StyledConfirmDialog, {
    className: "modal-select-date",
    open: showDiscardModal,
    onCancel: handleCloseDiscardModal,
    onConfirm: handleSaveDiscardModal,
    dialogTitle: modalHeaderText,
    dialogContent: modalDiscardMessage,
    cancelBtnText: modalCancelBtnText,
    confirmBtnText: modalDiscardBtnText
  }) : null);
};
SelectDate.displayName = "SelectDate";
//# sourceMappingURL=SelectDate.js.map