import React, { useCallback, useEffect } from 'react';
import ReactFlow, {
    addEdge,
    useNodesState,
    useEdgesState,
    Background,
    Controls,
    ReactFlowProvider
} from 'reactflow';
import 'reactflow/dist/style.css';
import dagre from 'dagre'; // Импортируем библиотеку dagre

// Инициализируем объект Dagre Graph
const dagreGraph = new dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));

// Определяем размеры узлов для корректного расположения
const nodeWidth = 172; // Ширина узла, может потребоваться корректировка
const nodeHeight = 36; // Высота узла, может потребоваться корректировка

/**
 * Применяет алгоритм расположения Dagre к узлам и рёбрам графа.
 * @param {Array} nodes Массив узлов React Flow.
 * @param {Array} edges Массив рёбер React Flow.
 * @param {string} direction Направление графа ('TB' - сверху вниз, 'LR' - слева направо).
 * @returns {Object} Объект с обновлёнными узлами и рёбрами, содержащими позиции.
 */
const getLayoutedElements = (nodes, edges, direction = 'TB') => {
    const isHorizontal = direction === 'LR'; // Проверяем, горизонтальное ли расположение
    dagreGraph.setGraph({ rankdir: direction }); // Устанавливаем направление графа

    // Добавляем узлы в граф Dagre с их размерами
    nodes.forEach((node) => {
        dagreGraph.setNode(node.id, { width: nodeWidth, height: nodeHeight });
    });

    // Добавляем рёбра в граф Dagre
    edges.forEach((edge) => {
        dagreGraph.setEdge(edge.source, edge.target);
    });

    // Выполняем расчёт расположения графа
    dagre.layout(dagreGraph);

    // Обновляем позиции узлов React Flow на основе расчётов Dagre
    const newNodes = nodes.map((node) => {
        const nodeWithPosition = dagreGraph.node(node.id); // Получаем данные узла из Dagre
        // Смещаем позицию узла Dagre (якорь в центре) к верхнему левому углу,
        // чтобы она соответствовала точке привязки узла React Flow (верхний левый угол).
        return {
            ...node,
            targetPosition: isHorizontal ? 'left' : 'top',
            sourcePosition: isHorizontal ? 'right' : 'bottom',
            position: {
                x: nodeWithPosition.x - nodeWidth / 2,
                y: nodeWithPosition.y - nodeHeight / 2,
            },
        };
    });

    return { nodes: newNodes, edges }; // Возвращаем обновлённые узлы и рёбра
};

const GraphPanel = ({ graphData, onNodeClick }) => {
    // Инициализируем состояния узлов и рёбер пустыми массивами
    const [nodes, setNodes, onNodesChange] = useNodesState([]);
    const [edges, setEdges, onEdgesChange] = useEdgesState([]);

    // Используем useEffect для применения Dagre layout при изменении данных графа
    useEffect(() => {
        // Проверяем, есть ли данные для построения графа
        if (graphData.nodes.length > 0 || graphData.edges.length > 0) {
            console.log("Applying Dagre layout with data:", graphData);

            // Преобразуем входящие данные в формат, необходимый для Dagre и React Flow
            const initialNodesForLayout = graphData.nodes.map(node => ({
                id: node.id,
                data: { label: node.data.label },
                position: { x: 0, y: 0 } // Временная позиция, будет перезаписана Dagre
            }));
            const initialEdgesForLayout = graphData.edges.map(edge => ({
                id: edge.id,
                source: edge.source,
                target: edge.target,
            }));

            // Применяем Dagre layout
            const { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(
                initialNodesForLayout,
                initialEdgesForLayout
            );

            // Обновляем состояния узлов и рёбер React Flow
            setNodes(layoutedNodes);
            setEdges(layoutedEdges);
        } else {
            // Если данных нет, очищаем граф
            setNodes([]);
            setEdges([]);
        }
    }, [graphData.nodes, graphData.edges, setNodes, setEdges]); // Зависимости: изменения в узлах и рёбрах графа

    const onConnect = useCallback(
        (params) => setEdges((eds) => addEdge(params, eds)),
        [setEdges]
    );

    const nodeClickHandler = useCallback((event, node) => {
        onNodeClick(node.id);
    }, [onNodeClick]);

    return (
        <div className="graph-panel">
            <ReactFlowProvider>
                <ReactFlow
                    nodes={nodes}
                    edges={edges}
                    onNodesChange={onNodesChange}
                    onEdgesChange={onEdgesChange}
                    onConnect={onConnect}
                    onNodeClick={nodeClickHandler}
                    fitView // Автоматически центрирует и масштабирует граф
                    attributionPosition="top-right"
                >
                    <Controls /> {/* Добавляем элементы управления */}
                    <Background variant="dots" gap={12} size={1} /> {/* Добавляем фон */}
                </ReactFlow>
            </ReactFlowProvider>
        </div>
    );
};

export default GraphPanel;