import { FEATHER_HANDLE_SCALE } from "@/masks/feather";
import type { ElementBounds } from "@/preview/element-bounds";
import type {
	MaskFeatures,
	MaskHandlePosition,
	MaskLineOverlay,
	MaskOverlay,
	MaskRectOverlay,
	RectangleMaskParams,
	MaskShapeOverlay,
} from "@/masks/types";

const LINE_HANDLE_OFFSET_SCREEN_PX = 20;
const BOX_HANDLE_OFFSET_SCREEN_PX = 20;
const LINE_EXTENT_MULTIPLIER = 50;

const CURSOR = {
	rotate: "crosshair",
	resizeDiagonal: "nwse-resize",
	resizeHorizontal: "ew-resize",
	resizeVertical: "ns-resize",
} as const;

/**
 * The renderer defines the split line as:
 *   - normal direction: (cos(rotation), sin(rotation))
 *   - line direction (parallel to cut): (-sin(rotation), cos(rotation))
 *   - reference point: (centerX * width, centerY * height) from element centre
 *
 * So rotation=0 → normal points right → line runs vertically.
 */
export function getLineMaskLinePoints({
	centerX,
	centerY,
	rotation,
	bounds,
}: {
	centerX: number;
	centerY: number;
	rotation: number;
	bounds: ElementBounds;
}): { start: { x: number; y: number }; end: { x: number; y: number } } {
	const angleRad = (rotation * Math.PI) / 180;
	const normalX = Math.cos(angleRad);
	const normalY = Math.sin(angleRad);
	const lineDirX = -normalY;
	const lineDirY = normalX;

	const cx = bounds.cx + centerX * bounds.width;
	const cy = bounds.cy + centerY * bounds.height;

	const extent = Math.max(bounds.width, bounds.height) * LINE_EXTENT_MULTIPLIER;

	return {
		start: {
			x: cx - lineDirX * extent,
			y: cy - lineDirY * extent,
		},
		end: {
			x: cx + lineDirX * extent,
			y: cy + lineDirY * extent,
		},
	};
}

export function getLineMaskOverlay({
	centerX,
	centerY,
	rotation,
	bounds,
	handleId = "position",
	cursor = "move",
}: {
	centerX: number;
	centerY: number;
	rotation: number;
	bounds: ElementBounds;
	handleId?: string;
	cursor?: string;
}): MaskLineOverlay {
	const { start, end } = getLineMaskLinePoints({
		centerX,
		centerY,
		rotation,
		bounds,
	});

	return {
		id: "line",
		type: "line",
		start,
		end,
		handleId,
		cursor,
	};
}

export function getLineMaskHandlePositions({
	centerX,
	centerY,
	rotation,
	feather,
	bounds,
	displayScale,
}: {
	centerX: number;
	centerY: number;
	rotation: number;
	feather: number;
	bounds: ElementBounds;
	displayScale: number;
}): MaskHandlePosition[] {
	const angleRad = (rotation * Math.PI) / 180;
	const normalX = Math.cos(angleRad);
	const normalY = Math.sin(angleRad);

	const cx = bounds.cx + centerX * bounds.width;
	const cy = bounds.cy + centerY * bounds.height;

	const iconOffsetCanvas = LINE_HANDLE_OFFSET_SCREEN_PX / displayScale;
	const featherOffset = iconOffsetCanvas + feather * FEATHER_HANDLE_SCALE;

	return [
		{
			id: "rotation",
			x: cx + normalX * iconOffsetCanvas,
			y: cy + normalY * iconOffsetCanvas,
			cursor: CURSOR.rotate,
			kind: "icon",
			icon: "rotate",
		},
		{
			id: "feather",
			x: cx - normalX * featherOffset,
			y: cy - normalY * featherOffset,
			cursor: CURSOR.resizeHorizontal,
			kind: "icon",
			icon: "feather",
		},
	];
}

