import { getCornerPoint, getOppositeCorner } from "./transformUtils.js";

//#region src/gui/transformCalculations.ts
/**
* Calculate the axis-aligned bounding box of a rotated rectangle.
* Given the element's position (top-left), size, and rotation,
* returns the min/max x/y that fully contains the rotated rectangle.
*/
function getRotatedBoundingBox(x, y, width, height, rotationDegrees) {
	if (rotationDegrees === 0) return {
		minX: x,
		minY: y,
		maxX: x + width,
		maxY: y + height
	};
	const rotationRadians = rotationDegrees * Math.PI / 180;
	const cos = Math.cos(rotationRadians);
	const sin = Math.sin(rotationRadians);
	const centerX = x + width / 2;
	const centerY = y + height / 2;
	const halfW = width / 2;
	const halfH = height / 2;
	const corners = [
		{
			x: -halfW,
			y: -halfH
		},
		{
			x: halfW,
			y: -halfH
		},
		{
			x: halfW,
			y: halfH
		},
		{
			x: -halfW,
			y: halfH
		}
	];
	let minX = Infinity;
	let minY = Infinity;
	let maxX = -Infinity;
	let maxY = -Infinity;
	for (const corner of corners) {
		const rotatedX = corner.x * cos - corner.y * sin + centerX;
		const rotatedY = corner.x * sin + corner.y * cos + centerY;
		minX = Math.min(minX, rotatedX);
		minY = Math.min(minY, rotatedY);
		maxX = Math.max(maxX, rotatedX);
		maxY = Math.max(maxY, rotatedY);
	}
	return {
		minX,
		minY,
		maxX,
		maxY
	};
}
/**
* Get the cursor type for a resize handle based on rotation.
* The cursor should reflect the actual direction the handle will resize in screen space.
*
* @param handle - The resize handle identifier
* @param rotationDegrees - Current rotation in degrees (0-360)
* @returns CSS cursor value
*/
function getResizeHandleCursor(handle, rotationDegrees) {
	const effectiveAngle = ({
		n: 0,
		ne: 45,
		e: 90,
		se: 135,
		s: 180,
		sw: 225,
		w: 270,
		nw: 315
	}[handle] + rotationDegrees) % 360;
	const normalizedAngle = effectiveAngle < 0 ? effectiveAngle + 360 : effectiveAngle;
	if (normalizedAngle >= 337.5 || normalizedAngle < 22.5) return "n-resize";
	else if (normalizedAngle >= 22.5 && normalizedAngle < 67.5) return "ne-resize";
	else if (normalizedAngle >= 67.5 && normalizedAngle < 112.5) return "e-resize";
	else if (normalizedAngle >= 112.5 && normalizedAngle < 157.5) return "se-resize";
	else if (normalizedAngle >= 157.5 && normalizedAngle < 202.5) return "s-resize";
	else if (normalizedAngle >= 202.5 && normalizedAngle < 247.5) return "sw-resize";
	else if (normalizedAngle >= 247.5 && normalizedAngle < 292.5) return "w-resize";
	else return "nw-resize";
}
/**
* Calculate new bounds for drag operation in canvas coordinates.
* Pure function - no side effects.
*
* Works in canvas coordinate space with zoom as a parameter.
* Converts screen deltas to canvas deltas.
*
* @param startPosition - Starting position in canvas coordinates
* @param screenDeltaX - Mouse movement delta in screen pixels
* @param screenDeltaY - Mouse movement delta in screen pixels
* @param zoomScale - Canvas zoom scale (1.0 = no zoom, 2.0 = 2x zoom, etc.)
* @returns New bounds with updated position (in canvas coordinates)
*/
function calculateDragBounds(startPosition, screenDeltaX, screenDeltaY, zoomScale = 1) {
	if (zoomScale <= 0) throw new Error("Zoom scale must be greater than 0");
	const canvasDeltaX = screenDeltaX / zoomScale;
	const canvasDeltaY = screenDeltaY / zoomScale;
	return {
		x: startPosition.x + canvasDeltaX,
		y: startPosition.y + canvasDeltaY
	};
}
/**
* Calculate new bounds for resize operation in canvas coordinates.
* Pure function - no side effects.
*
* Works in canvas coordinate space with zoom as a parameter.
* Converts screen deltas to canvas deltas, calculates new bounds in canvas coordinates.
*
* @param startSize - Starting size in canvas coordinates
* @param startPosition - Starting position in canvas coordinates
* @param startCorner - Starting corner position in canvas coordinates
* @param handle - Resize handle being dragged
* @param screenDeltaX - Mouse movement delta in screen pixels
* @param screenDeltaY - Mouse movement delta in screen pixels
* @param rotationDegrees - Current rotation in degrees
* @param minSize - Minimum size constraint in canvas coordinates
* @param zoomScale - Canvas zoom scale (1.0 = no zoom, 2.0 = 2x zoom, etc.)
* @param options - Optional resize modifiers (lockAspectRatio, resizeFromCenter)
* @returns New bounds with updated size and position (in canvas coordinates)
*/
function calculateResizeBounds(startSize, startPosition, startCorner, handle, screenDeltaX, screenDeltaY, rotationDegrees, minSize, zoomScale = 1, options = {}) {
	if (zoomScale <= 0) throw new Error("Zoom scale must be greater than 0");
	const { lockAspectRatio = false, resizeFromCenter = false } = options;
	const initialAspectRatio = startSize.width / startSize.height;
	const canvasDeltaX = screenDeltaX / zoomScale;
	const canvasDeltaY = screenDeltaY / zoomScale;
	const rotationRadians = rotationDegrees * Math.PI / 180;
	const oppositeCorner = getOppositeCorner(handle);
	const cos = Math.cos(-rotationRadians);
	const sin = Math.sin(-rotationRadians);
	const rotatedDeltaX = cos * canvasDeltaX - sin * canvasDeltaY;
	const rotatedDeltaY = sin * canvasDeltaX + cos * canvasDeltaY;
	const deltaMultiplier = resizeFromCenter ? 2 : 1;
	let newWidth = startSize.width;
	let newHeight = startSize.height;
	if (handle.includes("e")) newWidth = startSize.width + rotatedDeltaX * deltaMultiplier;
	else if (handle.includes("w")) newWidth = startSize.width - rotatedDeltaX * deltaMultiplier;
	if (handle.includes("s")) newHeight = startSize.height + rotatedDeltaY * deltaMultiplier;
	else if (handle.includes("n")) newHeight = startSize.height - rotatedDeltaY * deltaMultiplier;
	if (lockAspectRatio) {
		const isCornerHandle = handle.length === 2;
		const isHorizontalOnly = handle === "e" || handle === "w";
		const isVerticalOnly = handle === "n" || handle === "s";
		if (isCornerHandle) {
			const widthScale = newWidth / startSize.width;
			const heightScale = newHeight / startSize.height;
			const uniformScale = Math.abs(widthScale - 1) > Math.abs(heightScale - 1) ? widthScale : heightScale;
			newWidth = startSize.width * uniformScale;
			newHeight = startSize.height * uniformScale;
		} else if (isHorizontalOnly) newHeight = newWidth / initialAspectRatio;
		else if (isVerticalOnly) newWidth = newHeight * initialAspectRatio;
	}
	newWidth = Math.max(minSize, newWidth);
	newHeight = Math.max(minSize, newHeight);
	if (lockAspectRatio && (newWidth === minSize || newHeight === minSize)) if (newWidth === minSize) newHeight = Math.max(minSize, minSize / initialAspectRatio);
	else newWidth = Math.max(minSize, minSize * initialAspectRatio);
	let newX;
	let newY;
	if (resizeFromCenter) {
		const centerX = startPosition.x + startSize.width / 2;
		const centerY = startPosition.y + startSize.height / 2;
		newX = centerX - newWidth / 2;
		newY = centerY - newHeight / 2;
	} else {
		const newOppositeCorner = getCornerPoint(startPosition.x, startPosition.y, newWidth, newHeight, rotationRadians, oppositeCorner.x, oppositeCorner.y);
		const offsetX = startCorner.x - newOppositeCorner.x;
		const offsetY = startCorner.y - newOppositeCorner.y;
		newX = startPosition.x + offsetX;
		newY = startPosition.y + offsetY;
	}
	return {
		x: newX,
		y: newY,
		width: newWidth,
		height: newHeight
	};
}
/**
* Parse rotation angle from CSS transform.
* Handles both rotate() syntax and matrix() transforms.
* Pure function - no side effects.
*
* @param transform - CSS transform string (e.g., "rotate(45deg)" or "matrix(a, b, c, d, e, f)")
* @returns Rotation angle in degrees
*/
function parseRotationFromTransform(transform) {
	if (!transform || transform === "none") return 0;
	const rotateMatch = transform.match(/rotate\(([^)]+)\)/);
	if (rotateMatch?.[1]) {
		const value = rotateMatch[1].trim();
		const numValue = parseFloat(value);
		const unit = value.replace(String(numValue), "").trim();
		if (unit === "rad" || unit === "radians") return numValue * 180 / Math.PI;
		return numValue;
	}
	const matrixMatch = transform.match(/matrix\(([^)]+)\)/);
	if (!matrixMatch?.[1]) return 0;
	const values = matrixMatch[1].split(",").map((v) => parseFloat(v.trim()));
	if (values.length < 2) return 0;
	const a = values[0];
	const b = values[1];
	if (a === void 0 || b === void 0 || isNaN(a) || isNaN(b)) return 0;
	return Math.atan2(b, a) * (180 / Math.PI);
}

//#endregion
export { calculateDragBounds, calculateResizeBounds, getResizeHandleCursor, getRotatedBoundingBox, parseRotationFromTransform };
//# sourceMappingURL=transformCalculations.js.map