"use strict";
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
const Vue = require("vue");
const utils = require("./utils.js");
const index_esm = require("../../../@vant/use/dist/index.esm.js");
const useRefs = require("../composables/use-refs.js");
const useExpose = require("../composables/use-expose.js");
const index = require("../popup/index.js");
const index$1 = require("../button/index.js");
require("../toast/index.js");
const CalendarMonth = require("./CalendarMonth.js");
const CalendarHeader = require("./CalendarHeader.js");
const basic = require("../utils/basic.js");
const functionCall = require("../toast/function-call.js");
const props = require("../utils/props.js");
const dom = require("../utils/dom.js");
const calendarProps = {
  show: Boolean,
  type: props.makeStringProp("single"),
  switchMode: props.makeStringProp("none"),
  title: String,
  color: String,
  round: props.truthProp,
  readonly: Boolean,
  poppable: props.truthProp,
  maxRange: props.makeNumericProp(null),
  position: props.makeStringProp("bottom"),
  teleport: [String, Object],
  showMark: props.truthProp,
  showTitle: props.truthProp,
  formatter: Function,
  rowHeight: props.numericProp,
  confirmText: String,
  rangePrompt: String,
  lazyRender: props.truthProp,
  showConfirm: props.truthProp,
  defaultDate: [Date, Array],
  allowSameDay: Boolean,
  showSubtitle: props.truthProp,
  closeOnPopstate: props.truthProp,
  showRangePrompt: props.truthProp,
  confirmDisabledText: String,
  closeOnClickOverlay: props.truthProp,
  safeAreaInsetTop: Boolean,
  safeAreaInsetBottom: props.truthProp,
  minDate: {
    type: Date,
    validator: basic.isDate
  },
  maxDate: {
    type: Date,
    validator: basic.isDate
  },
  firstDayOfWeek: {
    type: props.numericProp,
    default: 0,
    validator: (val) => val >= 0 && val <= 6
  }
};
var stdin_default = Vue.defineComponent({
  name: utils.name,
  props: calendarProps,
  emits: ["select", "confirm", "unselect", "monthShow", "overRange", "update:show", "clickSubtitle", "clickDisabledDate", "clickOverlay", "panelChange"],
  setup(props2, {
    emit,
    slots
  }) {
    const canSwitch = Vue.computed(() => props2.switchMode !== "none");
    const minDate = Vue.computed(() => {
      if (!props2.minDate && !canSwitch.value) {
        return utils.getToday();
      }
      return props2.minDate;
    });
    const maxDate = Vue.computed(() => {
      if (!props2.maxDate && !canSwitch.value) {
        return utils.getMonthByOffset(utils.getToday(), 6);
      }
      return props2.maxDate;
    });
    const limitDateRange = (date, min = minDate.value, max = maxDate.value) => {
      if (min && utils.compareDay(date, min) === -1) {
        return min;
      }
      if (max && utils.compareDay(date, max) === 1) {
        return max;
      }
      return date;
    };
    const getInitialDate = (defaultDate = props2.defaultDate) => {
      const {
        type,
        allowSameDay
      } = props2;
      if (defaultDate === null) {
        return defaultDate;
      }
      const now = utils.getToday();
      if (type === "range") {
        if (!Array.isArray(defaultDate)) {
          defaultDate = [];
        }
        if (defaultDate.length === 1 && utils.compareDay(defaultDate[0], now) === 1) {
          defaultDate = [];
        }
        const min = minDate.value;
        const max = maxDate.value;
        const start = limitDateRange(defaultDate[0] || now, min, max ? allowSameDay ? max : utils.getPrevDay(max) : void 0);
        const end = limitDateRange(defaultDate[1] || (allowSameDay ? now : utils.getNextDay(now)), min ? allowSameDay ? min : utils.getNextDay(min) : void 0);
        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 getInitialPanelDate = () => {
      const date = Array.isArray(currentDate.value) ? currentDate.value[0] : currentDate.value;
      return date ? date : limitDateRange(utils.getToday());
    };
    let bodyHeight;
    const bodyRef = Vue.ref();
    const currentDate = Vue.ref(getInitialDate());
    const currentPanelDate = Vue.ref(getInitialPanelDate());
    const currentMonthRef = Vue.ref();
    const [monthRefs, setMonthRefs] = useRefs.useRefs();
    const dayOffset = Vue.computed(() => props2.firstDayOfWeek ? +props2.firstDayOfWeek % 7 : 0);
    const months = Vue.computed(() => {
      const months2 = [];
      if (!minDate.value || !maxDate.value) {
        return months2;
      }
      const cursor = new Date(minDate.value);
      cursor.setDate(1);
      do {
        months2.push(new Date(cursor));
        cursor.setMonth(cursor.getMonth() + 1);
      } while (utils.compareMonth(cursor, maxDate.value) !== 1);
      return months2;
    });
    const buttonDisabled = Vue.computed(() => {
      if (currentDate.value) {
        if (props2.type === "range") {
          return !currentDate.value[0] || !currentDate.value[1];
        }
        if (props2.type === "multiple") {
          return !currentDate.value.length;
        }
      }
      return !currentDate.value;
    });
    const getSelectedDate = () => currentDate.value;
    const onScroll = () => {
      const top = dom.getScrollTop(bodyRef.value);
      const bottom = top + bodyHeight;
      const heights = months.value.map((item, index2) => monthRefs.value[index2].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 < months.value.length; i++) {
        const month = monthRefs.value[i];
        const visible = height <= bottom && height + heights[i] >= top;
        if (visible) {
          visibleRange[1] = i;
          if (!currentMonth) {
            currentMonth = month;
            visibleRange[0] = i;
          }
          if (!monthRefs.value[i].showed) {
            monthRefs.value[i].showed = true;
            emit("monthShow", {
              date: month.date,
              title: month.getTitle()
            });
          }
        }
        height += heights[i];
      }
      months.value.forEach((month, index2) => {
        const visible = index2 >= visibleRange[0] - 1 && index2 <= visibleRange[1] + 1;
        monthRefs.value[index2].setVisible(visible);
      });
      if (currentMonth) {
        currentMonthRef.value = currentMonth;
      }
    };
    const scrollToDate = (targetDate) => {
      if (canSwitch.value) {
        currentPanelDate.value = targetDate;
      } else {
        index_esm.raf(() => {
          months.value.some((month, index2) => {
            if (utils.compareMonth(month, targetDate) === 0) {
              if (bodyRef.value) {
                monthRefs.value[index2].scrollToDate(bodyRef.value, targetDate);
              }
              return true;
            }
            return false;
          });
          onScroll();
        });
      }
    };
    const scrollToCurrentDate = () => {
      if (props2.poppable && !props2.show) {
        return;
      }
      if (currentDate.value) {
        const targetDate = props2.type === "single" ? currentDate.value : currentDate.value[0];
        if (basic.isDate(targetDate)) {
          scrollToDate(targetDate);
        }
      } else if (!canSwitch.value) {
        index_esm.raf(onScroll);
      }
    };
    const init = () => {
      if (props2.poppable && !props2.show) {
        return;
      }
      if (!canSwitch.value) {
        index_esm.raf(() => {
          bodyHeight = Math.floor(index_esm.useRect(bodyRef).height);
        });
      }
      scrollToCurrentDate();
    };
    const reset = (date = getInitialDate()) => {
      currentDate.value = date;
      scrollToCurrentDate();
    };
    const checkRange = (date) => {
      const {
        maxRange,
        rangePrompt,
        showRangePrompt
      } = props2;
      if (maxRange && utils.calcDateNum(date) > +maxRange) {
        if (showRangePrompt) {
          functionCall.showToast(rangePrompt || utils.t("rangePrompt", maxRange));
        }
        emit("overRange");
        return false;
      }
      return true;
    };
    const onPanelChange = (date) => {
      currentPanelDate.value = date;
      emit("panelChange", {
        date
      });
    };
    const onConfirm = () => {
      var _a;
      return emit("confirm", (_a = currentDate.value) != null ? _a : utils.cloneDates(currentDate.value));
    };
    const select = (date, complete) => {
      const setCurrentDate = (date2) => {
        currentDate.value = date2;
        emit("select", utils.cloneDates(date2));
      };
      if (complete && props2.type === "range") {
        const valid = checkRange(date);
        if (!valid) {
          setCurrentDate([date[0], utils.getDayByOffset(date[0], +props2.maxRange - 1)]);
          return;
        }
      }
      setCurrentDate(date);
      if (complete && !props2.showConfirm) {
        onConfirm();
      }
    };
    const getDisabledDate = (disabledDays2, startDay, date) => {
      var _a;
      return (_a = disabledDays2.find((day) => utils.compareDay(startDay, day.date) === -1 && utils.compareDay(day.date, date) === -1)) == null ? void 0 : _a.date;
    };
    const disabledDays = Vue.computed(() => monthRefs.value.reduce((arr, ref2) => {
      var _a, _b;
      arr.push(...(_b = (_a = ref2.disabledDays) == null ? void 0 : _a.value) != null ? _b : []);
      return arr;
    }, []));
    const onClickDay = (item) => {
      if (props2.readonly || !item.date) {
        return;
      }
      const {
        date
      } = item;
      const {
        type
      } = props2;
      if (type === "range") {
        if (!currentDate.value) {
          select([date]);
          return;
        }
        const [startDay, endDay] = currentDate.value;
        if (startDay && !endDay) {
          const compareToStart = utils.compareDay(date, startDay);
          if (compareToStart === 1) {
            const disabledDay = getDisabledDate(disabledDays.value, startDay, date);
            if (disabledDay) {
              const endDay2 = utils.getPrevDay(disabledDay);
              if (utils.compareDay(startDay, endDay2) === -1) {
                select([startDay, endDay2]);
              } else {
                select([date]);
              }
            } else {
              select([startDay, date], true);
            }
          } else if (compareToStart === -1) {
            select([date]);
          } else if (props2.allowSameDay) {
            select([date, date], true);
          }
        } else {
          select([date]);
        }
      } else if (type === "multiple") {
        if (!currentDate.value) {
          select([date]);
          return;
        }
        const dates = currentDate.value;
        const selectedIndex = dates.findIndex((dateItem) => utils.compareDay(dateItem, date) === 0);
        if (selectedIndex !== -1) {
          const [unselectedDate] = dates.splice(selectedIndex, 1);
          emit("unselect", utils.cloneDate(unselectedDate));
        } else if (props2.maxRange && dates.length >= +props2.maxRange) {
          functionCall.showToast(props2.rangePrompt || utils.t("rangePrompt", props2.maxRange));
        } else {
          select([...dates, date]);
        }
      } else {
        select(date, true);
      }
    };
    const onClickOverlay = (event) => emit("clickOverlay", event);
    const updateShow = (value) => emit("update:show", value);
    const renderMonth = (date, index2) => {
      const showMonthTitle = index2 !== 0 || !props2.showSubtitle;
      return Vue.createVNode(CalendarMonth.default, Vue.mergeProps({
        "ref": canSwitch.value ? currentMonthRef : setMonthRefs(index2),
        "date": date,
        "currentDate": currentDate.value,
        "showMonthTitle": showMonthTitle,
        "firstDayOfWeek": dayOffset.value,
        "lazyRender": canSwitch.value ? false : props2.lazyRender,
        "maxDate": maxDate.value,
        "minDate": minDate.value
      }, basic.pick(props2, ["type", "color", "showMark", "formatter", "rowHeight", "showSubtitle", "allowSameDay"]), {
        "onClick": onClickDay,
        "onClickDisabledDate": (item) => emit("clickDisabledDate", item)
      }), basic.pick(slots, ["top-info", "bottom-info", "month-title", "text"]));
    };
    const renderFooterButton = () => {
      if (slots.footer) {
        return slots.footer();
      }
      if (props2.showConfirm) {
        const slot = slots["confirm-text"];
        const disabled = buttonDisabled.value;
        const text = disabled ? props2.confirmDisabledText : props2.confirmText;
        return Vue.createVNode(index$1.Button, {
          "round": true,
          "block": true,
          "type": "primary",
          "color": props2.color,
          "class": utils.bem("confirm"),
          "disabled": disabled,
          "nativeType": "button",
          "onClick": onConfirm
        }, {
          default: () => [slot ? slot({
            disabled
          }) : text || utils.t("confirm")]
        });
      }
    };
    const renderFooter = () => Vue.createVNode("div", {
      "class": [utils.bem("footer"), {
        "van-safe-area-bottom": props2.safeAreaInsetBottom
      }]
    }, [renderFooterButton()]);
    const renderCalendar = () => {
      var _a, _b;
      return Vue.createVNode("div", {
        "class": utils.bem()
      }, [Vue.createVNode(CalendarHeader.default, {
        "date": (_a = currentMonthRef.value) == null ? void 0 : _a.date,
        "maxDate": maxDate.value,
        "minDate": minDate.value,
        "title": props2.title,
        "subtitle": (_b = currentMonthRef.value) == null ? void 0 : _b.getTitle(),
        "showTitle": props2.showTitle,
        "showSubtitle": props2.showSubtitle,
        "switchMode": props2.switchMode,
        "firstDayOfWeek": dayOffset.value,
        "onClickSubtitle": (event) => emit("clickSubtitle", event),
        "onPanelChange": onPanelChange
      }, basic.pick(slots, ["title", "subtitle", "prev-month", "prev-year", "next-month", "next-year"])), Vue.createVNode("div", {
        "ref": bodyRef,
        "class": utils.bem("body"),
        "onScroll": canSwitch.value ? void 0 : onScroll
      }, [canSwitch.value ? renderMonth(currentPanelDate.value, 0) : months.value.map(renderMonth)]), renderFooter()]);
    };
    Vue.watch(() => props2.show, init);
    Vue.watch(() => [props2.type, props2.minDate, props2.maxDate, props2.switchMode], () => reset(getInitialDate(currentDate.value)));
    Vue.watch(() => props2.defaultDate, (value) => {
      reset(value);
    });
    useExpose.useExpose({
      reset,
      scrollToDate,
      getSelectedDate
    });
    index_esm.onMountedOrActivated(init);
    return () => {
      if (props2.poppable) {
        return Vue.createVNode(index.Popup, {
          "show": props2.show,
          "class": utils.bem("popup"),
          "round": props2.round,
          "position": props2.position,
          "closeable": props2.showTitle || props2.showSubtitle,
          "teleport": props2.teleport,
          "closeOnPopstate": props2.closeOnPopstate,
          "safeAreaInsetTop": props2.safeAreaInsetTop,
          "closeOnClickOverlay": props2.closeOnClickOverlay,
          "onClickOverlay": onClickOverlay,
          "onUpdate:show": updateShow
        }, {
          default: renderCalendar
        });
      }
      return renderCalendar();
    };
  }
});
exports.calendarProps = calendarProps;
exports.default = stdin_default;