function rotatePoint({
	localX,
	localY,
	cx,
	cy,
	angleRad,
}: {
	localX: number;
	localY: number;
	cx: number;
	cy: number;
	angleRad: number;
}): { x: number; y: number } {
	const cos = Math.cos(angleRad);
	const sin = Math.sin(angleRad);
	return {
		x: cx + localX * cos - localY * sin,
		y: cy + localX * sin + localY * cos,
	};
}

export function getBoxMaskHandlePositions({
	centerX,
	centerY,
	width,
	height,
	rotation,
	feather,
	sizeMode,
	showScaleHandle = true,
	bounds,
	displayScale,
}: {
	centerX: number;
	centerY: number;
	width: number;
	height: number;
	rotation: number;
	feather: number;
	sizeMode: MaskFeatures["sizeMode"];
	showScaleHandle?: boolean;
	bounds: ElementBounds;
	displayScale: number;
}): MaskHandlePosition[] {
	const cx = bounds.cx + centerX * bounds.width;
	const cy = bounds.cy + centerY * bounds.height;
	const angleRad = (rotation * Math.PI) / 180;
	const halfWidth = (width * bounds.width) / 2;
	const halfHeight = (height * bounds.height) / 2;

	const handles: MaskHandlePosition[] = [];
	const handleOffsetCanvas = BOX_HANDLE_OFFSET_SCREEN_PX / displayScale;

	const rotHandle = rotatePoint({
		localX: 0,
		localY: -halfHeight - handleOffsetCanvas,
		cx,
		cy,
		angleRad,
	});
	handles.push({
		id: "rotation",
		x: rotHandle.x,
		y: rotHandle.y,
		cursor: CURSOR.rotate,
		kind: "icon",
		icon: "rotate",
	});

	const featherHandle = rotatePoint({
		localX: 0,
		localY: halfHeight + handleOffsetCanvas + feather * FEATHER_HANDLE_SCALE,
		cx,
		cy,
		angleRad,
	});
	handles.push({
		id: "feather",
		x: featherHandle.x,
		y: featherHandle.y,
		cursor: CURSOR.resizeVertical,
		kind: "icon",
		icon: "feather",
	});

	if (sizeMode === "width-height") {
		const corners = [
			{ localX: -halfWidth, localY: -halfHeight, id: "top-left" },
			{ localX: halfWidth, localY: -halfHeight, id: "top-right" },
			{ localX: halfWidth, localY: halfHeight, id: "bottom-right" },
			{ localX: -halfWidth, localY: halfHeight, id: "bottom-left" },
		];
		for (const { localX, localY, id } of corners) {
			const point = rotatePoint({ localX, localY, cx, cy, angleRad });
			handles.push({
				id,
				x: point.x,
				y: point.y,
				cursor: CURSOR.resizeDiagonal,
				kind: "corner",
			});
		}
		const right = rotatePoint({
			localX: halfWidth,
			localY: 0,
			cx,
			cy,
			angleRad,
		});
		const left = rotatePoint({
			localX: -halfWidth,
			localY: 0,
			cx,
			cy,
			angleRad,
		});
		const bottom = rotatePoint({
			localX: 0,
			localY: halfHeight,
			cx,
			cy,
			angleRad,
		});
		handles.push({
			id: "left",
			x: left.x,
			y: left.y,
			cursor: CURSOR.resizeHorizontal,
			kind: "edge",
			edgeAxis: "horizontal",
			rotation,
		});
		handles.push({
			id: "right",
			x: right.x,
			y: right.y,
			cursor: CURSOR.resizeHorizontal,
			kind: "edge",
			edgeAxis: "horizontal",
			rotation,
		});
		handles.push({
			id: "bottom",
			x: bottom.x,
			y: bottom.y,
			cursor: CURSOR.resizeVertical,
			kind: "edge",
			edgeAxis: "vertical",
			rotation,
		});
	} else if (sizeMode === "height-only") {
		const top = rotatePoint({
			localX: 0,
			localY: -halfHeight,
			cx,
			cy,
			angleRad,
		});
		const bottom = rotatePoint({
			localX: 0,
			localY: halfHeight,
			cx,
			cy,
			angleRad,
		});
		handles.push({
			id: "top",
			x: top.x,
			y: top.y,
			cursor: CURSOR.resizeVertical,
			kind: "edge",
			edgeAxis: "vertical",
			rotation,
		});
		handles.push({
			id: "bottom",
			x: bottom.x,
			y: bottom.y,
			cursor: CURSOR.resizeVertical,
			kind: "edge",
			edgeAxis: "vertical",
			rotation,
		});
	} else if (sizeMode === "width-only") {
		const left = rotatePoint({
			localX: -halfWidth,
			localY: 0,
			cx,
			cy,
			angleRad,
		});
		const right = rotatePoint({
			localX: halfWidth,
			localY: 0,
			cx,
			cy,
			angleRad,
		});
		handles.push({
			id: "left",
			x: left.x,
			y: left.y,
			cursor: CURSOR.resizeHorizontal,
			kind: "edge",
			edgeAxis: "horizontal",
			rotation,
		});
		handles.push({
			id: "right",
			x: right.x,
			y: right.y,
			cursor: CURSOR.resizeHorizontal,
			kind: "edge",
			edgeAxis: "horizontal",
			rotation,
		});
	} else if (sizeMode === "uniform" && showScaleHandle) {
		const point = rotatePoint({
			localX: halfWidth,
			localY: halfHeight,
			cx,
			cy,
			angleRad,
		});
		handles.push({
			id: "scale",
			x: point.x,
			y: point.y,
			cursor: CURSOR.resizeDiagonal,
			kind: "corner",
		});
	}

	return handles;
}

