function _extends() {
  _extends = Object.assign ? Object.assign.bind() : function(target) {
    for (var i = 1; i < arguments.length; i++) {
      var source = arguments[i];
      for (var key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
          target[key] = source[key];
        }
      }
    }
    return target;
  };
  return _extends.apply(this, arguments);
}
import React, { forwardRef, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
import classnames from "classnames";
import { Popup } from "../popup";
import Button from "../button";
import Toast from "../toast/index";
import CalendarHeader from "./CalendarHeader";
import CalendarMonth from "./CalendarMonth";
import { useUpdateEffect } from "../hooks";
import { getRect } from "../hooks/get-rect";
import useRefs from "../hooks/use-refs";
import { calcDateNum, cloneDate, cloneDates, compareDay, compareMonth, getDayByOffset, getNextDay, getPrevDay, getToday, t } from "./utils";
import { getScrollTop, pick } from "../utils";
import { raf } from "../utils/raf";
import ConfigProviderContext from "../config-provider/ConfigProviderContext";
const Calendar = /* @__PURE__ */ forwardRef((props, ref) => {
  const {
    prefixCls,
    createNamespace
  } = useContext(ConfigProviderContext);
  const [bem] = createNamespace("calendar", prefixCls);
  const {
    type,
    title,
    showTitle,
    showSubtitle,
    firstDayOfWeek,
    minDate,
    maxDate,
    safeAreaInsetBottom,
    footer,
    showConfirm,
    className,
    style
  } = props;
  const limitDateRange = (date, minDate2 = props.minDate, maxDate2 = props.maxDate) => {
    if (compareDay(date, minDate2) === -1) {
      return minDate2;
    }
    if (compareDay(date, maxDate2) === 1) {
      return maxDate2;
    }
    return date;
  };
  const getInitialDate = (defaultDate = props.defaultDate) => {
    if (defaultDate === null) {
      return defaultDate;
    }
    const now = getToday();
    if (type === "range") {
      if (!Array.isArray(defaultDate)) {
        defaultDate = [];
      }
      const start = limitDateRange(defaultDate[0] || now, minDate, getPrevDay(maxDate));
      const end = limitDateRange(defaultDate[1] || now, getNextDay(minDate));
      return [start, end];
    }
    if (type === "multiple") {
      if (Array.isArray(defaultDate)) {
        return defaultDate.map((date) => limitDateRange(date));
      }
      return [limitDateRange(now)];
    }
    if (!defaultDate || Array.isArray(defaultDate)) {
      defaultDate = now;
    }
    return limitDateRange(defaultDate);
  };
  const bodyRef = useRef(null);
  const bodyHeightRef = useRef(0);
  const [subtitle, setSubtitle] = useState("");
  const [currentDate, setCurrentDate] = useState(getInitialDate());
  const [monthRefs, setMonthRefs] = useRefs();
  const dayOffset = useMemo(() => firstDayOfWeek ? +firstDayOfWeek % 7 : 0, [firstDayOfWeek]);
  const monthsList = useMemo(() => {
    const months = [];
    const cursor = new Date(minDate);
    cursor.setDate(1);
    do {
      months.push(new Date(cursor));
      cursor.setMonth(cursor.getMonth() + 1);
    } while (compareMonth(cursor, maxDate) !== 1);
    return months;
  }, [minDate, maxDate]);
  const buttonDisabled = useMemo(() => {
    if (currentDate) {
      if (props.type === "range") {
        return !currentDate[0] || !currentDate[1];
      }
      if (props.type === "multiple") {
        return !currentDate.length;
      }
    }
    return !currentDate;
  }, [props.type, currentDate]);
  const onScroll = () => {
    var _a;
    if (!bodyRef.current)
      return;
    const top = getScrollTop(bodyRef.current);
    const bottom = top + bodyHeightRef.current;
    const heights = monthsList.map((_, index) => monthRefs[index].getHeight());
    const heightSum = heights.reduce((a, b) => a + b, 0);
    if (bottom > heightSum && top > 0) {
      return;
    }
    let height = 0;
    let currentMonth;
    const visibleRange = [-1, -1];
    for (let i = 0; i < monthsList.length; i++) {
      const month = monthRefs[i];
      const visible = height <= bottom && height + heights[i] >= top;
      if (visible) {
        visibleRange[1] = i;
        if (!currentMonth) {
          currentMonth = month;
          visibleRange[0] = i;
        }
        if (!monthRefs[i].showed) {
          monthRefs[i].showed = true;
          (_a = props.onMonthShow) == null ? void 0 : _a.call(props, {
            date: month.date,
            title: month.getTitle()
          });
        }
      }
      height += heights[i];
    }
    monthsList.forEach((_, index) => {
      const visible = index >= visibleRange[0] - 1 && index <= visibleRange[1] + 1;
      monthRefs[index].setVisible(visible);
    });
    if (currentMonth) {
      setSubtitle(currentMonth.getTitle());
    }
  };
  const scrollToDate = (targetDate) => {
    raf(() => {
      monthsList.some((month, index) => {
        if (compareMonth(month, targetDate) === 0) {
          if (bodyRef.current) {
            monthRefs[index].scrollToDate(bodyRef.current, targetDate);
          }
          return true;
        }
        return false;
      });
      onScroll();
    });
  };
  const scrollToCurrentDate = (date) => {
    if (props.poppable && !props.show) {
      return;
    }
    const currentDate2 = date || getInitialDate();
    if (currentDate2) {
      const targetDate = props.type === "single" ? currentDate2 : currentDate2[0];
      scrollToDate(targetDate);
    } else {
      raf(onScroll);
    }
  };
  const init = () => {
    if (props.poppable && !props.show) {
      return;
    }
    raf(() => {
      bodyHeightRef.current = Math.floor(getRect(bodyRef.current).height);
      scrollToCurrentDate();
    });
  };
  const reset = (date = getInitialDate()) => {
    setCurrentDate(date);
    scrollToCurrentDate(date);
  };
  const onConfirm = (date) => {
    var _a;
    (_a = props.onConfirm) == null ? void 0 : _a.call(props, cloneDates(date || currentDate));
  };
  const checkRange = (date) => {
    var _a;
    const {
      maxRange,
      rangePrompt,
      showRangePrompt
    } = props;
    if (maxRange && calcDateNum(date) > maxRange) {
      if (showRangePrompt) {
        Toast(rangePrompt || t("rangePrompt", maxRange));
      }
      (_a = props.onOverRange) == null ? void 0 : _a.call(props);
      return false;
    }
    return true;
  };
  const select = (date, complete) => {
    const toSetCurrentDate = (date2) => {
      var _a;
      setCurrentDate(date2);
      (_a = props.onSelect) == null ? void 0 : _a.call(props, cloneDates(date2));
    };
    if (complete && props.type === "range") {
      const valid = checkRange(date);
      if (!valid) {
        toSetCurrentDate([date[0], getDayByOffset(date[0], +props.maxRange - 1)]);
        return;
      }
    }
    toSetCurrentDate(date);
    if (complete && !props.showConfirm) {
      onConfirm(date);
    }
  };
  const onClickDay = (item) => {
    var _a;
    if (props.readonly || !item.date) {
      return;
    }
    const {
      date
    } = item;
    const {
      type: type2
    } = props;
    if (type2 === "range") {
      if (!currentDate) {
        select([date]);
        return;
      }
      const [startDay, endDay] = currentDate;
      if (startDay && !endDay) {
        const compareToStart = compareDay(date, startDay);
        if (compareToStart === 1) {
          select([startDay, date], true);
        } else if (compareToStart === -1) {
          select([date]);
        } else if (props.allowSameDay) {
          select([date, date], true);
        }
      } else {
        select([date]);
      }
    } else if (type2 === "multiple") {
      if (!currentDate) {
        select([date]);
        return;
      }
      const dates = currentDate;
      const selectedIndex = dates.findIndex((dateItem) => compareDay(dateItem, date) === 0);
      if (selectedIndex !== -1) {
        const [unselectedDate] = dates.splice(selectedIndex, 1);
        (_a = props.onUnselect) == null ? void 0 : _a.call(props, cloneDate(unselectedDate));
        setCurrentDate([...dates]);
      } else if (props.maxRange && dates.length >= props.maxRange) {
        Toast(props.rangePrompt || t("rangePrompt", props.maxRange));
      } else {
        select([...dates, date]);
      }
    } else {
      select(date, true);
    }
  };
  const renderMonth = (date, index) => {
    const showMonthTitle = index !== 0 || !props.showSubtitle;
    return /* @__PURE__ */ React.createElement(CalendarMonth, _extends({
      key: index,
      ref: setMonthRefs(index),
      date,
      currentDate,
      showMonthTitle,
      firstDayOfWeek: dayOffset
    }, pick(props, ["type", "color", "minDate", "maxDate", "showMark", "formatter", "rowHeight", "lazyRender", "showSubtitle", "allowSameDay"]), {
      onClick: onClickDay
    }));
  };
  const renderFooter = () => {
    const disabled = buttonDisabled;
    const text = disabled ? props.confirmDisabledText : props.confirmText;
    return /* @__PURE__ */ React.createElement("div", {
      className: classnames(bem("footer"), {
        "rc-safe-area-bottom": safeAreaInsetBottom
      })
    }, footer || (showConfirm ? /* @__PURE__ */ React.createElement(Button, {
      round: true,
      block: true,
      type: "danger",
      color: props.color,
      className: classnames(bem("confirm")),
      disabled: buttonDisabled,
      nativeType: "button",
      onClick: () => onConfirm()
    }, text || "\u786E\u8BA4") : null));
  };
  const renderCalendar = () => /* @__PURE__ */ React.createElement("div", {
    className: classnames(bem(), className),
    style
  }, /* @__PURE__ */ React.createElement(CalendarHeader, {
    title,
    subtitle: props.subtitle || subtitle,
    showTitle,
    showSubtitle,
    firstDayOfWeek,
    onClickSubtitle: (event) => {
      var _a;
      (_a = props.onClickSubtitle) == null ? void 0 : _a.call(props, event);
    }
  }), /* @__PURE__ */ React.createElement("div", {
    ref: bodyRef,
    className: classnames(bem("body")),
    onScroll
  }, monthsList.map(renderMonth)), renderFooter());
  useEffect(() => {
    init();
  }, [props.show]);
  useUpdateEffect(() => {
    reset(getInitialDate());
  }, [props.type, props.minDate, props.maxDate]);
  useUpdateEffect(() => {
    setCurrentDate(props.defaultDate);
    scrollToCurrentDate();
  }, [props.defaultDate]);
  useImperativeHandle(ref, () => ({
    reset,
    scrollToDate
  }));
  return props.poppable ? /* @__PURE__ */ React.createElement(Popup, {
    visible: props.show,
    className: classnames(bem("popup")),
    round: props.round,
    position: props.position,
    closeable: props.showTitle || props.showSubtitle,
    teleport: props.teleport,
    closeOnClickOverlay: props.closeOnClickOverlay,
    closeOnPopstate: props.closeOnPopstate,
    onClose: () => {
      var _a;
      return (_a = props.onClose) == null ? void 0 : _a.call(props);
    }
  }, renderCalendar()) : /* @__PURE__ */ React.createElement(React.Fragment, null, renderCalendar());
});
Calendar.defaultProps = {
  type: "single",
  title: "\u65E5\u671F\u9009\u62E9",
  color: "#ee0a24",
  rowHeight: 64,
  poppable: true,
  lazyRender: true,
  showMark: true,
  showTitle: true,
  showSubtitle: true,
  showConfirm: true,
  showRangePrompt: true,
  readonly: false,
  firstDayOfWeek: 0,
  footer: null,
  minDate: getToday(),
  maxDate: (() => {
    const now = getToday();
    return new Date(now.getFullYear(), now.getMonth() + 6, now.getDate());
  })(),
  show: false,
  position: "bottom",
  round: true,
  closeOnPopstate: true,
  closeOnClickOverlay: true,
  safeAreaInsetBottom: true,
  maxRange: null,
  allowSameDay: false
};
var stdin_default = Calendar;
export {
  stdin_default as default
};
