import { getIncomers } from "../../xyflow/react.js";
import { stratify, tree } from "d3-hierarchy";
const getPosition = (x, y, direction)=>{
    switch(direction){
        case 'TD':
            return {
                x,
                y
            };
        case 'LR':
            return {
                x: y,
                y: x
            };
        case 'BT':
            return {
                x: -x,
                y: -y
            };
        case 'RL':
            return {
                x: -y,
                y: x
            };
    }
};
const layout = tree().separation(()=>1);
const rootNode = {
    id: 'd3-hierarchy-root',
    x: 0,
    y: 0,
    position: {
        x: 0,
        y: 0
    },
    data: {}
};
const DEFAULT_NODE_WIDTH = 200;
const DEFAULT_NODE_HEIGHT = 100;
const d3HierarchyLayout = (nodes, edges, options)=>Promise.resolve((()=>{
        const isHorizontal = 'RL' === options.direction || 'LR' === options.direction;
        const initialNodes = [];
        let maxNodeWidth = 0;
        let maxNodeHeight = 0;
        for (const node of nodes){
            const nodeWithPosition = {
                ...node,
                ...node.position
            };
            initialNodes.push(nodeWithPosition);
            const nodeWidth = node.measured?.width ?? DEFAULT_NODE_WIDTH;
            const nodeHeight = node.measured?.height ?? DEFAULT_NODE_HEIGHT;
            maxNodeWidth = Math.max(maxNodeWidth, nodeWidth);
            maxNodeHeight = Math.max(maxNodeHeight, nodeHeight);
        }
        const nodeSize = isHorizontal ? [
            maxNodeHeight + options.spacing[1],
            maxNodeWidth + options.spacing[0]
        ] : [
            maxNodeWidth + options.spacing[0],
            maxNodeHeight + options.spacing[1]
        ];
        layout.nodeSize(nodeSize);
        const getParentId = (node)=>{
            if (node.id === rootNode.id) return;
            const incomers = getIncomers(node, nodes, edges);
            return incomers[0]?.id || rootNode.id;
        };
        const hierarchy = stratify().id((d)=>d.id).parentId(getParentId)([
            rootNode,
            ...initialNodes
        ]);
        const root = layout(hierarchy);
        const layoutNodes = new Map();
        for (const node of root)if (node.id) layoutNodes.set(node.id, node);
        const nextNodes = nodes.map((node)=>{
            const layoutNode = layoutNodes.get(node.id);
            if (!layoutNode) throw new Error(`Layout node not found for ${node.id}`);
            const { x, y } = layoutNode;
            const position = getPosition(x, y, options.direction);
            const nodeWidth = node.measured?.width ?? DEFAULT_NODE_WIDTH;
            const nodeHeight = node.measured?.height ?? DEFAULT_NODE_HEIGHT;
            const offsetPosition = {
                x: position.x - nodeWidth / 2,
                y: position.y - nodeHeight / 2
            };
            return {
                ...node,
                position: offsetPosition
            };
        });
        return {
            nodes: nextNodes,
            edges
        };
    })());
export { d3HierarchyLayout };