export function getBoxMaskRectOverlay({
	centerX,
	centerY,
	width,
	height,
	rotation,
	bounds,
	handleId = "position",
	cursor = "move",
	dashed = false,
}: {
	centerX: number;
	centerY: number;
	width: number;
	height: number;
	rotation: number;
	bounds: ElementBounds;
	handleId?: string;
	cursor?: string;
	dashed?: boolean;
}): MaskRectOverlay {
	return {
		id: "bounding-box",
		type: "rect",
		center: {
			x: bounds.cx + centerX * bounds.width,
			y: bounds.cy + centerY * bounds.height,
		},
		width: width * bounds.width,
		height: height * bounds.height,
		rotation,
		handleId,
		cursor,
		dashed,
	};
}

export function getBoxMaskShapeOverlay({
	centerX,
	centerY,
	width,
	height,
	rotation,
	bounds,
	pathData,
	handleId = "position",
	cursor = "move",
}: {
	centerX: number;
	centerY: number;
	width: number;
	height: number;
	rotation: number;
	bounds: ElementBounds;
	pathData: string;
	handleId?: string;
	cursor?: string;
}): MaskShapeOverlay {
	return {
		id: "shape-outline",
		type: "shape",
		center: {
			x: bounds.cx + centerX * bounds.width,
			y: bounds.cy + centerY * bounds.height,
		},
		width: width * bounds.width,
		height: height * bounds.height,
		rotation,
		pathData,
		handleId,
		cursor,
	};
}

export function getBoxMaskOverlays({
	params,
	bounds,
	pathData,
	showBoundingBox = true,
}: {
	params: Pick<
		RectangleMaskParams,
		"centerX" | "centerY" | "width" | "height" | "rotation"
	>;
	bounds: ElementBounds;
	pathData?: string;
	showBoundingBox?: boolean;
}): MaskOverlay[] {
	const overlays: MaskOverlay[] = [];
	if (showBoundingBox) {
		overlays.push(
			getBoxMaskRectOverlay({
				centerX: params.centerX,
				centerY: params.centerY,
				width: params.width,
				height: params.height,
				rotation: params.rotation,
				bounds,
				dashed: Boolean(pathData),
			}),
		);
	}

	if (pathData) {
		overlays.push(
			getBoxMaskShapeOverlay({
				centerX: params.centerX,
				centerY: params.centerY,
				width: params.width,
				height: params.height,
				rotation: params.rotation,
				bounds,
				pathData,
			}),
		);
	}

	return overlays;
}
