import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { addEdge, ReactFlow, Background, Controls, Edge, Node, ReactFlowProvider, useEdgesState, useNodesState, MiniMap, Panel, BackgroundVariant, ControlButton, applyNodeChanges, applyEdgeChanges, SelectionMode, OnNodesChange, OnEdgesChange, useReactFlow, useOnSelectionChange, useNodesInitialized } from '@xyflow/react';
import { Button } from '../../element/Button';
import '@xyflow/react/dist/style.css';
import { edgeTypes, GraphState, nodeTypes } from './types';
import useGraphStore from './store';
import { shallow } from 'zustand/shallow';
import { useKeyboardCtrl } from './useKeyboardCtrl';
import { getMindMapLayout } from './layout';




const selector = (store: GraphState) => ({
    nodes: store.present.nodes,
    edges: store.present.edges,
    setNodes: store.setNodes,
    setEdges: store.setEdges,
    record: store.record,
    onNodesChange: store.onNodesChange,
    onEdgesChange: store.onEdgesChange,
});

const panOnDrag = [1, 2];

const Flow: React.FC = () => {

    const store = useGraphStore(selector, shallow);
    useKeyboardCtrl()
    const nodesInitialized = useNodesInitialized();
    const onLayout = useCallback(async () => {
        const layouted = getMindMapLayout({ nodes: store.nodes, edges: store.edges })
        store.setNodes(layouted.nodes)
        store.setEdges(layouted.edges)
    }, [store.nodes, store.edges]);
    useEffect(() => {
        if (nodesInitialized && store.nodes.length) {
            console.log('layout')
            onLayout()
        }
    }, [nodesInitialized, store.nodes.length]);

    return (
        <ReactFlow
            nodesDraggable={true}
            nodes={store.nodes}
            edges={store.edges}

            onNodesChange={(changes) => {
                const recordTypes = new Set(['remove', 'select']);
                const undoChanges = changes.filter(change => recordTypes.has(change.type))
                const otherChanges = changes.filter(change => !recordTypes.has(change.type))
                if (undoChanges.length)
                    store.record(() => {
                        store.onNodesChange(undoChanges);
                    });
                store.onNodesChange(otherChanges);
            }}
            onEdgesChange={(changes) => {
                const recordTypes = new Set(['remove', 'select']);
                changes.forEach((change) => {
                    if (recordTypes.has(change.type)) {
                        store.record(() => {
                            store.onEdgesChange([change]);
                        });
                    } else {
                        store.onEdgesChange([change]);
                    }
                });
            }}
            selectionOnDrag
            panOnDrag={panOnDrag}
            nodeTypes={nodeTypes}
            edgeTypes={edgeTypes}
            selectionMode={SelectionMode.Partial}
            fitView
            minZoom={0.001}
            maxZoom={1000}
        >
            <Panel position="top-right">
                <div className='flex items-center gap-4'>
                    <Button onClick={onLayout}>自动布局</Button>
                    <span>节点个数{store.nodes.length}</span>
                    <span>边条数{store.edges.length}</span>
                </div>

            </Panel>
            <Background variant={BackgroundVariant.Dots} />
            <Controls >
                <ControlButton>测试</ControlButton>
            </Controls>
            <MiniMap pannable zoomable nodeStrokeWidth={3} position='bottom-right'></MiniMap>
        </ReactFlow>
    );
};

const GraphEditor: React.FC = () => {
    return (
        <ReactFlowProvider>
            <Flow></Flow>
        </ReactFlowProvider>
    );
};

export default GraphEditor;