import { getContentSize, getPixelBoundingBox } from "./layoutMeasurements.js";
//#region src/components/pisellFloorMapLayout/utils/floorMapCanvasStage.ts
/**
* 根据 items 计算内容区尺寸与偏移。
* 算法与 {@link useFloorMapTransformMetrics} 内原 useMemo 一致（不含「撑满视口」扩展）。
*/
function computeFloorMapContentStage(params) {
	const { items, cellSize, itemGap, itemUnit, boundingPadding, preferPixelBoundingBox = true } = params;
	const padSingle = boundingPadding;
	const pad = padSingle * 2;
	const box = preferPixelBoundingBox && itemUnit === "pixel" && items.length > 0 ? getPixelBoundingBox(items, cellSize) : null;
	if (box) return {
		contentWidth: box.maxRight - box.minLeft + pad,
		contentHeight: box.maxBottom - box.minTop + pad,
		contentOffsetX: padSingle - box.minLeft,
		contentOffsetY: padSingle - box.minTop,
		alignPadSingle: padSingle
	};
	const fromItems = getContentSize(items, cellSize, itemGap, itemUnit);
	return {
		contentWidth: fromItems.contentWidth + pad,
		contentHeight: fromItems.contentHeight + pad,
		contentOffsetX: 0,
		contentOffsetY: 0,
		alignPadSingle: null
	};
}
/**
* 全览网格行列：n≤3 单行；n≥4 用 ceil(√n) 列、ceil(n/cols) 行，行列接近且末行空格最少。
* 例：2→2×1，3→3×1，4→2×2，5/6→3×2，7-9→3×3，10-12→4×3。
*
* 仅供旧版「等大缩略图卡片」全览使用；新版 All 视图按原始尺寸装箱，请用
* {@link packCanvasesIntoShelves}。
*/
function getOverviewGridDims(count) {
	if (count <= 0) return {
		cols: 1,
		rows: 1
	};
	if (count <= 3) return {
		cols: count,
		rows: 1
	};
	const cols = Math.ceil(Math.sqrt(count));
	return {
		cols,
		rows: Math.ceil(count / cols)
	};
}
/**
* 多画布 All 视图的紧凑装箱（Bottom-Left Fill, BLF）：
*
* - 保留输入顺序（与 Tab 顺序一致），不旋转、不缩放，原始尺寸即渲染尺寸；
* - 对每张画布枚举候选落点 = `{(0,0)} ∪ 已放画布的{右侧, 下方}角`；过滤掉与已放冲突
*   的位置，再挑 **y 最小、再 x 最小** 的位置落下——优先填低洼，自然会把矮 / 窄画布
*   塞进高画布旁的空白；不会出现「等最高画布把整行撑满才换行」导致的大量空白；
* - 目标外框宽度 `targetWidth = max(最宽画布, √(总面积 × {@link aspectBias}))`，
*   令整体形状趋于 `aspectBias:1`（默认 2.5 → 宽:高 ≈ 2.5:1，轻微偏横）；
*   单张画布若本身比 targetWidth 还宽，仍允许独自首行铺开，避免被截。
*
* 复杂度 O(n²)（每个画布对所有已放做候选 + 冲突校验），n 通常 < 20，性能足够。
* 比旧的行装填（shelf packing）能显著减少长高画布旁的留白。
*
* @param boxes - 待装箱画布尺寸（保持顺序）
* @param gap - 画布之间的像素间距（同时作为冲突检测的最小净距）
* @param aspectBias - 目标宽高比偏置（width:height）；越大越横向，默认 2.5
*   - `1.5` ~ `2`：接近正方形，仅略偏横
*   - `2.5` ~ `3`：明显但温和的横向布局（推荐）
*   - `>= 4`：强横向，画布数较多时易接近单行
*/
function packCanvasesIntoShelves(boxes, gap, aspectBias = 2.5) {
	if (boxes.length === 0) return {
		positions: [],
		totalWidth: 0,
		totalHeight: 0
	};
	const safeGap = Math.max(0, gap);
	const safeBias = Number.isFinite(aspectBias) && aspectBias > 0 ? aspectBias : 1;
	const totalArea = boxes.reduce((acc, b) => acc + Math.max(0, b.width) * Math.max(0, b.height), 0);
	const widestBox = boxes.reduce((max, b) => Math.max(max, b.width), 0);
	const targetWidth = Math.max(widestBox, Math.sqrt(totalArea * safeBias));
	const placed = [];
	const positions = new Array(boxes.length);
	let totalWidth = 0;
	let totalHeight = 0;
	/**
	* 两矩形（带 safeGap 净距）是否冲突。
	* 不冲突条件：A 在 B 右侧 / 左侧 / 下方 / 上方 至少留 safeGap。
	* 取反即为冲突条件（x 与 y 方向都「靠得太近」）。
	*/
	const conflicts = (x, y, w, h, p) => {
		const xClash = x + w + safeGap > p.x && p.x + p.w + safeGap > x;
		const yClash = y + h + safeGap > p.y && p.y + p.h + safeGap > y;
		return xClash && yClash;
	};
	boxes.forEach((box, i) => {
		/**
		* 候选位置：原点 + 每张已放画布的「右侧角、下方角」。
		* 简单角点集对 n<20 的常见场景已能贴合 MaxRects 的视觉效果。
		*/
		const candidates = [{
			x: 0,
			y: 0
		}];
		for (const p of placed) {
			candidates.push({
				x: p.x + p.w + safeGap,
				y: p.y
			});
			candidates.push({
				x: p.x,
				y: p.y + p.h + safeGap
			});
		}
		let bestX = Number.POSITIVE_INFINITY;
		let bestY = Number.POSITIVE_INFINITY;
		for (const cand of candidates) {
			const { x, y } = cand;
			/**
			* 超出目标宽度的候选直接淘汰；除非：
			* - 这是第一张画布（placed 为空），或
			* - 这张画布本身就比 targetWidth 还宽（允许独占首行）。
			*/
			if (x + box.width > targetWidth && placed.length > 0 && box.width <= targetWidth) continue;
			let clash = false;
			for (const p of placed) if (conflicts(x, y, box.width, box.height, p)) {
				clash = true;
				break;
			}
			if (clash) continue;
			if (y < bestY || y === bestY && x < bestX) {
				bestX = x;
				bestY = y;
			}
		}
		if (!Number.isFinite(bestX)) {
			/** 兜底：实在挤不下就堆到所有已放画布的最下方（极端宽画布场景） */
			bestX = 0;
			bestY = placed.reduce((m, p) => Math.max(m, p.y + p.h + safeGap), 0);
		}
		placed.push({
			x: bestX,
			y: bestY,
			w: box.width,
			h: box.height
		});
		positions[i] = {
			x: bestX,
			y: bestY
		};
		if (bestX + box.width > totalWidth) totalWidth = bestX + box.width;
		if (bestY + box.height > totalHeight) totalHeight = bestY + box.height;
	});
	return {
		positions,
		totalWidth,
		totalHeight
	};
}
//#endregion
export { computeFloorMapContentStage, getOverviewGridDims, packCanvasesIntoShelves };
