/**
 * Layout utilities for canvas operations.
 *
 * Provides geometry calculations, bounds computation, and node overlap detection.
 */

// ============================================================
// Types
// ============================================================

/**
 * Rectangle with position and dimensions
 */
export interface Rect {
	x: number;
	y: number;
	width: number;
	height: number;
}

/**
 * Node with position and dimensions (alias for geometry functions)
 */
export interface NodeWithDimensions {
	x: number;
	y: number;
	width: number;
	height: number;
}

/**
 * Extended bounds with computed edges
 */
export interface NodeBounds {
	x: number;
	y: number;
	width: number;
	height: number;
	left: number;
	right: number;
	top: number;
	bottom: number;
}

/**
 * Mode for fitToBounds operation
 */
export enum FitToBoundsMode {
	/** Fit all nodes in the graph */
	Graph = 'graph',
	/** Fit only selected nodes */
	Selection = 'selection',
}

// ============================================================
// Bounds Calculation
// ============================================================

/**
 * Calculate the bounding rectangle that contains all nodes.
 *
 * @param nodes - Array of rectangles (nodes with x, y, width, height)
 * @returns Bounding rectangle containing all nodes
 *
 * @example
 * const bounds = calculateBounds([
 *   { x: 0, y: 0, width: 100, height: 100 },
 *   { x: 200, y: 150, width: 100, height: 100 },
 * ]);
 * // bounds = { x: 0, y: 0, width: 300, height: 250 }
 */
export const calculateBounds = (nodes: Rect[]): Rect => {
	if (nodes.length === 0) {
		return { x: 0, y: 0, width: 0, height: 0 };
	}
	const minX = Math.min(...nodes.map((node) => node.x));
	const minY = Math.min(...nodes.map((node) => node.y));
	const maxX = Math.max(...nodes.map((node) => node.x + node.width));
	const maxY = Math.max(...nodes.map((node) => node.y + node.height));

	return {
		x: minX,
		y: minY,
		width: maxX - minX,
		height: maxY - minY,
	};
};

// ============================================================
// Node Geometry
// ============================================================

/**
 * Get the center point of a node.
 */
export function getNodeCenter(node: NodeWithDimensions): { x: number; y: number } {
	return {
		x: node.x + node.width / 2,
		y: node.y + node.height / 2,
	};
}

/**
 * Set a node's position based on center coordinates.
 * Returns a new node object with updated position.
 */
export function setNodeCenter<T extends NodeWithDimensions>(node: T, centerX: number, centerY: number): T {
	return {
		...node,
		x: centerX - node.width / 2,
		y: centerY - node.height / 2,
	};
}

/**
 * Check if two nodes overlap.
 */
export function checkNodesOverlap(node1: NodeWithDimensions, node2: NodeWithDimensions): boolean {
	const center1 = getNodeCenter(node1);
	const center2 = getNodeCenter(node2);

	const dx = Math.abs(center1.x - center2.x);
	const dy = Math.abs(center1.y - center2.y);

	const minDistanceX = (node1.width + node2.width) / 2;
	const minDistanceY = (node1.height + node2.height) / 2;

	return dx < minDistanceX && dy < minDistanceY;
}

/**
 * Get the bounding box of a node.
 */
export function getNodeBounds(node: NodeWithDimensions): NodeBounds {
	return {
		x: node.x,
		y: node.y,
		width: node.width,
		height: node.height,
		left: node.x,
		right: node.x + node.width,
		top: node.y,
		bottom: node.y + node.height,
	};
}

/**
 * Check if two nodes are within a certain distance of each other.
 */
export function areNodesClose(node1: NodeWithDimensions, node2: NodeWithDimensions, threshold: number = 200): boolean {
	const center1 = getNodeCenter(node1);
	const center2 = getNodeCenter(node2);

	const distance = Math.sqrt(Math.pow(center1.x - center2.x, 2) + Math.pow(center1.y - center2.y, 2));

	return distance <= threshold;
}
