/**
 * Selection Transforms — align, distribute, arrange, and match-size
 * operations on canvas shape elements.
 *
 * Each function accepts an array of shape elements (with x, y, width, height)
 * and mutates their positions in place.
 *
 * Exposed on `window.__miSelectionTransforms` so the MiActionExecutor can
 * invoke them by name.
 */

interface ShapeEl {
	x: number;
	y: number;
	width: number;
	height: number;
}

// ── Align ──

export function alignLeft(shapes: ShapeEl[]) {
	if (shapes.length < 2) return;
	const minX = Math.min(...shapes.map((s) => s.x));
	for (const s of shapes) s.x = minX;
}

export function alignRight(shapes: ShapeEl[]) {
	if (shapes.length < 2) return;
	const maxRight = Math.max(...shapes.map((s) => s.x + s.width));
	for (const s of shapes) s.x = maxRight - s.width;
}

export function alignCenterH(shapes: ShapeEl[]) {
	if (shapes.length < 2) return;
	const centers = shapes.map((s) => s.x + s.width / 2);
	const avg = centers.reduce((a, b) => a + b, 0) / centers.length;
	for (const s of shapes) s.x = avg - s.width / 2;
}

export function alignTop(shapes: ShapeEl[]) {
	if (shapes.length < 2) return;
	const minY = Math.min(...shapes.map((s) => s.y));
	for (const s of shapes) s.y = minY;
}

export function alignBottom(shapes: ShapeEl[]) {
	if (shapes.length < 2) return;
	const maxBottom = Math.max(...shapes.map((s) => s.y + s.height));
	for (const s of shapes) s.y = maxBottom - s.height;
}

export function alignCenterV(shapes: ShapeEl[]) {
	if (shapes.length < 2) return;
	const centers = shapes.map((s) => s.y + s.height / 2);
	const avg = centers.reduce((a, b) => a + b, 0) / centers.length;
	for (const s of shapes) s.y = avg - s.height / 2;
}

// ── Distribute ──

export function distributeH(shapes: ShapeEl[]) {
	if (shapes.length < 3) return;
	const sorted = [...shapes].sort((a, b) => a.x - b.x);
	const first = sorted[0];
	const last = sorted[sorted.length - 1];
	const totalWidth = sorted.reduce((s, el) => s + el.width, 0);
	const span = last.x + last.width - first.x;
	const gap = (span - totalWidth) / (sorted.length - 1);

	let cursor = first.x;
	for (const s of sorted) {
		s.x = cursor;
		cursor += s.width + gap;
	}
}

export function distributeV(shapes: ShapeEl[]) {
	if (shapes.length < 3) return;
	const sorted = [...shapes].sort((a, b) => a.y - b.y);
	const first = sorted[0];
	const last = sorted[sorted.length - 1];
	const totalHeight = sorted.reduce((s, el) => s + el.height, 0);
	const span = last.y + last.height - first.y;
	const gap = (span - totalHeight) / (sorted.length - 1);

	let cursor = first.y;
	for (const s of sorted) {
		s.y = cursor;
		cursor += s.height + gap;
	}
}

// ── Arrange ──

export function arrangeRow(shapes: ShapeEl[]) {
	if (shapes.length < 2) return;
	const gap = 30;
	const baseY = Math.min(...shapes.map((s) => s.y));
	let cursor = shapes[0].x;
	for (const s of shapes) {
		s.x = cursor;
		s.y = baseY;
		cursor += s.width + gap;
	}
}

export function arrangeColumn(shapes: ShapeEl[]) {
	if (shapes.length < 2) return;
	const gap = 30;
	const baseX = Math.min(...shapes.map((s) => s.x));
	let cursor = shapes[0].y;
	for (const s of shapes) {
		s.x = baseX;
		s.y = cursor;
		cursor += s.height + gap;
	}
}

export function arrangeGrid(shapes: ShapeEl[]) {
	if (shapes.length < 2) return;
	const cols = Math.ceil(Math.sqrt(shapes.length));
	const gap = 30;
	const baseX = Math.min(...shapes.map((s) => s.x));
	const baseY = Math.min(...shapes.map((s) => s.y));
	const maxW = Math.max(...shapes.map((s) => s.width));
	const maxH = Math.max(...shapes.map((s) => s.height));

	for (let i = 0; i < shapes.length; i++) {
		const col = i % cols;
		const row = Math.floor(i / cols);
		shapes[i].x = baseX + col * (maxW + gap);
		shapes[i].y = baseY + row * (maxH + gap);
	}
}

export function arrangeCircle(shapes: ShapeEl[]) {
	if (shapes.length < 2) return;
	const cx = shapes.reduce((s, el) => s + el.x + el.width / 2, 0) / shapes.length;
	const cy = shapes.reduce((s, el) => s + el.y + el.height / 2, 0) / shapes.length;
	const maxDim = Math.max(...shapes.map((s) => Math.max(s.width, s.height)));
	const radius = Math.max(maxDim * shapes.length / (2 * Math.PI), 150);
	const step = (2 * Math.PI) / shapes.length;

	for (let i = 0; i < shapes.length; i++) {
		const angle = step * i - Math.PI / 2;
		shapes[i].x = cx + radius * Math.cos(angle) - shapes[i].width / 2;
		shapes[i].y = cy + radius * Math.sin(angle) - shapes[i].height / 2;
	}
}

// ── Match Size ──

export function matchWidth(shapes: ShapeEl[]) {
	if (shapes.length < 2) return;
	const maxW = Math.max(...shapes.map((s) => s.width));
	for (const s of shapes) s.width = maxW;
}

export function matchHeight(shapes: ShapeEl[]) {
	if (shapes.length < 2) return;
	const maxH = Math.max(...shapes.map((s) => s.height));
	for (const s of shapes) s.height = maxH;
}

export function matchSize(shapes: ShapeEl[]) {
	matchWidth(shapes);
	matchHeight(shapes);
}

// ── Registry: kebab-name → function ──

const TRANSFORM_MAP: Record<string, (shapes: ShapeEl[]) => void> = {
	"align-left": alignLeft,
	"align-right": alignRight,
	"align-center-h": alignCenterH,
	"align-top": alignTop,
	"align-bottom": alignBottom,
	"align-center-v": alignCenterV,
	"distribute-h": distributeH,
	"distribute-v": distributeV,
	"arrange-row": arrangeRow,
	"arrange-column": arrangeColumn,
	"arrange-grid": arrangeGrid,
	"arrange-circle": arrangeCircle,
	"match-width": matchWidth,
	"match-height": matchHeight,
	"match-size": matchSize,
};

/** Install the transform map on window so the action executor can find them. */
export function installSelectionTransforms() {
	(window as any).__miSelectionTransforms = TRANSFORM_MAP;
}
