var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// src/components/pisellRecordBoard/shellFrame/Calendar/BookingCalendar.tsx
var BookingCalendar_exports = {};
__export(BookingCalendar_exports, {
  default: () => BookingCalendar
});
module.exports = __toCommonJS(BookingCalendar_exports);
var import_react = __toESM(require("react"));
var import_antd = require("antd");
var import_icons = require("@ant-design/icons");
var import_utils = require("../../../pisellTimeNavigator/utils");
var import_calendarPersistGuard = require("./calendarPersistGuard");
var import_bookingCalendarConstants = require("./const/bookingCalendarConstants");
var import_bookingCalendarDateUtils = require("./utils/bookingCalendarDateUtils");
var import_MoveConfirmModal = require("./modal/MoveConfirmModal");
var import_OverflowListModal = require("./modal/OverflowListModal");
var import_bookingCalendarViewShared = require("./bookingCalendarViewShared");
var import_calendarI18n = require("./calendarI18n");
var import_BookingCalendarMonthView = require("./view/BookingCalendarMonthView");
var import_BookingCalendarWeekView = require("./view/BookingCalendarWeekView");
var import_BookingCalendarDayView = require("./view/BookingCalendarDayView");
var import_BookingCalendar = require("./BookingCalendar.less");
var { RangePicker } = import_antd.DatePicker;
function BookingCalendar(props = {}) {
  const allowPersist = (0, import_calendarPersistGuard.useCalendarPersist)();
  const courts = (0, import_react.useMemo)(() => {
    const r = props.resources;
    if (Array.isArray(r) && r.length > 0) {
      const mapped = r.filter(
        (x) => x && x.id !== void 0 && x.id !== null && String(x.id).trim() !== ""
      ).map((x) => ({
        id: String(x.id),
        name: x.name != null && String(x.name).trim() !== "" ? String(x.name) : String(x.id),
        type: x.groupType && String(x.groupType).trim() !== "" ? String(x.groupType) : (0, import_calendarI18n.tCal)("pisell2.recordBoard.calendar.common.resourceFallback")
      }));
      if (mapped.length > 0) return mapped;
    }
    return [];
  }, [props.resources]);
  const isLight = props.appearance === "light";
  const [internalView, setInternalView] = (0, import_react.useState)("month");
  const [internalAnchor, setInternalAnchor] = (0, import_react.useState)(() => /* @__PURE__ */ new Date());
  const view = props.calendarView != null ? props.calendarView : internalView;
  const linkedAnchorMs = props.anchorDate != null ? props.anchorDate.getTime() : null;
  const anchorDate = (0, import_react.useMemo)(() => {
    if (props.anchorDate != null) {
      return new Date(props.anchorDate);
    }
    return internalAnchor;
  }, [linkedAnchorMs, internalAnchor]);
  const resolvedSlotMinutes = (0, import_react.useMemo)(() => {
    const raw = props.slotStepMinutes ?? 60;
    const n = Math.round(Number(raw));
    if (!Number.isFinite(n) || n < 1) return 60;
    return Math.min(24 * 60, n);
  }, [props.slotStepMinutes]);
  const slotStepHours = resolvedSlotMinutes / 60;
  const slotColWidth = import_bookingCalendarConstants.dayColWidth;
  const timelinePxPerHour = import_bookingCalendarConstants.dayColWidth / slotStepHours;
  const commitView = (v) => {
    var _a;
    (_a = props.onCalendarViewChange) == null ? void 0 : _a.call(props, v);
    if (!props.onCalendarViewChange) {
      setInternalView(v);
    }
  };
  const commitAnchor = (d) => {
    var _a;
    (_a = props.onAnchorDateChange) == null ? void 0 : _a.call(props, d);
    if (!props.onAnchorDateChange) {
      setInternalAnchor(d);
    }
  };
  const [internalBookings, setBookings] = (0, import_react.useState)([]);
  const isControlledBookings = props.bookings != null;
  const bookings = isControlledBookings ? props.bookings : internalBookings;
  (0, import_react.useEffect)(() => {
    if (!props.onViewportChange) return;
    const a = new Date(anchorDate);
    let rangeStart;
    let rangeEnd;
    if (view === "month") {
      rangeStart = new Date(a.getFullYear(), a.getMonth(), 1);
      rangeEnd = new Date(a.getFullYear(), a.getMonth() + 1, 0);
    } else if (view === "week") {
      rangeStart = (0, import_bookingCalendarDateUtils.startOfWeek)(a);
      rangeEnd = (0, import_bookingCalendarDateUtils.addDays)(rangeStart, 6);
    } else {
      rangeStart = new Date(a);
      rangeEnd = new Date(a);
    }
    props.onViewportChange({
      view,
      anchorDate: a,
      rangeStart,
      rangeEnd
    });
  }, [view, anchorDate, props.onViewportChange]);
  const [selectedFreeSlots, setSelectedFreeSlots] = (0, import_react.useState)([]);
  const [selectedBlockSlots, setSelectedBlockSlots] = (0, import_react.useState)([]);
  const [focusedCourtId, setFocusedCourtId] = (0, import_react.useState)(null);
  const [showBlockPanel, setShowBlockPanel] = (0, import_react.useState)(false);
  const [blockFormName, setBlockFormName] = (0, import_react.useState)(
    () => (0, import_calendarI18n.tCal)("pisell2.recordBoard.calendar.block.defaultTitle")
  );
  const [blockModalNote, setBlockModalNote] = (0, import_react.useState)("");
  const [blockResourceId, setBlockResourceId] = (0, import_react.useState)("");
  const [blockTimeRange, setBlockTimeRange] = (0, import_react.useState)(null);
  const [blockSaving, setBlockSaving] = (0, import_react.useState)(false);
  const [transitioningToDay, setTransitioningToDay] = (0, import_react.useState)(null);
  const [navDirection, setNavDirection] = (0, import_react.useState)(0);
  const [overflowPopover, setOverflowPopover] = (0, import_react.useState)(null);
  const [overflowListModal, setOverflowListModal] = (0, import_react.useState)(null);
  const [draggingItem, setDraggingItem] = (0, import_react.useState)(null);
  const [moveConfirm, setMoveConfirm] = (0, import_react.useState)(null);
  const [moveDraft, setMoveDraft] = (0, import_react.useState)(null);
  const [collapsedGroups, setCollapsedGroups] = (0, import_react.useState)({
    VIP: false,
    Standard: false
  });
  const blockPanelRef = (0, import_react.useRef)(null);
  const overflowPanelRef = (0, import_react.useRef)(null);
  const moveConfirmRef = (0, import_react.useRef)(null);
  const visibleCourts = (0, import_react.useMemo)(() => courts, [courts]);
  const visibleCourtRows = (0, import_react.useMemo)(
    () => (0, import_bookingCalendarViewShared.buildGroupedCourtRows)(visibleCourts, collapsedGroups),
    [visibleCourts, collapsedGroups]
  );
  const dayKey = (0, import_bookingCalendarDateUtils.fmtDate)(anchorDate);
  const hourSlots = (0, import_react.useMemo)(
    () => (0, import_utils.buildCalendarTimelineSlotStartsFromRange)(
      props.timelineRange ?? import_bookingCalendarConstants.DEFAULT_CALENDAR_TIMELINE,
      anchorDate,
      resolvedSlotMinutes
    ),
    [props.timelineRange, anchorDate, resolvedSlotMinutes]
  );
  const {
    dayRowHeights,
    dayRowTopMap,
    overlayBookings,
    courtDayDisplayLaneCount,
    hiddenDayOverlayIdSet,
    dayOverlayOverflowPluses
  } = (0, import_react.useMemo)(() => {
    const defaultHeights = visibleCourtRows.map(
      (row) => row.kind === "group" ? import_bookingCalendarConstants.groupRowHeight : import_bookingCalendarConstants.dayRowHeight
    );
    let tops = (0, import_bookingCalendarDateUtils.buildDayRowTopMap)(visibleCourtRows, defaultHeights);
    let overlays = (0, import_bookingCalendarDateUtils.buildOverlayBookings)(
      visibleCourtRows,
      dayKey,
      bookings,
      tops,
      hourSlots,
      defaultHeights,
      slotStepHours
    );
    const expandedHeights = visibleCourtRows.map(
      (row, i) => {
        if (row.kind !== "court") return defaultHeights[i];
        const lc = (0, import_bookingCalendarDateUtils.maxConcurrentBookingsOnCourt)(overlays, row.id);
        const displayLc = (0, import_bookingCalendarDateUtils.effectiveDayOverlayDisplayLaneCount)(lc);
        if (displayLc <= 1) return import_bookingCalendarConstants.dayRowHeight;
        const need = import_bookingCalendarConstants.DAY_OVERLAY_INNER_TOP + import_bookingCalendarConstants.DAY_OVERLAY_INNER_BOTTOM + displayLc * import_bookingCalendarConstants.DAY_OVERLAY_LANE_MIN_PX + (displayLc - 1) * import_bookingCalendarConstants.DAY_OVERLAY_LANE_GAP;
        return Math.max(import_bookingCalendarConstants.dayRowHeight, need);
      }
    );
    const tops2 = (0, import_bookingCalendarDateUtils.buildDayRowTopMap)(visibleCourtRows, expandedHeights);
    overlays = (0, import_bookingCalendarDateUtils.buildOverlayBookings)(
      visibleCourtRows,
      dayKey,
      bookings,
      tops2,
      hourSlots,
      expandedHeights,
      slotStepHours
    );
    const courtDayDisplayLaneCount2 = {};
    const hiddenDayOverlayIdSet2 = /* @__PURE__ */ new Set();
    const dayOverlayOverflowPluses2 = [];
    for (const row of visibleCourtRows) {
      if (row.kind !== "court") continue;
      const cid = row.id;
      const rawLc = (0, import_bookingCalendarDateUtils.maxConcurrentBookingsOnCourt)(overlays, cid);
      courtDayDisplayLaneCount2[cid] = (0, import_bookingCalendarDateUtils.effectiveDayOverlayDisplayLaneCount)(rawLc);
      const clusters = (0, import_bookingCalendarDateUtils.clusterDayCourtOverlaysByOverlap)(overlays, cid);
      for (const cluster of clusters) {
        if (cluster.length <= import_bookingCalendarConstants.DAY_OVERLAY_VISIBLE_BOOKING_CAP) continue;
        const sortedByLane = [...cluster].sort(
          (a, b) => (a.lane ?? 0) - (b.lane ?? 0) || a.start - b.start
        );
        for (let i = import_bookingCalendarConstants.DAY_OVERLAY_VISIBLE_BOOKING_CAP; i < sortedByLane.length; i++) {
          const o = sortedByLane[i];
          hiddenDayOverlayIdSet2.add(
            (0, import_bookingCalendarDateUtils.dayOverlayHiddenKey)(o.item, dayKey, o.courtId)
          );
        }
        const hidden = sortedByLane.slice(import_bookingCalendarConstants.DAY_OVERLAY_VISIBLE_BOOKING_CAP);
        let minS = Infinity;
        let maxE = -Infinity;
        for (const o of cluster) {
          minS = Math.min(minS, o.start);
          maxE = Math.max(maxE, o.start + o.span);
        }
        const anchor = hidden[0];
        dayOverlayOverflowPluses2.push({
          key: `${cid}-${minS}-${maxE}-${dayKey}`,
          courtId: cid,
          rowTop: anchor.rowTop,
          rowHeight: anchor.rowHeight,
          start: minS,
          span: maxE - minS,
          plusCount: hidden.length,
          overflowItems: hidden.map((o) => o.item)
        });
      }
    }
    return {
      dayRowHeights: expandedHeights,
      dayRowTopMap: tops2,
      overlayBookings: overlays,
      courtDayDisplayLaneCount: courtDayDisplayLaneCount2,
      hiddenDayOverlayIdSet: hiddenDayOverlayIdSet2,
      dayOverlayOverflowPluses: dayOverlayOverflowPluses2
    };
  }, [visibleCourtRows, dayKey, bookings, hourSlots, slotStepHours]);
  const weekDays = (0, import_react.useMemo)(() => (0, import_bookingCalendarDateUtils.rangeDays)(anchorDate), [anchorDate]);
  const selectedWeekKeys = (0, import_react.useMemo)(
    () => new Set(weekDays.map((d) => (0, import_bookingCalendarDateUtils.fmtDate)(d))),
    [weekDays]
  );
  const firstTimelineHour = hourSlots[0] ?? 0;
  const endTimelineExclusive = hourSlots.length ? hourSlots[hourSlots.length - 1] + slotStepHours : 24;
  const isBusinessHour = (h) => (0, import_bookingCalendarDateUtils.isHourInTimelineSlots)(h, hourSlots);
  const monthDays = (0, import_react.useMemo)(
    () => (0, import_bookingCalendarDateUtils.monthGrid)(anchorDate, bookings, courts, hourSlots, slotStepHours),
    [anchorDate, bookings, courts, hourSlots, slotStepHours]
  );
  const dayRowRemainingByCourt = (0, import_react.useMemo)(() => {
    const total = hourSlots.length;
    return Object.fromEntries(
      visibleCourtRows.filter((row) => row.kind === "court").map((court) => {
        const occupied = hourSlots.filter(
          (hour) => isBusinessHour(hour) && (0, import_bookingCalendarDateUtils.dayOccupancy)(
            court.id,
            dayKey,
            bookings,
            hourSlots,
            slotStepHours
          )[hour]
        ).length;
        const remaining = Math.max(0, total - occupied);
        const ratio = total > 0 ? remaining / total : 0;
        return [court.id, { remaining, total, ratio }];
      })
    );
  }, [visibleCourtRows, dayKey, bookings, hourSlots, slotStepHours]);
  const dayHourRemaining = (0, import_react.useMemo)(() => {
    const total = visibleCourts.length;
    return Object.fromEntries(
      hourSlots.map((hour) => {
        if (!isBusinessHour(hour))
          return [hour, { remaining: 0, total, ratio: 0 }];
        const remaining = visibleCourts.filter(
          (court) => !(0, import_bookingCalendarDateUtils.dayOccupancy)(
            court.id,
            dayKey,
            bookings,
            hourSlots,
            slotStepHours
          )[hour]
        ).length;
        const ratio = total > 0 ? remaining / total : 0;
        return [hour, { remaining, total, ratio }];
      })
    );
  }, [visibleCourts, dayKey, bookings, hourSlots, slotStepHours]);
  const dayContentHeight = import_bookingCalendarConstants.dayHeaderHeight + dayRowHeights.reduce((sum, h) => sum + h, 0);
  (0, import_react.useEffect)(() => {
    function handleOutside(e) {
      const target = e.target;
      if (!(target instanceof Node)) return;
      if (showBlockPanel && blockPanelRef.current && !blockPanelRef.current.contains(target))
        setShowBlockPanel(false);
      if (overflowPopover && overflowPanelRef.current && !overflowPanelRef.current.contains(target))
        setOverflowPopover(null);
      if (overflowListModal && overflowPanelRef.current && !overflowPanelRef.current.contains(target))
        setOverflowListModal(null);
      if (moveConfirm && moveConfirmRef.current && !moveConfirmRef.current.contains(target))
        setMoveConfirm(null);
    }
    document.addEventListener("mousedown", handleOutside);
    return () => document.removeEventListener("mousedown", handleOutside);
  }, [showBlockPanel, overflowPopover, overflowListModal, moveConfirm]);
  (0, import_react.useEffect)(() => {
    if (!showBlockPanel) return;
    if (!(0, import_bookingCalendarDateUtils.isFreeSelectionContiguousSameResource)(selectedFreeSlots, slotStepHours)) {
      setShowBlockPanel(false);
    }
  }, [showBlockPanel, selectedFreeSlots, slotStepHours]);
  (0, import_react.useEffect)(() => {
    if (props.onBlockedTimePanelRequest) return;
    if (!showBlockPanel || selectedFreeSlots.length === 0) return;
    const groups = (0, import_bookingCalendarDateUtils.groupSelectedSlots)(selectedFreeSlots, slotStepHours);
    const g = groups[0];
    if (!g) return;
    setBlockResourceId(String(g.courtId));
    setBlockTimeRange([
      (0, import_bookingCalendarDateUtils.dayAndHourToDayjs)(g.date, g.startHour),
      (0, import_bookingCalendarDateUtils.dayAndHourToDayjs)(g.date, g.endHour)
    ]);
    setBlockFormName((0, import_calendarI18n.tCal)("pisell2.recordBoard.calendar.block.defaultTitle"));
    setBlockModalNote("");
  }, [showBlockPanel, selectedFreeSlots, slotStepHours]);
  (0, import_react.useEffect)(() => {
    if (!transitioningToDay) return;
    const timer = setTimeout(() => setTransitioningToDay(null), 280);
    return () => clearTimeout(timer);
  }, [transitioningToDay]);
  function isFreeSelected(courtId, hour) {
    return selectedFreeSlots.some(
      (slot) => slot.courtId === courtId && slot.date === dayKey && slot.hour === hour
    );
  }
  function isBlockSelected(courtId, hour) {
    return selectedBlockSlots.some(
      (slot) => slot.courtId === courtId && slot.date === dayKey && slot.hour === hour
    );
  }
  function goToDayFromCell(day, courtId, source) {
    setNavDirection(day > anchorDate ? 1 : -1);
    setTransitioningToDay({ source });
    commitAnchor(day);
    setFocusedCourtId(courtId || null);
    commitView("day");
  }
  function openBookingDetail(item) {
    var _a;
    if (((_a = props.onBookingClick) == null ? void 0 : _a.call(props, item)) === true) {
      return;
    }
    setOverflowPopover(null);
  }
  function toggleSlot(courtId, hour) {
    const existing = (0, import_bookingCalendarDateUtils.dayOccupancy)(
      courtId,
      dayKey,
      bookings,
      hourSlots,
      slotStepHours
    )[hour];
    const court = courts.find((c) => c.id === courtId);
    const slot = {
      courtId,
      court: court == null ? void 0 : court.name,
      date: dayKey,
      hour
    };
    if (!existing) {
      setSelectedFreeSlots(
        (prev) => prev.some((s) => (0, import_bookingCalendarDateUtils.sameSlot)(s, slot)) ? prev.filter((s) => !(0, import_bookingCalendarDateUtils.sameSlot)(s, slot)) : [...prev, slot]
      );
      return;
    }
    if (existing.kind === "block") {
      setSelectedBlockSlots(
        (prev) => prev.some((s) => (0, import_bookingCalendarDateUtils.sameSlot)(s, slot)) ? prev.filter((s) => !(0, import_bookingCalendarDateUtils.sameSlot)(s, slot)) : [...prev, slot]
      );
    }
  }
  function deselectAll() {
    setSelectedFreeSlots([]);
    setSelectedBlockSlots([]);
  }
  function createBookingFromSelection() {
    if (!allowPersist("createBooking")) return;
    if (selectedFreeSlots.length === 0) return;
    const groups = (0, import_bookingCalendarDateUtils.groupSelectedSlots)(selectedFreeSlots, slotStepHours);
    const newBookings = groups.map(
      (slot, idx) => ({
        id: `new-${slot.courtId}-${slot.date}-${slot.startHour}-${idx}`,
        courtId: slot.courtId,
        date: slot.date,
        startHour: slot.startHour,
        endHour: slot.endHour,
        name: (0, import_calendarI18n.tCal)("pisell2.recordBoard.calendar.common.newBookingName"),
        kind: "booking"
      })
    );
    setBookings((prev) => [...newBookings, ...prev]);
    setSelectedFreeSlots([]);
  }
  function openSelectedBlocks() {
    if (!allowPersist("removeBlocks")) return;
    if (selectedBlockSlots.length === 0) return;
    const selectedSet = new Set(
      selectedBlockSlots.map((s) => `${s.courtId}-${s.date}-${s.hour}`)
    );
    setBookings(
      (prev) => prev.filter((item) => {
        if (item.kind !== "block") return true;
        const seg = (0, import_bookingCalendarDateUtils.getBookingSegmentForDate)(item, item.date);
        const hoursInItem = hourSlots.filter(
          (slotStart) => slotStart >= item.startHour - 1e-9 && slotStart < item.endHour - 1e-9
        );
        return !hoursInItem.some(
          (h) => selectedSet.has(`${item.courtId}-${item.date}-${h}`)
        );
      })
    );
    setSelectedBlockSlots([]);
  }
  const handleOpenBlockPanelFromSelection = (0, import_react.useCallback)(async () => {
    if (!(0, import_bookingCalendarDateUtils.isFreeSelectionContiguousSameResource)(selectedFreeSlots, slotStepHours)) {
      return;
    }
    const groups = (0, import_bookingCalendarDateUtils.groupSelectedSlots)(selectedFreeSlots, slotStepHours);
    const g = groups[0];
    if (!g) return;
    if (props.onBlockedTimePanelRequest) {
      try {
        const slotsPayload = selectedFreeSlots.map((s) => {
          const slot = {
            courtId: s.courtId,
            date: s.date,
            hour: s.hour
          };
          const extra = s;
          if (extra.court !== void 0 && extra.court !== "") {
            slot.court = extra.court;
          }
          return slot;
        });
        const payload = {
          slotStepHours,
          slotStepMinutes: resolvedSlotMinutes,
          dayKey,
          selectedFreeSlots: slotsPayload,
          mergedRange: {
            courtId: g.courtId,
            date: g.date,
            startHour: g.startHour,
            endHour: g.endHour
          }
        };
        const ok = await props.onBlockedTimePanelRequest(payload);
        if (ok !== false) {
          setSelectedFreeSlots([]);
        }
      } catch {
      }
      return;
    }
    setShowBlockPanel(true);
  }, [
    selectedFreeSlots,
    slotStepHours,
    resolvedSlotMinutes,
    dayKey,
    props.onBlockedTimePanelRequest
  ]);
  async function saveBlockedTime() {
    if (!(blockTimeRange == null ? void 0 : blockTimeRange[0]) || !(blockTimeRange == null ? void 0 : blockTimeRange[1])) {
      import_antd.message.warning(
        (0, import_calendarI18n.tCal)("pisell2.recordBoard.calendar.block.warnSelectTime")
      );
      return;
    }
    const [start, end] = blockTimeRange;
    if (!end.isAfter(start)) {
      import_antd.message.warning(
        (0, import_calendarI18n.tCal)("pisell2.recordBoard.calendar.block.warnEndAfterStart")
      );
      return;
    }
    const rid = Number(blockResourceId);
    if (!Number.isFinite(rid) || rid <= 0) {
      import_antd.message.warning(
        (0, import_calendarI18n.tCal)("pisell2.recordBoard.calendar.block.warnSelectResource")
      );
      return;
    }
    const channels = props.blockedTimeSalesChannels ?? ["online_store"];
    const payload = {
      name: (blockFormName || "").trim() || (0, import_calendarI18n.tCal)("pisell2.recordBoard.calendar.block.defaultTitle"),
      note: (blockModalNote || "").trim(),
      resource_ids: [rid],
      blocked_sales_channels: channels,
      start_time: start.format("YYYY-MM-DD HH:mm"),
      end_time: end.format("YYYY-MM-DD HH:mm")
    };
    if (props.onBlockedTimeSave) {
      setBlockSaving(true);
      try {
        const ok = await props.onBlockedTimeSave(payload);
        if (ok === false) return;
        setShowBlockPanel(false);
        setSelectedFreeSlots([]);
        setBlockModalNote("");
      } finally {
        setBlockSaving(false);
      }
      return;
    }
    const courtId = String(blockResourceId);
    const date = start.format("YYYY-MM-DD");
    const endDate = end.format("YYYY-MM-DD");
    const startHour = start.hour() + start.minute() / 60;
    const endHour = end.hour() + end.minute() / 60;
    const nextBlock = {
      id: `block-local-${courtId}-${date}-${startHour}-${Date.now()}`,
      courtId,
      date,
      endDate: endDate !== date ? endDate : void 0,
      startHour,
      endHour,
      name: payload.name,
      note: payload.note,
      blockedAt: date,
      kind: "block"
    };
    if (!allowPersist("createBlock")) return;
    setBookings((prev) => [nextBlock, ...prev]);
    setSelectedFreeSlots([]);
    setShowBlockPanel(false);
    setBlockModalNote("");
  }
  function handleDropMove(targetCourtId, targetDate, targetHour) {
    if (!draggingItem) return;
    const duration = draggingItem.endHour - draggingItem.startHour;
    const nextStart = targetHour;
    const nextEnd = targetHour + duration;
    if (!isBusinessHour(nextStart) || nextEnd > endTimelineExclusive) return;
    const targetCourt = targetCourtId ?? draggingItem.courtId;
    const itemSnapshot = draggingItem;
    const draft = {
      targetCourtId: targetCourt,
      targetDate,
      targetHour
    };
    setDraggingItem(null);
    if (props.onBookingMoveRequest) {
      void Promise.resolve(
        props.onBookingMoveRequest({ item: itemSnapshot, draft })
      ).catch(() => {
      });
      return;
    }
    setMoveConfirm({
      item: itemSnapshot,
      targetCourtId: targetCourt,
      targetDate,
      targetHour
    });
    setMoveDraft(draft);
  }
  function handleGridDropMove(targetDate, targetCourtId = null) {
    if (!draggingItem || draggingItem.kind === "block") return;
    handleDropMove(
      targetCourtId ?? draggingItem.courtId,
      targetDate,
      draggingItem.startHour
    );
  }
  function confirmMove() {
    if (!moveConfirm || !moveDraft) return;
    if (!allowPersist("moveBooking")) return;
    const { item } = moveConfirm;
    const { targetCourtId, targetDate, targetHour } = moveDraft;
    const duration = item.endHour - item.startHour;
    setBookings(
      (prev) => prev.map(
        (b) => b.id === item.id ? {
          ...b,
          courtId: targetCourtId,
          date: targetDate,
          startHour: targetHour,
          endHour: targetHour + duration
        } : b
      )
    );
    setMoveConfirm(null);
    setMoveDraft(null);
  }
  return /* @__PURE__ */ import_react.default.createElement(
    import_antd.Spin,
    {
      spinning: Boolean(props.loading),
      wrapperClassName: "pisell-rb-cal-spin-wrap flex min-h-0 flex-1 flex-col"
    },
    /* @__PURE__ */ import_react.default.createElement(
      "div",
      {
        className: `theme-root theme-app flex h-full min-h-0 flex-col p-2 md:p-3 ${isLight ? "theme-light" : "theme-dark"}`
      },
      /* @__PURE__ */ import_react.default.createElement(
        "div",
        {
          className: "theme-shell soft-shadow mx-0 flex h-full min-h-0 w-full max-w-none flex-1 flex-col rounded-[28px] border overflow-hidden transition-[padding-right] duration-200",
          style: { paddingRight: 0 }
        },
        /* @__PURE__ */ import_react.default.createElement("div", { className: "flex min-h-0 flex-1 flex-col" }, view === "month" && /* @__PURE__ */ import_react.default.createElement(
          import_BookingCalendarMonthView.BookingCalendarMonthView,
          {
            isLight,
            anchorDate,
            monthDays,
            bookings,
            goToDayFromCell,
            handleGridDropMove,
            setDraggingItem,
            openBookingDetail,
            overflowPopover,
            setOverflowPopover,
            overflowListModal,
            setOverflowListModal,
            overflowPanelRef,
            renderMonthWeekBooking: props.renderMonthWeekBooking
          }
        ), view === "week" && /* @__PURE__ */ import_react.default.createElement(
          import_BookingCalendarWeekView.BookingCalendarWeekView,
          {
            calendarProps: props,
            isLight,
            weekDays,
            bookings,
            courts,
            hourSlots,
            slotStepHours,
            visibleCourts,
            visibleCourtRows,
            isBusinessHour,
            goToDayFromCell,
            handleGridDropMove,
            openBookingDetail,
            setDraggingItem,
            setCollapsedGroups,
            overflowPopover,
            setOverflowPopover,
            overflowListModal,
            setOverflowListModal,
            overflowPanelRef
          }
        ), view === "day" && /* @__PURE__ */ import_react.default.createElement(
          import_BookingCalendarDayView.BookingCalendarDayView,
          {
            calendarProps: props,
            isLight,
            view,
            anchorDate,
            dayKey,
            hourSlots,
            resolvedSlotMinutes,
            slotColWidth,
            firstTimelineHour,
            endTimelineExclusive,
            isBusinessHour,
            dayHourRemaining,
            timelinePxPerHour,
            dayContentHeight,
            dayRowHeights,
            visibleCourtRows,
            overlayBookings,
            dayOverlayOverflowPluses,
            setCollapsedGroups,
            visibleCourts,
            bookings,
            slotStepHours,
            isFreeSelected,
            isBlockSelected,
            toggleSlot,
            handleDropMove,
            hiddenDayOverlayIdSet,
            courtDayDisplayLaneCount,
            openBookingDetail,
            setDraggingItem,
            setNavDirection,
            commitAnchor,
            setFocusedCourtId,
            setOverflowListModal,
            selectedFreeSlots,
            selectedBlockSlots,
            deselectAll,
            openSelectedBlocks,
            onOpenBlockPanel: handleOpenBlockPanelFromSelection,
            createBookingFromSelection,
            focusedCourtId,
            dayRowRemainingByCourt
          }
        ))
      ),
      showBlockPanel && !props.onBlockedTimePanelRequest && selectedFreeSlots.length > 0 && (0, import_bookingCalendarDateUtils.isFreeSelectionContiguousSameResource)(
        selectedFreeSlots,
        slotStepHours
      ) && /* @__PURE__ */ import_react.default.createElement("div", { className: "fixed inset-0 z-50 bg-black/55 backdrop-blur-sm flex items-end md:items-center justify-center p-2 md:p-4" }, /* @__PURE__ */ import_react.default.createElement(
        "div",
        {
          ref: blockPanelRef,
          className: `w-full max-w-[720px] max-h-[92vh] overflow-y-auto rounded-t-3xl md:rounded-3xl border p-4 md:p-6 shadow-2xl ${isLight ? "theme-panel theme-border soft-shadow" : "border-zinc-700 bg-[#121217]"}`
        },
        /* @__PURE__ */ import_react.default.createElement("div", { className: "mb-4 flex items-center justify-between gap-3" }, /* @__PURE__ */ import_react.default.createElement("div", { className: "text-xl font-semibold" }, (0, import_calendarI18n.tCal)("pisell2.recordBoard.calendar.block.panelTitle")), /* @__PURE__ */ import_react.default.createElement(
          "button",
          {
            type: "button",
            "aria-label": (0, import_calendarI18n.tCal)(
              "pisell2.recordBoard.calendar.block.closeAria"
            ),
            onClick: () => setShowBlockPanel(false),
            className: `rounded-xl p-2 ${isLight ? "btn-neutral" : "border border-zinc-700 text-zinc-300 hover:bg-zinc-800"}`
          },
          /* @__PURE__ */ import_react.default.createElement(import_icons.CloseOutlined, { style: { fontSize: 20 } })
        )),
        /* @__PURE__ */ import_react.default.createElement(
          "div",
          {
            className: `space-y-4 rounded-2xl border p-4 ${isLight ? "theme-panel-alt theme-border" : "border-zinc-700 bg-[#171820]"}`
          },
          /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement(
            "label",
            {
              className: `mb-2 block text-sm ${isLight ? "theme-text-muted" : "text-zinc-400"}`
            },
            (0, import_calendarI18n.tCal)("pisell2.recordBoard.calendar.block.fieldTitle")
          ), /* @__PURE__ */ import_react.default.createElement(
            "input",
            {
              value: blockFormName,
              onChange: (e) => setBlockFormName(e.target.value),
              placeholder: (0, import_calendarI18n.tCal)(
                "pisell2.recordBoard.calendar.block.placeholderTitle"
              ),
              className: `w-full rounded-xl px-3 py-2 outline-none ${isLight ? "theme-input theme-text" : "border border-zinc-700 bg-[#111218] text-white"}`
            }
          )),
          /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement(
            "label",
            {
              className: `mb-2 block text-sm ${isLight ? "theme-text-muted" : "text-zinc-400"}`
            },
            "备注"
          ), /* @__PURE__ */ import_react.default.createElement(
            "input",
            {
              value: blockModalNote,
              onChange: (e) => setBlockModalNote(e.target.value),
              placeholder: "选填",
              className: `w-full rounded-xl px-3 py-2 outline-none ${isLight ? "theme-input theme-text" : "border border-zinc-700 bg-[#111218] text-white"}`
            }
          )),
          /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement(
            "label",
            {
              className: `mb-2 block text-sm ${isLight ? "theme-text-muted" : "text-zinc-400"}`
            },
            (0, import_calendarI18n.tCal)("pisell2.recordBoard.calendar.block.fieldResource")
          ), /* @__PURE__ */ import_react.default.createElement(
            "select",
            {
              value: blockResourceId,
              onChange: (e) => setBlockResourceId(e.target.value),
              className: `w-full rounded-xl px-3 py-2 outline-none ${isLight ? "theme-input theme-text" : "border border-zinc-700 bg-[#111218] text-white"}`
            },
            /* @__PURE__ */ import_react.default.createElement("option", { value: "" }, (0, import_calendarI18n.tCal)("pisell2.recordBoard.calendar.block.noResource")),
            visibleCourts.map((c) => /* @__PURE__ */ import_react.default.createElement("option", { key: c.id, value: String(c.id) }, c.name))
          )),
          /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement(
            "label",
            {
              className: `mb-2 block text-sm ${isLight ? "theme-text-muted" : "text-zinc-400"}`
            },
            (0, import_calendarI18n.tCal)(
              "pisell2.recordBoard.calendar.block.fieldTimeRange"
            )
          ), /* @__PURE__ */ import_react.default.createElement(
            RangePicker,
            {
              ...{
                style: { width: "100%" },
                showTime: {
                  format: "HH:mm",
                  minuteStep: resolvedSlotMinutes >= 60 ? 60 : Math.max(1, resolvedSlotMinutes)
                },
                format: "YYYY-MM-DD HH:mm",
                value: blockTimeRange ?? void 0,
                onChange: (v) => setBlockTimeRange(v ?? null)
              }
            }
          ))
        ),
        /* @__PURE__ */ import_react.default.createElement("div", { className: "mt-6 flex flex-col-reverse sm:flex-row items-stretch sm:items-center justify-end gap-3" }, /* @__PURE__ */ import_react.default.createElement(
          "button",
          {
            type: "button",
            disabled: blockSaving,
            onClick: () => setShowBlockPanel(false),
            className: `rounded-xl px-4 py-2 ${isLight ? "btn-neutral" : "border border-zinc-700 text-zinc-300 hover:bg-zinc-800"}`
          },
          (0, import_calendarI18n.tCal)("pisell2.recordBoard.calendar.common.cancel")
        ), /* @__PURE__ */ import_react.default.createElement(
          "button",
          {
            type: "button",
            disabled: blockSaving,
            onClick: () => void saveBlockedTime(),
            className: `rounded-xl px-5 py-3 text-sm font-semibold disabled:opacity-50 ${isLight ? "btn-brand" : "bg-violet-600 text-white hover:bg-violet-500"}`
          },
          blockSaving ? (0, import_calendarI18n.tCal)("pisell2.recordBoard.calendar.common.saving") : (0, import_calendarI18n.tCal)("pisell2.recordBoard.calendar.common.save")
        ))
      )),
      overflowListModal && /* @__PURE__ */ import_react.default.createElement("div", { className: "fixed inset-0 z-[69] bg-black/45 backdrop-blur-sm flex items-center justify-center p-4" }, /* @__PURE__ */ import_react.default.createElement(
        "div",
        {
          ref: overflowPanelRef,
          className: `flex w-full max-w-[520px] max-h-[72vh] flex-col overflow-hidden rounded-3xl border p-5 shadow-2xl ${isLight ? "theme-panel theme-border soft-shadow" : "border-zinc-700 bg-[#121217]"}`
        },
        /* @__PURE__ */ import_react.default.createElement("div", { className: "mb-4 flex shrink-0 items-start justify-between" }, /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { className: "text-xl font-semibold" }, (0, import_calendarI18n.tCal)("pisell2.recordBoard.calendar.overflow.bookingsForDay")), /* @__PURE__ */ import_react.default.createElement("div", { className: "mt-1 text-sm text-zinc-400" }, overflowListModal.title)), /* @__PURE__ */ import_react.default.createElement(
          "button",
          {
            onClick: () => setOverflowListModal(null),
            className: "rounded-xl border border-zinc-700 px-3 py-2 text-zinc-300 hover:bg-zinc-800"
          },
          (0, import_calendarI18n.tCal)("pisell2.recordBoard.calendar.common.close")
        )),
        /* @__PURE__ */ import_react.default.createElement("div", { className: "min-h-0 flex-1 overflow-hidden px-0.5" }, /* @__PURE__ */ import_react.default.createElement(
          import_OverflowListModal.OverflowListModalVirtualList,
          {
            items: overflowListModal.items,
            dateKey: overflowListModal.date,
            listWidth: 468,
            onPickItem: openBookingDetail,
            onClose: () => setOverflowListModal(null),
            showStatusUi: Boolean(
              overflowListModal.scope && String(overflowListModal.scope).startsWith(
                "day-lane-overflow-"
              )
            )
          }
        ))
      )),
      moveConfirm && /* @__PURE__ */ import_react.default.createElement(
        import_MoveConfirmModal.MoveConfirmModal,
        {
          moveConfirm,
          moveDraft,
          setMoveDraft,
          panelRef: moveConfirmRef,
          isLight,
          courts,
          visibleCourts,
          hourSlots,
          isBusinessHour,
          firstTimelineHour,
          endTimelineExclusive,
          onConfirm: confirmMove,
          onClose: () => {
            setMoveConfirm(null);
            setMoveDraft(null);
          }
        }
      ),
      transitioningToDay && /* @__PURE__ */ import_react.default.createElement("div", { className: "fixed inset-6 z-[60] rounded-[28px] border border-violet-400/20 bg-[#151220] pointer-events-none" })
    )
  );
}
