import React, { useEffect, useMemo } from 'react';
import {
  ReactFlow,
  Background,
  Panel,
  SelectionMode,
  ConnectionLineType,
  Node,
  Edge,
  OnNodesChange,
  OnEdgesChange,
  OnConnect,
  OnReconnect
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import CustomEdge from './components/customEdge';
import CustomConnectionLine from './components/customConnectionLine';
import NodeContextMenu from './components/nodeContextMenu';
import EdgeContextMenu from './components/edgeContextMenu';
import PaneContextMenu from './components/paneContextMenu';
import NodeEditModal from './components/nodeEditModal';
import AddNodeMenu from './components/addNodeMenu';
import ActionBar from './components/actionBar';
import { useAlignmentGuidelines } from '@/hooks/useAlignmentGuidelines';
import { useHistory } from './components/historyContext';
import { NodeTypes } from '@xyflow/react';

const edgeTypes = {
  custom: CustomEdge
};

interface FlowEditorMainProps {
  nodes: Node[];
  edges: Edge[];
  nodeTypes: NodeTypes;
  setNodes: React.Dispatch<React.SetStateAction<Node[]>>;
  setEdges: React.Dispatch<React.SetStateAction<Edge[]>>;
  reactFlowInstance: any;
  reactFlowWrapper: React.RefObject<HTMLDivElement>;
  menu: any;
  setMenu: React.Dispatch<React.SetStateAction<any>>;
  editingNode: Node | null;
  setEditingNode: React.Dispatch<React.SetStateAction<Node | null>>;
  isEditModalOpen: boolean;
  setIsEditModalOpen: React.Dispatch<React.SetStateAction<boolean>>;
  isDelete: boolean;
  setIsDelete: React.Dispatch<React.SetStateAction<boolean>>;
  edgeForNodeAdd: Edge | null;
  setEdgeForNodeAdd: React.Dispatch<React.SetStateAction<Edge | null>>;
  positionForNodeAdd: { x: number, y: number } | null;
  setPositionForNodeAdd: React.Dispatch<React.SetStateAction<{ x: number, y: number } | null>>;
  isRunning: boolean;
  setIsRunning: React.Dispatch<React.SetStateAction<boolean>>;
  initialData: any;
  canvasDataMap: any;

  // Callbacks
  onNodesChange: OnNodesChange;
  onEdgesChange: OnEdgesChange;
  onConnect: OnConnect;
  onReconnect: OnReconnect;
  onDragOver: (event: React.DragEvent) => void;
  onDrop: (event: React.DragEvent) => void;
  onNodeDrag: (event: React.MouseEvent, node: Node) => void;
  onNodeDragStop: () => void;
  onNodeContextMenu: (event: React.MouseEvent, node: Node) => void;
  onNodeDoubleClick: (event: React.MouseEvent, node: Node) => void;
  onEdgeContextMenu: (event: React.MouseEvent, edge: Edge) => void;
  onPaneContextMenu: (event: React.MouseEvent) => void;
  onPaneClick: () => void;
  closeEditModal: () => void;
  saveNodeEdit: (updatedData: any) => void;
  deleteNode: (node: Node) => void;
  deleteEdge: (edge: Edge) => void;
  editNode: (node: Node) => void;
  editEdge: (edge: Edge) => void;
  copyNode: (node: Node) => void;
  addNodeOnEdge: (nodeType: string, node: any) => void;
  addNodeOnPane: (nodeType: string, position: { x: number, y: number }, node?: any) => void;
  handleAddNode: (nodeType: string, node: any) => void;
  saveFlowDataToServer: () => void;
  handleRun: (running: boolean) => void;
}

const FlowEditorMain: React.FC<FlowEditorMainProps> = (props) => {
  const {
    nodes,
    edges,
    nodeTypes,
    setNodes,
    setEdges,
    reactFlowInstance,
    reactFlowWrapper,
    menu,
    setMenu,
    editingNode,
    setEditingNode,
    isEditModalOpen,
    setIsEditModalOpen,
    isDelete,
    setIsDelete,
    edgeForNodeAdd,
    setEdgeForNodeAdd,
    positionForNodeAdd,
    setPositionForNodeAdd,
    isRunning,
    initialData,
    canvasDataMap,
    onNodesChange,
    onEdgesChange,
    onConnect,
    onReconnect,
    onDragOver,
    onDrop,
    onNodeDrag,
    onNodeDragStop,
    onNodeContextMenu,
    onNodeDoubleClick,
    onEdgeContextMenu,
    onPaneContextMenu,
    onPaneClick,
    closeEditModal,
    saveNodeEdit,
    deleteNode,
    deleteEdge,
    editNode,
    editEdge,
    copyNode,
    addNodeOnEdge,
    addNodeOnPane,
    handleAddNode,
    saveFlowDataToServer,
    handleRun
  } = props;

  const { getGuidelines, clearGuidelines, AlignmentGuides } = useAlignmentGuidelines();
  const { undo, redo, canUndo, canRedo } = useHistory();
  const reactFlowId = useMemo(() => new Date().getTime().toString(), []);

  // 监听键盘事件实现快捷键
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      // Ctrl+Z 撤销
      if (e.ctrlKey && e.key === 'z' && !e.shiftKey && canUndo) {
        e.preventDefault();
        undo();
      }
      // Ctrl+Shift+Z 重做
      if (e.ctrlKey && e.shiftKey && e.key === 'Z' && canRedo) {
        e.preventDefault();
        redo();
      }
      // Ctrl+Y 重做
      if (e.ctrlKey && e.key === 'y' && canRedo) {
        e.preventDefault();
        redo();
      }
    };

    document.addEventListener('keydown', handleKeyDown);
    return () => {
      document.removeEventListener('keydown', handleKeyDown);
    };
  }, [undo, redo, canUndo, canRedo]);

  // 监听节点和边的变化以拍摄快照
  useEffect(() => {
    // 获取 HistoryProvider 中的 takeSnapshot 方法
    const event = new CustomEvent('takeSnapshot', {
      detail: { nodes: [...nodes], edges: [...edges] }
    });
    document.dispatchEvent(event);
  }, [nodes, edges]);

  return (
    <div ref={reactFlowWrapper} style={{ width: '100%', height: '100%', position: 'relative' }}
         onContextMenu={(e) => e.preventDefault()}>
      <ReactFlow
        id={reactFlowId}
        nodes={nodes}
        edges={edges}
        nodeTypes={nodeTypes}
        edgeTypes={edgeTypes}
        snapToGrid={true}
        snapGrid={[2, 2]}
        onNodesDelete={(deleted) => {
          setNodes((nds) => nds.filter((n) => !deleted.find((d) => d.id === n.id)));
          setIsEditModalOpen(false);
        }}
        onNodesChange={onNodesChange}
        onEdgesChange={onEdgesChange}
        onConnect={onConnect}
        onReconnect={onReconnect}
        onDrop={onDrop}
        onDragOver={onDragOver}
        onNodeDrag={onNodeDrag}
        connectionLineType={ConnectionLineType.SmoothStep}
        connectionLineComponent={CustomConnectionLine}
        onNodeDragStop={onNodeDragStop}
        onNodeContextMenu={onNodeContextMenu}
        onEdgeContextMenu={onEdgeContextMenu}
        onNodeClick={onNodeDoubleClick}
        onPaneClick={onPaneClick}
        onPaneContextMenu={onPaneContextMenu}
        onEdgeMouseEnter={(_event, edge) => {
          setEdges((eds) => eds.map(e => {
            if (e.id === edge.id) {
              return { ...e, data: { ...e.data, hovered: true } };
            }
            return e;
          }));
        }}
        onEdgeMouseLeave={(_event, edge) => {
          setEdges((eds) => eds.map(e => {
            if (e.id === edge.id) {
              return { ...e, data: { ...e.data, hovered: false } };
            }
            return e;
          }));
        }}
        fitView
        selectionKeyCode={['Meta', 'Control']}
        selectionMode={SelectionMode.Partial}
        panOnDrag={[0, 1, 2]} // 支持多点触控平移
        zoomOnScroll={true}
        zoomOnPinch={true}
        panOnScrollSpeed={0.5}
      >
        <Background />
        <Panel position="top-left">
          <ActionBar
            onSave={saveFlowDataToServer}
            onUndo={undo}
            onRedo={redo}
            canUndo={canUndo}
            canRedo={canRedo}
            onRun={handleRun}
            isRunning={isRunning}
          ></ActionBar>
        </Panel>
        <AlignmentGuides />
      </ReactFlow>

      {/*节点右键上下文*/}
      {menu && menu.type === 'node' && (
        <div
          style={{
            position: 'absolute',
            top: menu.top,
            left: menu.left,
            zIndex: 1000
          }}
        >
          <NodeContextMenu
            node={nodes.find(n => n.id === menu.id)!}
            onDelete={deleteNode}
            onEdit={editNode}
            onCopy={copyNode}
            onCloseMenu={setMenu}
            onCloseOpenModal={setIsEditModalOpen}
          />
        </div>
      )}

      {/*边右键上下文*/}
      {menu && menu.type === 'edge' && (
        <div
          style={{
            position: 'absolute',
            top: menu.top,
            left: menu.left,
            zIndex: 1000
          }}
        >
          <EdgeContextMenu
            edge={edges.find(e => e.id === menu.id)!}
            onDelete={deleteEdge}
            onEdit={editEdge}
            onAddNode={(edge) => {
              setEdgeForNodeAdd(edge);
              setIsEditModalOpen(false);
              setMenu(null); // 关闭上下文菜单
            }}
          />
        </div>
      )}

      {/*画布右键上下文*/}
      {menu && menu.type === 'pane' && (
        <div
          style={{
            position: 'absolute',
            top: menu.top,
            left: menu.left,
            zIndex: 1000
          }}
        >
          <PaneContextMenu
            position={menu.position!}
            onAddNode={(nodeType: string, position: { x: number, y: number }, node: any) => {
              addNodeOnPane(nodeType, position, node);
              setIsEditModalOpen(false);
              setMenu(null); // 关闭上下文菜单
            }}
          />
        </div>
      )}

      {/*节点点击/节点编辑上下文*/}
      <NodeEditModal
        popupContainer={reactFlowWrapper}
        node={editingNode}
        isOpen={isEditModalOpen}
        isDelete={isDelete}
        onSave={saveNodeEdit}
        onClose={closeEditModal}
      />

      {/*统一的添加节点菜单*/}
      {(edgeForNodeAdd || positionForNodeAdd) && (
        <div
          style={{
            position: 'absolute',
            top: edgeForNodeAdd ? (edgeForNodeAdd.data?.y as number || 0) : (positionForNodeAdd?.y || 0),
            left: edgeForNodeAdd ? ((edgeForNodeAdd.data?.x as number || 0) + 20) : (positionForNodeAdd?.x || 0),
            zIndex: 1000,
            transform: 'none'
          }}
        >
          <AddNodeMenu
            onAddNode={(nodeType, node) => {
              handleAddNode(nodeType, node);
              // 关闭菜单
              setEdgeForNodeAdd(null);
              setPositionForNodeAdd(null);
            }}
            position={positionForNodeAdd || undefined}
            edgeId={edgeForNodeAdd?.id}
          />
        </div>
      )}
    </div>
  );
};

export default FlowEditorMain;