const require_runtime = require("../../../_virtual/_rolldown/runtime.js");
const require_objectSpread2 = require("../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js");
let dayjs = require("dayjs");
dayjs = require_runtime.__toESM(dayjs);
//#region src/plus/pisellReservation/floorRoomCard/floorRoomCardUtils.ts
/**
* 图元多段联系人之间的间隔（中点两侧为 nbsp）。
* 普通空格在部分 inline-flex / flex 排版下会与相邻文本折叠，看起来像「了点没空格」。
*/
const FLOOR_ROOM_CARD_GUEST_SEGMENT_SEP = "\xA0·\xA0";
function normalizeHmsForDayjs(time) {
	const parts = time.trim().split(":").map((p) => p.trim());
	if (parts.length >= 2) return `${String(parts[0]).padStart(2, "0")}:${String(parts[1]).padStart(2, "0")}:${parts[2] != null ? String(parts[2]).padStart(2, "0") : "00"}`;
	return "00:00:00";
}
function bookingStartEndMs(startDate, startTime, endDate, endTime) {
	return {
		start: (0, dayjs.default)(`${startDate}T${normalizeHmsForDayjs(startTime)}`).valueOf(),
		end: (0, dayjs.default)(`${endDate}T${normalizeHmsForDayjs(endTime)}`).valueOf()
	};
}
/** 统一的起止毫秒（供资源墙/卡片兼容层复用，避免重复推断） */
function floorRoomCardBookingStartEndMs(booking) {
	return bookingStartEndMs(booking.start_date, booking.start_time, booking.end_date, booking.end_time);
}
/** 日程时刻按展示「整分」对齐（该分钟 00.000） */
function reservationScheduleMinuteFloorMs(ms) {
	if (!Number.isFinite(ms)) return ms;
	return (0, dayjs.default)(ms).startOf("minute").valueOf();
}
/**
* 大屏等资源墙：写在日程上的「结束」表示该分钟整段结束前不算 overtime；
* expired 从「结束时刻所在分钟的下一分钟」整点开始。
* 例：结束 9:00 → 9:00:00～9:00:59 仍 non-expired，9:01:00 起 expired。
*/
function reservationScheduleOccupiedOvertimeThresholdMs(endMs) {
	return reservationScheduleMinuteFloorMs(endMs) + 6e4;
}
/**
* 大屏等资源墙：未到「开始分钟」的下一分钟整点不算迟到（与结束侧对称）。
* 例：开始 8:00 → 8:00:00～8:00:59 仍 boardingSoon，8:01:00 起 late。
*/
function reservationScheduleReservedLateThresholdMs(startMs) {
	return reservationScheduleMinuteFloorMs(startMs) + 6e4;
}
/**
* 预留态时间行：图元内仅展示时刻 + 文案后缀，不展示开始日期。
*/
function formatFloorRoomCardBookingStartLine(booking, endSuffix) {
	var _booking$start_time;
	const hm = String((_booking$start_time = booking.start_time) !== null && _booking$start_time !== void 0 ? _booking$start_time : "").trim();
	if (hm) return `${hm} ${endSuffix}`.trim();
	return endSuffix;
}
/**
* 占用态时间行：图元内仅展示结束时刻 + 后缀，不展示结束日期。
*/
function formatFloorRoomCardBookingEndLine(booking, endSuffix) {
	var _booking$end_time;
	const hm = String((_booking$end_time = booking.end_time) !== null && _booking$end_time !== void 0 ? _booking$end_time : "").trim();
	if (hm) return `${hm} ${endSuffix}`.trim();
	return endSuffix;
}
/**
* 「下一条」等时段：图元内只写起止时刻，不写日期。
*/
function formatFloorRoomCardBookingTimeRange(booking) {
	var _booking$start_time2, _booking$end_time2;
	const st = String((_booking$start_time2 = booking.start_time) !== null && _booking$start_time2 !== void 0 ? _booking$start_time2 : "").trim();
	const et = String((_booking$end_time2 = booking.end_time) !== null && _booking$end_time2 !== void 0 ? _booking$end_time2 : "").trim();
	if (st && et) return `${st} - ${et}`;
	return st || et || "";
}
/** 预约时段内进度 0–100（与 demo getProgressPercent 一致，使用真实时间） */
function getFloorRoomCardProgressPercent(startDate, startTime, endDate, endTime, nowMs = Date.now()) {
	const { start, end } = bookingStartEndMs(startDate, startTime, endDate, endTime);
	if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) return 0;
	if (nowMs <= start) return 0;
	if (nowMs >= end) return 100;
	return Math.round((nowMs - start) / (end - start) * 100);
}
/**
* 进度条百分比：优先宿主 `progressPercent`（0–100），否则按起止时间与当前时刻推算。
*/
function resolveFloorRoomCardProgressPercent(booking, nowMs = Date.now()) {
	const p = booking.progressPercent;
	if (p != null && Number.isFinite(p)) return Math.min(100, Math.max(0, Math.round(p)));
	return getFloorRoomCardProgressPercent(booking.start_date, booking.start_time, booking.end_date, booking.end_time, nowMs);
}
/** 将分钟数格式化为「10m」「1h 5m」等（图元迟到/超时展示） */
function formatFloorRoomCardDurationMinutes(totalMin) {
	if (totalMin <= 0) return "0m";
	const h = Math.floor(totalMin / 60);
	const m = totalMin % 60;
	if (h > 0) return m > 0 ? `${h}h ${m}m` : `${h}h`;
	return `${m}m`;
}
/** 距开始时刻的倒计时分钟（不含文案前缀）；仅本地起止时间推算 */
function getFloorRoomCardArrivalMinutes(room, nowMs = Date.now()) {
	const b = room.bookings[0];
	if (!b || room.status !== "reserved") return null;
	const { start } = bookingStartEndMs(b.start_date, b.start_time, b.end_date, b.end_time);
	if (!Number.isFinite(start)) return null;
	const diffMin = Math.floor((start - nowMs) / 6e4);
	if (diffMin < 0) return null;
	return diffMin;
}
/**
* 预留态「还有 n 分钟」：优先宿主 `remainingReserveTime`（分钟，>0），否则 {@link getFloorRoomCardArrivalMinutes}
*/
function resolveFloorRoomCardReservedCountdownMinutes(room, nowMs = Date.now()) {
	const b = room.bookings[0];
	if (!b || room.status !== "reserved") return null;
	const r = b.remainingReserveTime;
	if (r != null && Number.isFinite(r)) {
		const n = Math.max(0, Math.round(r));
		if (n > 0) return n;
	}
	return getFloorRoomCardArrivalMinutes(room, nowMs);
}
/**
* 多预约列表中单条：与 {@link resolveFloorRoomCardReservedCountdownMinutes} 一致，但针对当前行 booking。
*/
function resolveFloorRoomCardReservedCountdownMinutesForBooking(booking, nowMs = Date.now()) {
	const r = booking.remainingReserveTime;
	if (r != null && Number.isFinite(r)) {
		const n = Math.max(0, Math.round(r));
		if (n > 0) return n;
	}
	const { start } = bookingStartEndMs(booking.start_date, booking.start_time, booking.end_date, booking.end_time);
	if (!Number.isFinite(start)) return null;
	const diffMin = Math.floor((start - nowMs) / 6e4);
	if (diffMin < 0) return null;
	return diffMin;
}
/**
* 紧凑多预约行：仅当该条 booking 有宿主 `lateTime`（分钟）时为 late，否则 not_arrived（不按本地时刻推算迟到）。
*/
function getFloorRoomCardReservedRowBodyType(booking, _nowMs = Date.now()) {
	if (booking.lateTime != null && Number.isFinite(booking.lateTime) && booking.lateTime > 0) return "late";
	return "not_arrived";
}
/** 当前时刻是否落在预约时段内 [start, end)（进行中） */
function isFloorRoomCardBookingInProgress(booking, nowMs = Date.now()) {
	const { start, end } = bookingStartEndMs(booking.start_date, booking.start_time, booking.end_date, booking.end_time);
	if (!Number.isFinite(start) || !Number.isFinite(end) || end <= start) return false;
	return nowMs >= start && nowMs < end;
}
/** 当前时刻是否在预约开始之前（未开始） */
function isFloorRoomCardBookingNotStarted(booking, nowMs = Date.now()) {
	const { start } = bookingStartEndMs(booking.start_date, booking.start_time, booking.end_date, booking.end_time);
	if (!Number.isFinite(start)) return false;
	return nowMs < start;
}
/**
* 第一条预约进行中且其后仍有未开始的时段：返回第一条「未开始」预约，用于 Next 行。
* 不依赖 cardType（不必 late/timeout）。
*/
function getFloorRoomCardNextNotStartedBooking(data, nowMs = Date.now()) {
	const list = data.bookings;
	if (list.length < 2) return null;
	if (!isFloorRoomCardBookingInProgress(list[0], nowMs)) return null;
	for (let i = 1; i < list.length; i++) if (isFloorRoomCardBookingNotStarted(list[i], nowMs)) return list[i];
	return null;
}
function sortFloorRoomCardBookingsByStart(list) {
	return [...list].sort((a, b) => {
		const { start: as } = bookingStartEndMs(a.start_date, a.start_time, a.end_date, a.end_time);
		const { start: bs } = bookingStartEndMs(b.start_date, b.start_time, b.end_date, b.end_time);
		return as - bs;
	});
}
/**
* 多条预约里恰好一条 `hostBookingStatus === 'occupied'` 时：把该条排到首位，便于标准占用卡用 bookings[0] 展示。
* 多条同时为 occupied 或未标记 host 时不改顺序。
*/
function reorderBookingsForSingleOccupiedPrimary(list) {
	if (list.length <= 1) return list;
	if (list.filter((b) => b.hostBookingStatus === "occupied").length !== 1) return list;
	const sorted = sortFloorRoomCardBookingsByStart(list);
	const occIdx = sorted.findIndex((b) => b.hostBookingStatus === "occupied");
	if (occIdx < 0) return list;
	const primary = sorted[occIdx];
	/** 当前占用之后的时段在前，便于 bookings[1] 与「下一条」一致 */
	const after = sorted.slice(occIdx + 1);
	const before = sorted.slice(0, occIdx);
	return [
		primary,
		...after,
		...before
	];
}
/**
* 多条预约且仅一条为 occupied：按开始时间排序后，取占用段之后的下一条（用于 Next 行）。
*/
function getFloorRoomCardNextAfterSingleOccupiedBooking(data) {
	const list = data.bookings;
	if (list.length < 2) return null;
	if (list.filter((b) => b.hostBookingStatus === "occupied").length !== 1) return null;
	const sorted = sortFloorRoomCardBookingsByStart(list);
	const i = sorted.findIndex((b) => b.hostBookingStatus === "occupied");
	if (i < 0 || i >= sorted.length - 1) return null;
	return sorted[i + 1];
}
/**
* 多条均为预留（无 occupied）：`bookings` 已按开始时间排好，主卡为 [0]，Next 为紧邻的下一条。
*/
function getFloorRoomCardNextAfterPrimaryReserved(data) {
	var _data$bookings$;
	if (data.status !== "reserved" || data.bookings.length < 2) return null;
	if (data.bookings.some((b) => b.hostBookingStatus === "occupied")) return null;
	return (_data$bookings$ = data.bookings[1]) !== null && _data$bookings$ !== void 0 ? _data$bookings$ : null;
}
/**
* 接口标记 `isNext` 的预约：按开始时间取第一条，供 Next 行展示。
*/
function getFloorRoomCardExplicitNextBooking(data) {
	var _sortFloorRoomCardBoo;
	const marked = data.bookings.filter((b) => b.isNext === true);
	if (marked.length === 0) return null;
	return (_sortFloorRoomCardBoo = sortFloorRoomCardBookingsByStart(marked)[0]) !== null && _sortFloorRoomCardBoo !== void 0 ? _sortFloorRoomCardBoo : null;
}
/**
* 与 {@link buildCardBodyViewModel} Next 行同一套优先级：接口 `is_next`/`isNext` →
* 单 occupied 后一条 → 多条 reserved 第二条 →「进行中」后首条未开始。
*/
function resolveFloorRoomCardNextBookingLikeBodyModel(data, nowMs = Date.now()) {
	var _ref, _ref2, _getFloorRoomCardExpl;
	return (_ref = (_ref2 = (_getFloorRoomCardExpl = getFloorRoomCardExplicitNextBooking(data)) !== null && _getFloorRoomCardExpl !== void 0 ? _getFloorRoomCardExpl : getFloorRoomCardNextAfterSingleOccupiedBooking(data)) !== null && _ref2 !== void 0 ? _ref2 : getFloorRoomCardNextAfterPrimaryReserved(data)) !== null && _ref !== void 0 ? _ref : getFloorRoomCardNextNotStartedBooking(data, nowMs);
}
/** Next 条客人一行：与图元同源，多层联系人用 ` · ` 拼接 */
function formatFloorRoomCardNextGuestStripLine(b) {
	return floorRoomCardGuestSegments(b, true).join(FLOOR_ROOM_CARD_GUEST_SEGMENT_SEP);
}
/** 单层 holder：姓名优先；预留态可手机号尾号脱敏 */
function formatFloorRoomCardGuestDisplayLineFromHolder(holder, showPhone) {
	var _holder$name;
	const n = holder === null || holder === void 0 || (_holder$name = holder.name) === null || _holder$name === void 0 ? void 0 : _holder$name.trim();
	if (n) return n;
	if (showPhone && (holder === null || holder === void 0 ? void 0 : holder.phone)) {
		const m = maskPisellReservationPhoneTail(holder.phone);
		if (m) return m;
	}
	return "";
}
function dedupeAdjacentDuplicateStrings(lines) {
	const out = [];
	for (const L of lines) {
		if (!L) continue;
		if (out.length === 0 || out[out.length - 1] !== L) out.push(L);
	}
	return out;
}
/**
* 图元联系人：按 holder → contacts_info → customer 各层格式化后合并；
* 无 {@link FloorRoomCardBooking.contactTiers} 时退化为单层 {@link FloorRoomCardBooking.holder}。
*/
function floorRoomCardGuestSegments(booking, showPhone) {
	const tiers = booking.contactTiers;
	if (tiers === null || tiers === void 0 ? void 0 : tiers.length) return dedupeAdjacentDuplicateStrings(tiers.map((t) => formatFloorRoomCardGuestDisplayLineFromHolder(require_objectSpread2._objectSpread2({ name: t.name }, t.phone ? { phone: t.phone } : {}), showPhone).trim()).filter(Boolean));
	const fb = formatFloorRoomCardGuestDisplayLineFromHolder(booking.holder, showPhone).trim();
	return fb ? [fb] : [];
}
/**
* 联系人展示字符串（单层或多层 ` · `）；与平面图 / 资源墙单行摘要一致。
*/
function formatFloorRoomCardGuestDisplayLine(booking, showPhone) {
	return floorRoomCardGuestSegments(booking, showPhone).join(FLOOR_ROOM_CARD_GUEST_SEGMENT_SEP);
}
/**
* 主区域展示用：第一条非 `isNext`；若全部为 next 则回退首条。
*/
function getFloorRoomCardPrimaryBooking(data) {
	const non = data.bookings.find((b) => b.isNext !== true);
	return non !== null && non !== void 0 ? non : data.bookings[0];
}
/**
* 多条预约且均为预留态（host 为 reserved 或未标）：按开始时间排序，主卡只展示最近一档，其余走 Next。
*/
function reorderBookingsAllReservedChronological(list) {
	if (list.length <= 1) return list;
	if (list.some((b) => b.hostBookingStatus === "occupied")) return list;
	if (!list.every((b) => b.hostBookingStatus == null || b.hostBookingStatus === "reserved")) return list;
	return sortFloorRoomCardBookingsByStart(list);
}
/** 与 demo getCardType 一致 */
function getFloorRoomCardType(room) {
	if (room.status === "locked") return "locked";
	if (room.status === "empty") return "empty";
	/**
	* 多条 / 单条判定一律基于「主档预约」，即排除被业务标记为 `isNext` 的下一档预约。
	* 历史实现里这个豁免只在 reserved 态做了一次（"1 reserved + 1 next ≈ 单条 + Next 条带"），
	* occupied 态没做，导致"1 用餐中 + 1 Next"也被判成 multi_occupied，body 走 `.rc-compact` 紧凑排，
	* 与设计预期"主档单条 = 单条卡 + 底部 Next 条带"不一致。这里把豁免推广到通用：
	*   - 主档 ≤ 1 条 → 一律走标准单条卡分支（剩下若有 isNext 由 RoomCardBodyView 的 Next 条带渲染）
	*   - 主档 ≥ 2 条 → 才进入 multi_* 列表卡分支
	*/
	const mainBookings = room.bookings.filter((b) => b.isNext !== true);
	const occCount = mainBookings.filter((b) => b.hostBookingStatus === "occupied").length;
	if (mainBookings.length > 1) {
		if (room.status === "reserved" && occCount === 0) return "multi_reserved";
		const withHost = mainBookings.filter((b) => b.hostBookingStatus != null);
		if (withHost.length > 0) {
			if (occCount >= 2) return "multi_occupied";
			if (occCount === 1 && room.status === "occupied") {
				const s = room.sub_status;
				if (s === "payed" || s === "payment_required" || s === "timeout") return s;
				return "payed";
			}
			if (withHost.every((b) => b.hostBookingStatus === "reserved")) {
				const s = room.sub_status;
				if (s === "not_arrived" || s === "late") return s;
				return "not_arrived";
			}
		}
		if (room.status === "occupied") {
			const s = room.sub_status;
			if (s === "payed" || s === "payment_required" || s === "timeout") return s;
			return "payed";
		}
		if (room.status === "reserved") {
			const s = room.sub_status;
			if (s === "not_arrived" || s === "late") return s;
			return "not_arrived";
		}
	}
	if (room.status === "occupied") {
		const s = room.sub_status;
		if (s === "payed" || s === "payment_required" || s === "timeout") return s;
		return "payed";
	}
	if (room.status === "reserved") {
		const s = room.sub_status;
		if (s === "not_arrived" || s === "late") return s;
		return "not_arrived";
	}
	return "empty";
}
/**
* 平面图 RoomCard 联系人手机号展示：与 {@link ReservationFloorRoomCard} ContactInfo 一致。
*/
function maskPisellReservationPhoneTail(phone) {
	return phone.length >= 4 ? `***${phone.slice(-4)}` : null;
}
/**
* 房间标题：优先数据行 `main_field` 展示名（` ## ` 前为主名称），其次 `code`，最后图元编辑名。
* 与平面图 `reservationCards` 绑定桌位卡一致。
*/
function displayRoomTitleFromRow(row, sceneElementName) {
	var _row$code;
	const rawMain = row.main_field;
	if (typeof rawMain === "string" && rawMain.trim()) {
		var _rawMain$split$;
		const first = (_rawMain$split$ = rawMain.split(" ## ")[0]) === null || _rawMain$split$ === void 0 ? void 0 : _rawMain$split$.trim();
		if (first) return first;
	}
	const c = (_row$code = row.code) === null || _row$code === void 0 ? void 0 : _row$code.trim();
	if (c) return c;
	const n = sceneElementName === null || sceneElementName === void 0 ? void 0 : sceneElementName.trim();
	if (n) return n;
	return "";
}
//#endregion
exports.FLOOR_ROOM_CARD_GUEST_SEGMENT_SEP = FLOOR_ROOM_CARD_GUEST_SEGMENT_SEP;
exports.displayRoomTitleFromRow = displayRoomTitleFromRow;
exports.floorRoomCardBookingStartEndMs = floorRoomCardBookingStartEndMs;
exports.floorRoomCardGuestSegments = floorRoomCardGuestSegments;
exports.formatFloorRoomCardBookingEndLine = formatFloorRoomCardBookingEndLine;
exports.formatFloorRoomCardBookingStartLine = formatFloorRoomCardBookingStartLine;
exports.formatFloorRoomCardBookingTimeRange = formatFloorRoomCardBookingTimeRange;
exports.formatFloorRoomCardDurationMinutes = formatFloorRoomCardDurationMinutes;
exports.formatFloorRoomCardGuestDisplayLine = formatFloorRoomCardGuestDisplayLine;
exports.formatFloorRoomCardGuestDisplayLineFromHolder = formatFloorRoomCardGuestDisplayLineFromHolder;
exports.formatFloorRoomCardNextGuestStripLine = formatFloorRoomCardNextGuestStripLine;
exports.getFloorRoomCardExplicitNextBooking = getFloorRoomCardExplicitNextBooking;
exports.getFloorRoomCardPrimaryBooking = getFloorRoomCardPrimaryBooking;
exports.getFloorRoomCardReservedRowBodyType = getFloorRoomCardReservedRowBodyType;
exports.getFloorRoomCardType = getFloorRoomCardType;
exports.isFloorRoomCardBookingInProgress = isFloorRoomCardBookingInProgress;
exports.isFloorRoomCardBookingNotStarted = isFloorRoomCardBookingNotStarted;
exports.maskPisellReservationPhoneTail = maskPisellReservationPhoneTail;
exports.reorderBookingsAllReservedChronological = reorderBookingsAllReservedChronological;
exports.reorderBookingsForSingleOccupiedPrimary = reorderBookingsForSingleOccupiedPrimary;
exports.reservationScheduleMinuteFloorMs = reservationScheduleMinuteFloorMs;
exports.reservationScheduleOccupiedOvertimeThresholdMs = reservationScheduleOccupiedOvertimeThresholdMs;
exports.reservationScheduleReservedLateThresholdMs = reservationScheduleReservedLateThresholdMs;
exports.resolveFloorRoomCardNextBookingLikeBodyModel = resolveFloorRoomCardNextBookingLikeBodyModel;
exports.resolveFloorRoomCardProgressPercent = resolveFloorRoomCardProgressPercent;
exports.resolveFloorRoomCardReservedCountdownMinutes = resolveFloorRoomCardReservedCountdownMinutes;
exports.resolveFloorRoomCardReservedCountdownMinutesForBooking = resolveFloorRoomCardReservedCountdownMinutesForBooking;
