/**
 * Layout hooks for viewport manipulation.
 *
 * Provides fit-to-bounds, graph bounds calculation, and layout utilities.
 * The core fitToBounds logic lives in viewport-store.ts (headless atom).
 */

import { useAtomValue, useSetAtom } from 'jotai';

import { graphAtom } from '../core/graph-store';
import { nodePositionUpdateCounterAtom } from '../core/graph-position';
import { uiNodesAtom } from '../core/graph-derived';
import { fitToBoundsAtom } from '../core/viewport-store';
import { selectedNodeIdsAtom } from '../core/selection-store';
import { calculateBounds, FitToBoundsMode, type Rect } from '../utils/layout';

// Re-export for convenience
export { FitToBoundsMode } from '../utils/layout';
export type { Rect } from '../utils/layout';

export const useGetGraphBounds = () => {
	const graph = useAtomValue(graphAtom);
	useAtomValue(nodePositionUpdateCounterAtom);

	const nodes: Rect[] = graph.nodes().map((node) => {
		const nodeAttributes = graph.getNodeAttributes(node);
		return {
			x: nodeAttributes.x,
			y: nodeAttributes.y,
			width: nodeAttributes.width || 500,
			height: nodeAttributes.height || 500,
		};
	});

	const bounds = calculateBounds(nodes);
	return { bounds, nodes };
};

export const useSelectionBounds = () => {
	const selectedNodeIds = useAtomValue(selectedNodeIdsAtom);
	const nodes = useAtomValue(uiNodesAtom);

	const selectedNodes = nodes
		.filter((node) => selectedNodeIds.has(node.id))
		.map((node) => ({
			x: node.position.x,
			y: node.position.y,
			width: node.width ?? 500,
			height: node.height ?? 500,
		}));
	return calculateBounds(selectedNodes);
};

/**
 * Hook to fit the viewport to show specific bounds.
 * Delegates to fitToBoundsAtom (headless, no React required).
 */
export const useFitToBounds = () => {
	const setFitToBounds = useSetAtom(fitToBoundsAtom);

	const fitToBounds = (mode: FitToBoundsMode | 'graph' | 'selection', padding: number = 20) => {
		setFitToBounds({ mode, padding });
	};

	return { fitToBounds };
};

/**
 * Combined layout hook providing all layout utilities.
 *
 * @returns Object with fitToBounds and graph bounds utilities
 *
 * @example
 * const { fitToBounds, graphBounds, selectionBounds } = useLayout();
 *
 * // After modifying nodes:
 * fitToBounds(FitToBoundsMode.Graph, 50);
 */
export const useLayout = () => {
	const { fitToBounds } = useFitToBounds();
	const { bounds: graphBounds, nodes: graphNodes } = useGetGraphBounds();
	const selectionBounds = useSelectionBounds();

	return {
		fitToBounds,
		graphBounds,
		graphNodes,
		selectionBounds,
	};
};
