import { _objectSpread2 } from "../../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js";
import { _asyncToGenerator } from "../../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/asyncToGenerator.js";
import { buildCalendarTimelineSlotStartsFromRange } from "../../../pisellTimeNavigator/utils/index.js";
import { useCalendarPersist } from "./calendarPersistGuard.js";
import { DEFAULT_CALENDAR_TIMELINE } from "./const/bookingCalendarConstants.js";
import { tCal } from "./calendarI18n.js";
import { addDays, dayAndHourToDayjs, fmtDate, groupSelectedSlots, isFreeSelectionContiguousSameResource, isHourInTimelineSlots, monthCalendarDays, monthGrid, rangeDays, startOfWeek } from "./utils/bookingCalendarDateUtils.js";
import { MoveConfirmModal } from "./modal/MoveConfirmModal.js";
import { BookingCalendarBlockPanel } from "./modal/BookingCalendarBlockPanel.js";
import { buildGroupedCourtRows } from "./bookingCalendarViewShared.js";
import { BookingCalendarOverflowListLayer } from "./modal/BookingCalendarOverflowListLayer.js";
import { BookingCalendarMonthView } from "./view/BookingCalendarMonthView.js";
import { BookingCalendarWeekView } from "./view/BookingCalendarWeekView.js";
import { BookingCalendarDayView } from "./view/BookingCalendarDayView.js";
import { BookingCalendarResourceView } from "./view/BookingCalendarResourceView.js";
import { BookingCalendarDaySelectionBar } from "./view/BookingCalendarDaySelectionBar.js";
import { isResourceSelectionContiguousSameCourt } from "./utils/bookingCalendarSelectionUtils.js";
import { useBookingCalendarDayOverlayLayout } from "./hooks/useBookingCalendarDayOverlayLayout.js";
import { useBookingCalendarDayHourRemaining } from "./view/day/useBookingCalendarDayHourRemaining.js";
import { useBookingCalendarDaySelection } from "./view/day/useBookingCalendarDaySelection.js";
import { useBookingCalendarResourceDayHeaderRemaining } from "./view/resource/useBookingCalendarResourceDayHeaderRemaining.js";
import { useBookingCalendarResourceCellToggle } from "./view/resource/useBookingCalendarResourceCellToggle.js";
import { useBookingCalendarGoToDayFromCell } from "./view/useBookingCalendarGoToDayFromCell.js";
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
import { Spin, message } from "antd";
import "./BookingCalendar.less";
//#region src/components/pisellRecordBoard/shellFrame/Calendar/BookingCalendar.tsx
/**
* RecordBoard 预约日历：月 / 周 / 日三视图，资源分组与折叠、锁台、拖拽改期、日视图多 lane overlay。
* 受控：`calendarView`、`anchorDate`、`bookings` 等见 {@link RecordBoardCalendarProps}；未传时由内部 state 驱动（便于 Story）。
*/
/** 看板日历根组件：内含主题 CSS 与 Spin，按 `view` 挂载月 / 周 / 日子组件 */
function BookingCalendar(props = {}) {
	var _hourSlots$;
	const allowPersist = useCalendarPersist();
	/** 将 `resources` 规范为 `{ id, name, type }`，供分组与三视图共用 */
	const courts = 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) : tCal("pisell2.recordBoard.calendar.common.resourceFallback")
			}));
			if (mapped.length > 0) return mapped;
		}
		return [];
	}, [props.resources]);
	/** 顶栏受控：有 props 用 props，无则回退本地 state（便于 Story 单测） */
	const isLight = props.appearance === "light";
	const [internalView, setInternalView] = useState("month");
	const [internalAnchor, setInternalAnchor] = useState(() => /* @__PURE__ */ new Date());
	const view = props.calendarView != null ? props.calendarView : internalView;
	const anchorDate = useMemo(() => {
		if (props.anchorDate != null) return new Date(props.anchorDate);
		return internalAnchor;
	}, [props.anchorDate != null ? props.anchorDate.getTime() : null, internalAnchor]);
	const resolvedSlotMinutes = useMemo(() => {
		var _props$slotStepMinute;
		const raw = (_props$slotStepMinute = props.slotStepMinutes) !== null && _props$slotStepMinute !== void 0 ? _props$slotStepMinute : 60;
		const n = Math.round(Number(raw));
		if (!Number.isFinite(n) || n < 1) return 60;
		return Math.min(1440, n);
	}, [props.slotStepMinutes]);
	const slotStepHours = resolvedSlotMinutes / 60;
	/** 每槽一列固定为「原整点列」宽度，细粒度仅增加列数，由容器横向滚动承载（日/周等时间轴） */
	const slotColWidth = 92;
	/** 资源视图：按「日」分列，单列单独加宽 */
	const resourceViewSlotColWidth = 102;
	const timelinePxPerHour = 92 / slotStepHours;
	/** 切换月/周/日：先 `onCalendarViewChange`，无受控回调时再 `setInternalView` */
	const commitView = (v) => {
		var _props$onCalendarView;
		(_props$onCalendarView = props.onCalendarViewChange) === null || _props$onCalendarView === void 0 || _props$onCalendarView.call(props, v);
		if (!props.onCalendarViewChange) setInternalView(v);
	};
	/** 切换锚定日：先 `onAnchorDateChange`，无受控时再 `setInternalAnchor` */
	const commitAnchor = (d) => {
		var _props$onAnchorDateCh;
		(_props$onAnchorDateCh = props.onAnchorDateChange) === null || _props$onAnchorDateCh === void 0 || _props$onAnchorDateCh.call(props, d);
		if (!props.onAnchorDateChange) setInternalAnchor(d);
	};
	const [internalBookings, setBookings] = useState([]);
	/** 预约与锁台片段列表；受控时用 props，否则用本地演示数据 */
	const bookings = props.bookings != null ? props.bookings : internalBookings;
	/** 锚定日或视图变化时上报当前可视区间，供业务按范围拉数 */
	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 === "resource") {
			rangeStart = new Date(a.getFullYear(), a.getMonth(), 1);
			rangeEnd = new Date(a.getFullYear(), a.getMonth() + 1, 0);
		} else if (view === "week") {
			rangeStart = startOfWeek(a);
			rangeEnd = 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] = useState([]);
	const [selectedBlockSlots, setSelectedBlockSlots] = useState([]);
	const [selectedResourceCells, setSelectedResourceCells] = useState([]);
	const [focusedCourtId, setFocusedCourtId] = useState(null);
	const [showBlockPanel, setShowBlockPanel] = useState(false);
	const [blockFormName, setBlockFormName] = useState(() => tCal("pisell2.recordBoard.calendar.block.defaultTitle"));
	const [blockModalNote, setBlockModalNote] = useState("");
	const [blockResourceId, setBlockResourceId] = useState("");
	const [blockTimeRange, setBlockTimeRange] = useState(null);
	const [blockSaving, setBlockSaving] = useState(false);
	const [transitioningToDay, setTransitioningToDay] = useState(null);
	const [navDirection, setNavDirection] = useState(0);
	const [overflowPopover, setOverflowPopover] = useState(null);
	const [overflowListModal, setOverflowListModal] = useState(null);
	const [draggingItem, setDraggingItem] = useState(null);
	const [moveConfirm, setMoveConfirm] = useState(null);
	const [moveDraft, setMoveDraft] = useState(null);
	const [collapsedGroups, setCollapsedGroups] = useState({
		VIP: false,
		Standard: false
	});
	/**
	* 进入日视图（含首次即以日视图打开、从周/月切换、从格子 goToDay 等）时递增，
	* 供日视图将横向 scroll 定位到「当前时间」列。
	*/
	const [dayTimelineScrollToNowToken, setDayTimelineScrollToNowToken] = useState(0);
	const [resourceMonthScrollToTodayToken, setResourceMonthScrollToTodayToken] = useState(0);
	const prevCalendarViewRef = useRef(null);
	const prevViewForSlotIsolationRef = useRef(view);
	/** 任意入口切入 `day` 时递增一次（含首屏即为日视图：`prev === null`） */
	useLayoutEffect(() => {
		const prev = prevCalendarViewRef.current;
		if (view === "day" && (prev === null || prev !== "day")) setDayTimelineScrollToNowToken((t) => t + 1);
		if (view === "resource" && (prev === null || prev !== "resource")) setResourceMonthScrollToTodayToken((t) => t + 1);
		prevCalendarViewRef.current = view;
	}, [view]);
	const blockPanelRef = useRef(null);
	const overflowPanelRef = useRef(null);
	const moveConfirmRef = useRef(null);
	/** 与 `courts` 相同别名，便于子视图语义（可见资源列表） */
	const visibleCourts = useMemo(() => courts, [courts]);
	/**
	* 日/周/月左侧行模型：VIP/Standard 与按 `type` 分组，可折叠。
	* 全部分组折叠时保留仅 group 头行（与周视图一致，不自动平铺 court）。
	*/
	const visibleCourtRows = useMemo(() => buildGroupedCourtRows(visibleCourts, collapsedGroups), [visibleCourts, collapsedGroups]);
	/** 当前锚定日的 `YYYY-MM-DD`（日视图主键） */
	const dayKey = fmtDate(anchorDate);
	/** 时间轴上的槽位起始小时（含 `slotStepMinutes` 细粒度） */
	const hourSlots = useMemo(() => {
		var _props$timelineRange;
		return buildCalendarTimelineSlotStartsFromRange((_props$timelineRange = props.timelineRange) !== null && _props$timelineRange !== void 0 ? _props$timelineRange : DEFAULT_CALENDAR_TIMELINE, anchorDate, resolvedSlotMinutes);
	}, [
		props.timelineRange,
		anchorDate,
		resolvedSlotMinutes
	]);
	/**
	* 日视图 overlay 行高 / 并行 lane / +N 溢出（详见 hook 内注释）。
	*/
	const { dayRowHeights, overlayBookings, courtDayDisplayLaneCount, hiddenDayOverlayIdSet, dayOverlayOverflowPluses } = useBookingCalendarDayOverlayLayout(visibleCourtRows, dayKey, bookings, hourSlots, slotStepHours);
	/** 周视图表头对应的 7 个自然日 */
	const weekDays = useMemo(() => rangeDays(anchorDate), [anchorDate]);
	/** 资源视图：当月每日一列 */
	const resourceMonthDays = useMemo(() => monthCalendarDays(anchorDate), [anchorDate]);
	useMemo(() => new Set(weekDays.map((d) => fmtDate(d))), [weekDays]);
	const firstTimelineHour = (_hourSlots$ = hourSlots[0]) !== null && _hourSlots$ !== void 0 ? _hourSlots$ : 0;
	const endTimelineExclusive = hourSlots.length ? hourSlots[hourSlots.length - 1] + slotStepHours : 24;
	/** 槽位起始小时是否落在当前营业/时间轴配置内 */
	const isBusinessHour = useCallback((h) => isHourInTimelineSlots(h, hourSlots), [hourSlots]);
	const dayHourRemaining = useBookingCalendarDayHourRemaining(visibleCourts, dayKey, bookings, hourSlots, slotStepHours, isBusinessHour);
	const resourceDayHeaderRemaining = useBookingCalendarResourceDayHeaderRemaining(resourceMonthDays, visibleCourts, bookings, hourSlots, slotStepHours);
	/**
	* 资源视图：选区是否可触发 Block / Create Booking。
	* - 任何选中 → SelectionBar 显示「Cancel」。
	* - 同 court + 连续多天（含单日） → 才显示「Block / Create」按钮。
	*/
	const resourceSelectionContiguous = useMemo(() => isResourceSelectionContiguousSameCourt(selectedResourceCells), [selectedResourceCells]);
	const resourceSelectionBarMeta = useMemo(() => {
		if (selectedResourceCells.length === 0) return null;
		return {
			freePickCount: selectedResourceCells.length,
			blockPickCount: selectedResourceCells.length,
			freeAllowsBlockPanel: resourceSelectionContiguous
		};
	}, [selectedResourceCells, resourceSelectionContiguous]);
	/** 日视图与资源视图选中隔离：切换视图时清空另一侧 */
	useEffect(() => {
		if (prevViewForSlotIsolationRef.current !== view) {
			if (view === "day") setSelectedResourceCells([]);
			if (view === "resource") {
				setSelectedFreeSlots([]);
				setSelectedBlockSlots([]);
			}
			prevViewForSlotIsolationRef.current = view;
		}
	}, [view]);
	/** 月历每格摘要（占用点、锁台等），供月视图渲染 */
	const monthDays = useMemo(() => monthGrid(anchorDate, bookings, courts, hourSlots, slotStepHours), [
		anchorDate,
		bookings,
		courts,
		hourSlots,
		slotStepHours
	]);
	/** 日视图内容区总高度（表头 + 各资源行叠加以 overlay 抬高后的高度） */
	const dayContentHeight = 56 + dayRowHeights.reduce((sum, h) => sum + h, 0);
	/** 点击文档空白处关闭锁台面版、溢出浮层、改期确认等面板 */
	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
	]);
	/** 锁台面版打开时若选区不再连续同资源则自动收起（避免与表单状态不一致） */
	useEffect(() => {
		if (!showBlockPanel) return;
		if (view === "resource") {
			if (!resourceSelectionContiguous) setShowBlockPanel(false);
			return;
		}
		if (!isFreeSelectionContiguousSameResource(selectedFreeSlots, slotStepHours)) setShowBlockPanel(false);
	}, [
		showBlockPanel,
		view,
		selectedFreeSlots,
		resourceSelectionContiguous,
		slotStepHours
	]);
	/** 打开锁台面版时用当前选中的空闲连续段预填资源与时间范围（仅内置锁台面版） */
	useEffect(() => {
		if (props.onBlockedTimePanelRequest) return;
		if (!showBlockPanel) return;
		if (view === "resource") {
			var _bizHours$, _bizHours;
			if (!resourceSelectionContiguous) return;
			const sortedDates = [...selectedResourceCells].map((s) => s.dateKey).sort();
			const firstDate = sortedDates[0];
			const lastDate = sortedDates[sortedDates.length - 1];
			const bizHours = hourSlots.filter((h) => isHourInTimelineSlots(h, hourSlots));
			const h0 = (_bizHours$ = bizHours[0]) !== null && _bizHours$ !== void 0 ? _bizHours$ : 0;
			const hLast = (_bizHours = bizHours[bizHours.length - 1]) !== null && _bizHours !== void 0 ? _bizHours : h0;
			const slotStep = slotStepHours > 0 ? slotStepHours : 1;
			setBlockResourceId(String(selectedResourceCells[0].courtId));
			setBlockTimeRange([dayAndHourToDayjs(firstDate, h0), dayAndHourToDayjs(lastDate, hLast + slotStep)]);
			setBlockFormName(tCal("pisell2.recordBoard.calendar.block.defaultTitle"));
			setBlockModalNote("");
			return;
		}
		if (selectedFreeSlots.length === 0) return;
		const g = groupSelectedSlots(selectedFreeSlots, slotStepHours)[0];
		if (!g) return;
		setBlockResourceId(String(g.courtId));
		setBlockTimeRange([dayAndHourToDayjs(g.date, g.startHour), dayAndHourToDayjs(g.date, g.endHour)]);
		setBlockFormName(tCal("pisell2.recordBoard.calendar.block.defaultTitle"));
		setBlockModalNote("");
	}, [
		showBlockPanel,
		view,
		selectedFreeSlots,
		selectedResourceCells,
		resourceSelectionContiguous,
		hourSlots,
		slotStepHours,
		props.onBlockedTimePanelRequest
	]);
	/** 周/月跳入日视图时的短动画标记，超时清除 */
	useEffect(() => {
		if (!transitioningToDay) return;
		const timer = setTimeout(() => setTransitioningToDay(null), 280);
		return () => clearTimeout(timer);
	}, [transitioningToDay]);
	const goToDayFromCell = useBookingCalendarGoToDayFromCell(anchorDate, commitAnchor, commitView, setNavDirection, setTransitioningToDay, setSelectedFreeSlots, setSelectedBlockSlots, setSelectedResourceCells, setFocusedCourtId);
	const toggleResourceCell = useBookingCalendarResourceCellToggle(setSelectedResourceCells);
	const { isFreeSelected, isBlockSelected, toggleSlot } = useBookingCalendarDaySelection(dayKey, bookings, hourSlots, slotStepHours, courts, selectedFreeSlots, selectedBlockSlots, setSelectedFreeSlots, setSelectedBlockSlots);
	/** 卡片详情：业务若 `onBookingClick` 返回 true 则视为已消费；否则关闭溢出气泡 */
	const openBookingDetail = useCallback((item) => {
		var _props$onBookingClick;
		if (((_props$onBookingClick = props.onBookingClick) === null || _props$onBookingClick === void 0 ? void 0 : _props$onBookingClick.call(props, item)) === true) return;
		setOverflowPopover(null);
	}, [props.onBookingClick]);
	/** 清空空闲与锁台多选 */
	function deselectAll() {
		setSelectedFreeSlots([]);
		setSelectedBlockSlots([]);
	}
	/** 将连续空闲选区合并为一条或多条本地预约（演示/未接写接口时） */
	function createBookingFromSelection() {
		if (selectedFreeSlots.length === 0) return;
		const groups = groupSelectedSlots(selectedFreeSlots, slotStepHours);
		const host = props.onCreateBookingFromSelection;
		if (host) {
			_asyncToGenerator(function* () {
				try {
					if ((yield Promise.resolve(host({
						mode: "day",
						groups: groups.map((g) => ({
							courtId: g.courtId,
							date: g.date,
							startHour: g.startHour,
							endHour: g.endHour
						}))
					}))) !== false) setSelectedFreeSlots([]);
				} catch (_unused) {}
			})();
			return;
		}
		if (!allowPersist("createBooking")) return;
		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: tCal("pisell2.recordBoard.calendar.common.newBookingName"),
			kind: "booking"
		}));
		setBookings((prev) => [...newBookings, ...prev]);
		setSelectedFreeSlots([]);
	}
	/**
	* 资源视图：连续多天 → 一条跨日整天预约，时间 = 营业开始 → 营业结束。
	* 单日 → 同样按整天写入。仅在 `resourceSelectionContiguous` 为 true 时执行。
	*/
	function createBookingFromResourceSelection() {
		var _bizHours$2, _bizHours2;
		if (!resourceSelectionContiguous) return;
		const sortedDates = [...selectedResourceCells].map((s) => s.dateKey).sort();
		const firstDate = sortedDates[0];
		const lastDate = sortedDates[sortedDates.length - 1];
		const courtId = selectedResourceCells[0].courtId;
		const bizHours = hourSlots.filter((h) => isHourInTimelineSlots(h, hourSlots));
		const h0 = (_bizHours$2 = bizHours[0]) !== null && _bizHours$2 !== void 0 ? _bizHours$2 : 0;
		const endHour = ((_bizHours2 = bizHours[bizHours.length - 1]) !== null && _bizHours2 !== void 0 ? _bizHours2 : h0) + (slotStepHours > 0 ? slotStepHours : 1);
		const host = props.onCreateBookingFromSelection;
		if (host) {
			_asyncToGenerator(function* () {
				try {
					if ((yield Promise.resolve(host({
						mode: "resource",
						courtId,
						dates: sortedDates,
						startHour: h0,
						endHour
					}))) !== false) setSelectedResourceCells([]);
				} catch (_unused2) {}
			})();
			return;
		}
		if (!allowPersist("createBooking")) return;
		const newBooking = {
			id: `new-${courtId}-${firstDate}-${Date.now()}`,
			courtId,
			date: firstDate,
			endDate: lastDate !== firstDate ? lastDate : void 0,
			startHour: h0,
			endHour,
			name: tCal("pisell2.recordBoard.calendar.common.newBookingName"),
			kind: "booking"
		};
		setBookings((prev) => [newBooking, ...prev]);
		setSelectedResourceCells([]);
	}
	/** 屏蔽：宿主 lock 弹窗，或内置锁台面版 */
	const handleOpenBlockPanelFromSelection = useCallback(_asyncToGenerator(function* () {
		if (!isFreeSelectionContiguousSameResource(selectedFreeSlots, slotStepHours)) return;
		const g = groupSelectedSlots(selectedFreeSlots, slotStepHours)[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: g.date,
					selectedFreeSlots: slotsPayload,
					mergedRange: {
						courtId: g.courtId,
						date: g.date,
						startHour: g.startHour,
						endHour: g.endHour
					}
				};
				if ((yield props.onBlockedTimePanelRequest(payload)) !== false) setSelectedFreeSlots([]);
			} catch (_unused3) {}
			return;
		}
		setShowBlockPanel(true);
	}), [
		selectedFreeSlots,
		slotStepHours,
		resolvedSlotMinutes,
		props.onBlockedTimePanelRequest
	]);
	/**
	* 资源视图：仅在「同 court + 连续多天」时打开 Block 面板，按整天预填资源 + 跨日时间范围。
	*/
	const handleOpenBlockPanelFromResource = useCallback(_asyncToGenerator(function* () {
		var _bizHours$3, _bizHours3;
		if (!resourceSelectionContiguous) return;
		const sortedDates = [...selectedResourceCells].map((s) => s.dateKey).sort();
		const firstDate = sortedDates[0];
		const lastDate = sortedDates[sortedDates.length - 1];
		const courtId = selectedResourceCells[0].courtId;
		const court = courts.find((c) => c.id === courtId);
		const bizHours = hourSlots.filter((h) => isHourInTimelineSlots(h, hourSlots));
		const h0 = (_bizHours$3 = bizHours[0]) !== null && _bizHours$3 !== void 0 ? _bizHours$3 : 0;
		const hLast = (_bizHours3 = bizHours[bizHours.length - 1]) !== null && _bizHours3 !== void 0 ? _bizHours3 : h0;
		const slotStep = slotStepHours > 0 ? slotStepHours : 1;
		const startHour = h0;
		const endHour = hLast + slotStep;
		if (props.onBlockedTimePanelRequest) {
			try {
				const payload = {
					slotStepHours,
					slotStepMinutes: resolvedSlotMinutes,
					dayKey: firstDate,
					selectedFreeSlots: sortedDates.map((d) => _objectSpread2({
						courtId,
						date: d,
						hour: startHour
					}, (court === null || court === void 0 ? void 0 : court.name) ? { court: court.name } : {})),
					mergedRange: {
						courtId,
						date: firstDate,
						endDate: lastDate !== firstDate ? lastDate : void 0,
						startHour,
						endHour
					}
				};
				if ((yield props.onBlockedTimePanelRequest(payload)) !== false) setSelectedResourceCells([]);
			} catch (_unused4) {}
			return;
		}
		setShowBlockPanel(true);
	}), [
		selectedResourceCells,
		resourceSelectionContiguous,
		hourSlots,
		slotStepHours,
		courts,
		resolvedSlotMinutes,
		props.onBlockedTimePanelRequest
	]);
	/** 提交锁台：优先走 `onBlockedTimeSave`；否则写入本地 block 片段 */
	function saveBlockedTime() {
		return _saveBlockedTime.apply(this, arguments);
	}
	function _saveBlockedTime() {
		_saveBlockedTime = _asyncToGenerator(function* () {
			var _props$blockedTimeSal;
			if (!(blockTimeRange === null || blockTimeRange === void 0 ? void 0 : blockTimeRange[0]) || !(blockTimeRange === null || blockTimeRange === void 0 ? void 0 : blockTimeRange[1])) {
				message.warning(tCal("pisell2.recordBoard.calendar.block.warnSelectTime"));
				return;
			}
			const [start, end] = blockTimeRange;
			if (!end.isAfter(start)) {
				message.warning(tCal("pisell2.recordBoard.calendar.block.warnEndAfterStart"));
				return;
			}
			const rid = Number(blockResourceId);
			if (!Number.isFinite(rid) || rid <= 0) {
				message.warning(tCal("pisell2.recordBoard.calendar.block.warnSelectResource"));
				return;
			}
			const channels = (_props$blockedTimeSal = props.blockedTimeSalesChannels) !== null && _props$blockedTimeSal !== void 0 ? _props$blockedTimeSal : ["online_store"];
			const payload = {
				name: (blockFormName || "").trim() || 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 {
					if ((yield props.onBlockedTimeSave(payload)) === false) return;
					setShowBlockPanel(false);
					setSelectedFreeSlots([]);
					setSelectedResourceCells([]);
					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([]);
			setSelectedResourceCells([]);
			setShowBlockPanel(false);
			setBlockModalNote("");
		});
		return _saveBlockedTime.apply(this, arguments);
	}
	/** 拖拽改期松手：宿主接管改约，或弹出内置确认框 */
	const handleDropMove = useCallback((targetCourtId, targetDate, targetHour) => {
		if (!draggingItem) return;
		const duration = draggingItem.endHour - draggingItem.startHour;
		const nextStart = targetHour;
		const nextEnd = targetHour + duration;
		if (!isHourInTimelineSlots(nextStart, hourSlots) || nextEnd > endTimelineExclusive) return;
		const targetCourt = targetCourtId !== null && targetCourtId !== void 0 ? targetCourtId : draggingItem.courtId;
		const itemSnapshot = draggingItem;
		const draft = {
			targetCourtId: targetCourt,
			targetDate,
			targetHour
		};
		setDraggingItem(null);
		if (props.onBookingMoveRequest) {
			Promise.resolve(props.onBookingMoveRequest({
				item: itemSnapshot,
				draft
			})).catch(() => {});
			return;
		}
		setMoveConfirm({
			item: itemSnapshot,
			targetCourtId: targetCourt,
			targetDate,
			targetHour
		});
		setMoveDraft(draft);
	}, [
		draggingItem,
		hourSlots,
		endTimelineExclusive,
		props.onBookingMoveRequest
	]);
	/** 周/月格 drop：保持原开始小时，仅换日或资源 */
	const handleGridDropMove = useCallback((targetDate, targetCourtId = null) => {
		if (!draggingItem || draggingItem.kind === "block") return;
		handleDropMove(targetCourtId !== null && targetCourtId !== void 0 ? targetCourtId : draggingItem.courtId, targetDate, draggingItem.startHour);
	}, [draggingItem, handleDropMove]);
	/** 确认改期：在 bookings 中平移该条的起止小时与 court/date */
	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 ? _objectSpread2(_objectSpread2({}, b), {}, {
			courtId: targetCourtId,
			date: targetDate,
			startHour: targetHour,
			endHour: targetHour + duration
		}) : b));
		setMoveConfirm(null);
		setMoveDraft(null);
	}
	return /* @__PURE__ */ React.createElement(Spin, {
		spinning: Boolean(props.loading),
		wrapperClassName: "pisell-rb-cal-spin-wrap flex min-h-0 flex-1 flex-col"
	}, /* @__PURE__ */ React.createElement("div", { className: `theme-root theme-app flex h-full min-h-0 flex-col ${isLight ? "theme-light" : "theme-dark"}` }, /* @__PURE__ */ React.createElement("div", {
		className: "theme-shell soft-shadow mx-0 flex h-full min-h-0 w-full max-w-none flex-1 flex-col overflow-hidden transition-[padding-right] duration-200",
		style: { paddingRight: 0 }
	}, /* @__PURE__ */ React.createElement("div", { className: "flex min-h-0 flex-1 flex-col" }, view === "month" && /* @__PURE__ */ React.createElement(BookingCalendarMonthView, {
		isLight,
		anchorDate,
		monthDays,
		bookings,
		goToDayFromCell,
		handleGridDropMove,
		setDraggingItem,
		openBookingDetail,
		overflowPopover,
		setOverflowPopover,
		overflowListModal,
		setOverflowListModal,
		overflowPanelRef,
		renderMonthWeekBooking: props.renderMonthWeekBooking
	}), view === "week" && /* @__PURE__ */ React.createElement(BookingCalendarWeekView, {
		calendarProps: props,
		isLight,
		weekDays,
		bookings,
		courts,
		hourSlots,
		slotStepHours,
		visibleCourts,
		visibleCourtRows,
		isBusinessHour,
		goToDayFromCell,
		handleGridDropMove,
		openBookingDetail,
		setDraggingItem,
		setCollapsedGroups,
		overflowPopover,
		setOverflowPopover,
		overflowListModal,
		setOverflowListModal,
		overflowPanelRef
	}), view === "resource" && /* @__PURE__ */ React.createElement(BookingCalendarResourceView, {
		calendarProps: props,
		isLight,
		anchorDate,
		monthDays: resourceMonthDays,
		slotColWidth: resourceViewSlotColWidth,
		bookings,
		hourSlots,
		slotStepHours,
		visibleCourts,
		visibleCourtRows,
		handleGridDropMove,
		openBookingDetail,
		setDraggingItem,
		setCollapsedGroups,
		overflowPopover,
		setOverflowPopover,
		setOverflowListModal,
		overflowPanelRef,
		resourceMonthScrollToTodayToken,
		resourceDayHeaderRemaining,
		toggleResourceCell,
		selectedResourceCells
	}), view === "day" && /* @__PURE__ */ React.createElement(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,
		focusedCourtId,
		dayTimelineScrollToNowToken
	}))), view === "day" && (selectedFreeSlots.length > 0 || selectedBlockSlots.length > 0) || view === "resource" && selectedResourceCells.length > 0 ? /* @__PURE__ */ React.createElement(BookingCalendarDaySelectionBar, {
		slotStepHours,
		selectedFreeSlots: view === "resource" ? [] : selectedFreeSlots,
		resourceSelectionSummary: view === "resource" ? resourceSelectionBarMeta : void 0,
		deselectAll: view === "resource" ? () => setSelectedResourceCells([]) : deselectAll,
		onOpenBlockPanel: view === "resource" ? handleOpenBlockPanelFromResource : handleOpenBlockPanelFromSelection,
		createBookingFromSelection: view === "resource" ? createBookingFromResourceSelection : createBookingFromSelection
	}) : null, showBlockPanel && !props.onBlockedTimePanelRequest && (view === "resource" ? resourceSelectionContiguous : selectedFreeSlots.length > 0 && isFreeSelectionContiguousSameResource(selectedFreeSlots, slotStepHours)) && /* @__PURE__ */ React.createElement(BookingCalendarBlockPanel, {
		blockPanelRef,
		isLight,
		blockFormName,
		setBlockFormName,
		blockModalNote,
		setBlockModalNote,
		blockResourceId,
		setBlockResourceId,
		blockTimeRange,
		setBlockTimeRange,
		resolvedSlotMinutes,
		visibleCourts,
		blockSaving,
		onClose: () => setShowBlockPanel(false),
		onSave: saveBlockedTime
	}), overflowListModal && /* @__PURE__ */ React.createElement(BookingCalendarOverflowListLayer, {
		overflowPanelRef,
		isLight,
		modal: overflowListModal,
		onClose: () => setOverflowListModal(null),
		onPickItem: openBookingDetail
	}), moveConfirm && /* @__PURE__ */ React.createElement(MoveConfirmModal, {
		moveConfirm,
		moveDraft,
		setMoveDraft,
		panelRef: moveConfirmRef,
		isLight,
		courts,
		visibleCourts,
		hourSlots,
		isBusinessHour,
		firstTimelineHour,
		endTimelineExclusive,
		onConfirm: confirmMove,
		onClose: () => {
			setMoveConfirm(null);
			setMoveDraft(null);
		}
	}), transitioningToDay && /* @__PURE__ */ React.createElement("div", { className: "fixed inset-6 z-[60] rounded-[28px] border border-violet-400/20 bg-[#151220] pointer-events-none" })));
}
//#endregion
export { BookingCalendar as default };
