import React, { useState, useCallback, useRef, useEffect } from 'react';
import {
  ReactFlow,
  applyNodeChanges,
  applyEdgeChanges,
  addEdge,
  reconnectEdge,
  Background,
  Controls,
  Node,
  Edge,
  ReactFlowProvider,
  useReactFlow,
  EdgeTypes,
  SelectionMode,
  useStoreApi,
  Panel,
  ConnectionLineType
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import { Button, Modal } from '@arco-design/web-react';
import { nodeTypeMap, nodeTypes, registerNodeType } from './node';
import SideBar from './sideBar/sideBar';
import { convertFlowData } from '@/utils/convertFlowData';
import { exampleFlowData } from '@/pages/flowEditor/test/exampleFlowData';
import LocalNode from '@/pages/flowEditor/node/localNode/LocalNode';
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 { defaultNodeTypes } from '@/pages/flowEditor/node/types/defaultType';
import { localNodeData } from '@/pages/flowEditor/sideBar/config/localNodeData';
import { useAlignmentGuidelines } from '@/hooks/useAlignmentGuidelines';

const edgeTypes: EdgeTypes = {
  custom: CustomEdge
};

const FlowEditorWithProvider: React.FC = () => {
  return (
    <div style={{ width: '100%', height: '91vh', display: 'flex' }} onContextMenu={(e) => e.preventDefault()}>
      <ReactFlowProvider>
        {/*<SideBar />*/}
        <FlowEditor />
      </ReactFlowProvider>
    </div>
  );
};

const FlowEditor: React.FC = () => {
  const [nodes, setNodes] = useState<Node[]>([]);
  const [edges, setEdges] = useState<Edge[]>([]);
  const reactFlowInstance = useReactFlow();
  const reactFlowWrapper = useRef<HTMLDivElement>(null);
  const [menu, setMenu] = useState<{
    id: string;
    type: 'node' | 'edge' | 'pane';
    top: number;
    left: number;
    position?: { x: number; y: number };
  } | null>(null);
  const store = useStoreApi();

  // 添加编辑弹窗相关状态
  const [editingNode, setEditingNode] = useState<Node | null>(null);
  const [isEditModalOpen, setIsEditModalOpen] = useState(false);

  // 添加节点选择弹窗状态
  const [edgeForNodeAdd, setEdgeForNodeAdd] = useState<Edge | null>(null);
  const [positionForNodeAdd, setPositionForNodeAdd] = useState<{ x: number, y: number } | null>(null);

  const { getGuidelines, clearGuidelines, AlignmentGuides } = useAlignmentGuidelines();

  // 获取handle类型 (api或data)
  const getHandleType = (handleId: string, nodeParams: any) => {
    // 检查是否为api类型的handle
    const apiOuts = nodeParams.apiOuts || [];
    const apiIns = nodeParams.apiIns || [];

    if (apiOuts.some((api: any) => api.name === handleId) ||
      apiIns.some((api: any) => api.name === handleId)) {
      return 'api';
    }

    // 检查是否为data类型的handle
    const dataOuts = nodeParams.dataOuts || [];
    const dataIns = nodeParams.dataIns || [];

    if (dataOuts.some((data: any) => data.name === handleId) ||
      dataIns.some((data: any) => data.name === handleId)) {
      return 'data';
    }

    // 默认为data类型
    return 'data';
  };

  // 验证数据类型是否匹配
  const validateDataType = (sourceNode: defaultNodeTypes, targetNode: defaultNodeTypes, sourceHandleId: string, targetHandleId: string) => {
    const sourceParams = sourceNode.data?.parameters || {};
    const targetParams = targetNode.data?.parameters || {};

    // 获取源节点的输出参数
    let sourceDataType = '';
    const sourceApiOuts = sourceParams.apiOuts || [];
    const sourceDataOuts = sourceParams.dataOuts || [];

    // 查找源handle的数据类型
    const sourceApi = sourceApiOuts.find((api: any) => api.name === sourceHandleId);
    const sourceData = sourceDataOuts.find((data: any) => data.name === sourceHandleId);

    if (sourceApi) {
      sourceDataType = sourceApi.dataType || '';
    }
    else if (sourceData) {
      sourceDataType = sourceData.dataType || '';
    }

    // 获取目标节点的输入参数
    let targetDataType = '';
    const targetApiIns = targetParams.apiIns || [];
    const targetDataIns = targetParams.dataIns || [];

    // 查找目标handle的数据类型
    const targetApi = targetApiIns.find((api: any) => api.name === targetHandleId);
    const targetData = targetDataIns.find((data: any) => data.name === targetHandleId);

    if (targetApi) {
      targetDataType = targetApi.dataType || '';
    }
    else if (targetData) {
      targetDataType = targetData.dataType || '';
    }

    // 如果任一数据类型为空，则允许连接
    if (!sourceDataType || !targetDataType) {
      return true;
    }

    // 比较数据类型是否匹配
    return sourceDataType === targetDataType;
  };

  const onNodesChange = useCallback(
    (changes: any) => {
      const newNodes = applyNodeChanges(changes, nodes);
      setNodes(newNodes);
      // 如果需要在节点变化时执行某些操作，可以在这里添加
      onPaneClick();
    },
    [nodes]
  );

  const onEdgesChange = useCallback(
    (changes: any) => {
      const newEdges = applyEdgeChanges(changes, edges);
      setEdges(newEdges);
      // 如果需要在边变化时执行某些操作，可以在这里添加
      onPaneClick();
    },
    [edges]
  );

  const onConnect = useCallback(
    (params: any) => {
      // 获取源节点和目标节点
      const sourceNode = nodes.find(node => node.id === params.source);
      const targetNode = nodes.find(node => node.id === params.target);

      // 如果找不到节点，不创建连接
      if (!sourceNode || !targetNode) {
        return;
      }

      // 获取源节点和目标节点的参数信息
      const sourceParams = sourceNode.data?.parameters || {};
      const targetParams = targetNode.data?.parameters || {};

      // 获取源handle和目标handle的类型 (api或data)
      const sourceHandleType = getHandleType(params.sourceHandle, sourceParams);
      const targetHandleType = getHandleType(params.targetHandle, targetParams);

      // 验证连接类型是否匹配 (api只能连api, data只能连data)
      if (sourceHandleType !== targetHandleType) {
        console.warn('连接类型不匹配: ', sourceHandleType, targetHandleType);
        return;
      }

      // 验证数据类型是否匹配
      if (!validateDataType(sourceNode, targetNode, params.sourceHandle, params.targetHandle)) {
        console.warn('数据类型不匹配');
        return;
      }

      // TODO 目前是临时定义，存在事件数据的时候才展示
      // params.data = {
      //   displayData: {
      //     label: '测试',
      //     value: '数据展示'
      //   }
      // };

      // 如果验证通过，创建连接
      setEdges((edgesSnapshot) => addEdge({ ...params, type: 'custom' }, edgesSnapshot));
    },
    [nodes]
  );

  // 边重新连接处理
  const onReconnect = useCallback(
    (oldEdge: Edge, newConnection: any) => {
      // 获取源节点和目标节点
      const sourceNode = nodes.find(node => node.id === newConnection.source);
      const targetNode = nodes.find(node => node.id === newConnection.target);

      // 如果找不到节点，不创建连接
      if (!sourceNode || !targetNode) {
        return;
      }

      // 获取源节点和目标节点的参数信息
      const sourceParams = sourceNode.data?.parameters || {};
      const targetParams = targetNode.data?.parameters || {};

      // 获取源handle和目标handle的类型 (api或data)
      const sourceHandleType = getHandleType(newConnection.sourceHandle, sourceParams);
      const targetHandleType = getHandleType(newConnection.targetHandle, targetParams);

      // 验证连接类型是否匹配 (api只能连api, data只能连data)
      if (sourceHandleType !== targetHandleType) {
        console.warn('连接类型不匹配: ', sourceHandleType, targetHandleType);
        return;
      }

      // 验证数据类型是否匹配
      if (!validateDataType(sourceNode, targetNode, newConnection.sourceHandle, newConnection.targetHandle)) {
        console.warn('数据类型不匹配');
        return;
      }

      // 如果验证通过，重新连接
      setEdges((els) => reconnectEdge(oldEdge, newConnection, els));
    },
    [nodes]
  );

  const onDragOver = useCallback((event: React.DragEvent) => {
    event.preventDefault();
    event.dataTransfer.dropEffect = 'move';
  }, []);

  // 侧边栏节点实例
  const onDrop = useCallback(
    (event: React.DragEvent) => {
      event.preventDefault();

      if (!reactFlowInstance) return;

      const callBack = event.dataTransfer.getData('application/reactflow');
      const nodeData = JSON.parse(callBack);
      if (typeof nodeData.nodeType === 'undefined' || !nodeData.nodeType) {
        return;
      }

      const position = reactFlowInstance.screenToFlowPosition({
        x: event.clientX,
        y: event.clientY
      });

      const newNode = {
        id: `${nodeData.nodeType}-${Date.now()}`,
        type: nodeData.nodeType,
        position,
        data: { ...nodeData.data, title: nodeData.nodeName, type: nodeData.nodeType }
      };

      // 将未定义的节点动态追加进nodeTypes
      const nodeMap = Array.from(Object.values(nodeTypeMap).map(key => key));
      // 目前默认添加的都是系统组件/本地组件
      if (!nodeMap.includes(nodeData.nodeType)) registerNodeType(nodeData.nodeType, LocalNode, nodeData.nodeName);

      setNodes((nds) => nds.concat(newNode));
    },
    [reactFlowInstance]
  );

  const onNodeDrag = useCallback(
    (_: any, node: Node) => {
      // 获取对齐线
      getGuidelines(node, nodes);
    },
    [nodes, getGuidelines]
  );

  // 节点拖拽结束处理
  const onNodeDragStop = useCallback(() => {
    // 清除对齐线
    clearGuidelines();
  }, [clearGuidelines]);

  useEffect(() => {
    const { nodes: convertedNodes, edges: convertedEdges } = convertFlowData(exampleFlowData);
    // 为所有边添加类型
    const initialEdges: Edge[] = convertedEdges.map(edge => ({
      ...edge,
      type: 'custom'
    }));

    setNodes(convertedNodes);
    setEdges(initialEdges);
  }, []);

  // 监听边的变化，处理添加节点的触发
  useEffect(() => {
    const edgeToAddNode = edges.find(edge => edge.data?.addNodeTrigger);
    const pane = reactFlowWrapper.current?.getBoundingClientRect();
    if (edgeToAddNode) {
      edgeToAddNode.data.y = (edgeToAddNode.data.clientY as number) - pane.top;
      edgeToAddNode.data.x = (edgeToAddNode.data.clientX as number) - pane.left;
      setEdgeForNodeAdd(edgeToAddNode);

      // 清除触发标志
      setEdges(eds => eds.map(edge => {
        if (edge.id === edgeToAddNode.id) {
          const { addNodeTrigger, ...restData } = edge.data || {};
          return {
            ...edge,
            data: restData
          };
        }
        return edge;
      }));
    }
  }, [edges]);

  // 节点右键菜单处理
  const onNodeContextMenu = useCallback(
    (event: React.MouseEvent, node: Node) => {
      event.preventDefault();

      const pane = reactFlowWrapper.current?.getBoundingClientRect();
      if (!pane) return;

      setMenu({
        id: node.id,
        type: 'node',
        top: event.clientY - pane.top,
        left: event.clientX - pane.left
      });
    },
    [setMenu]
  );

  // 节点双击处理
  const onNodeDoubleClick = useCallback(
    (event: React.MouseEvent, node: Node) => {
      // 不可编辑的类型
      if (['AND', 'OR', 'JSON2STR', 'STR2JSON'].includes(node.type)) return;
      setEditingNode(node);
      setIsEditModalOpen(true);
    },
    []
  );

  // 边右键菜单处理
  const onEdgeContextMenu = useCallback(
    (event: React.MouseEvent, edge: Edge) => {
      event.preventDefault();

      const pane = reactFlowWrapper.current?.getBoundingClientRect();
      if (!pane) return;

      setMenu({
        id: edge.id,
        type: 'edge',
        top: event.clientY - pane.top,
        left: event.clientX - pane.left
      });
    },
    [setMenu]
  );

  // 画布右键菜单处理
  const onPaneContextMenu = useCallback(
    (event: React.MouseEvent) => {
      event.preventDefault();

      const pane = reactFlowWrapper.current?.getBoundingClientRect();
      if (!pane || !reactFlowInstance) return;

      // 计算在画布中的位置
      const position = reactFlowInstance.screenToFlowPosition({
        x: event.clientX,
        y: event.clientY
      });

      setMenu({
        id: 'pane-context-menu',
        type: 'pane',
        top: event.clientY - pane.top,
        left: event.clientX - pane.left,
        position
      });
    },
    [reactFlowInstance]
  );

  // 点击画布其他区域关闭菜单
  const onPaneClick = useCallback(() => {
    setMenu(null);
    // 关闭添加节点菜单
    setEdgeForNodeAdd(null);
    setPositionForNodeAdd(null);
  }, [setMenu]);

  // 关闭编辑弹窗
  const closeEditModal = useCallback(() => {
    setIsEditModalOpen(false);
    setEditingNode(null);
  }, []);

  // 保存节点编辑
  const saveNodeEdit = useCallback((updatedData: any) => {
    console.log('updatedData:', updatedData);
    const updatedNodes = nodes.map((node) => {
      if (node.id === editingNode?.id) {
        return {
          ...node,
          data: { ...node.data, ...updatedData }
        };
      }
      return node;
    });

    setNodes(updatedNodes);
    closeEditModal();

    // TODO 如果需要在节点编辑后立即保存到服务器，可以调用保存函数
    // saveFlowDataToServer();
  }, [nodes, editingNode, closeEditModal]);

  // 删除节点
  const deleteNode = useCallback((node: Node) => {
    setNodes((nds) => nds.filter((n) => n.id !== node.id));
    setEdges((eds) => eds.filter((e) => e.source !== node.id && e.target !== node.id));
    setMenu(null);
  }, []);

  // 删除边
  const deleteEdge = useCallback((edge: Edge) => {
    setEdges((eds) => eds.filter((e) => e.id !== edge.id));
    setMenu(null);
  }, []);

  // 编辑节点
  const editNode = useCallback((node: Node) => {
    setMenu(null);
    setEditingNode(node);
    setIsEditModalOpen(true);
  }, []);

  // 编辑边
  const editEdge = useCallback((edge: Edge) => {
    // 这里可以实现边编辑逻辑
    console.log('编辑边:', edge);
    setMenu(null);
  }, []);

  // 复制节点
  const copyNode = useCallback((node: Node) => {
    // 这里可以实现节点复制逻辑
    console.log('复制节点:', node);
    setMenu(null);
  }, []);

  // 在边上添加节点的具体实现
  const addNodeOnEdge = useCallback((nodeType: string) => {
    if (!edgeForNodeAdd || !reactFlowInstance) return;

    // 查找节点定义
    const nodeDefinition = localNodeData.find(n => n.nodeType === nodeType);
    if (!nodeDefinition) return;

    // 获取源节点和目标节点
    const sourceNode = nodes.find(n => n.id === edgeForNodeAdd.source);
    const targetNode = nodes.find(n => n.id === edgeForNodeAdd.target);

    if (!sourceNode || !targetNode) return;

    // 计算中点位置
    const position = {
      x: (sourceNode.position.x + targetNode.position.x) / 2,
      y: (sourceNode.position.y + targetNode.position.y) / 2
    };

    // 创建新节点
    const newNode = {
      id: `${nodeType}-${Date.now()}`,
      type: nodeType,
      position,
      data: {
        ...nodeDefinition.data,
        title: nodeDefinition.nodeName,
        type: nodeType
      }
    };

    // 将未定义的节点动态追加进nodeTypes
    const nodeMap = Array.from(Object.values(nodeTypeMap).map(key => key));
    if (!nodeMap.includes(nodeType)) registerNodeType(nodeType, LocalNode, nodeDefinition.nodeName);

    // 添加新节点
    setNodes((nds) => [...nds, newNode]);

    // 删除旧边
    setEdges((eds) => eds.filter(e => e.id !== edgeForNodeAdd.id));

    // 创建新边: source -> new node, new node -> target
    setEdges((eds) => [
      ...eds,
      {
        id: `e${edgeForNodeAdd.source}-${newNode.id}`,
        source: edgeForNodeAdd.source,
        target: newNode.id,
        type: 'custom'
      },
      {
        id: `e${newNode.id}-${edgeForNodeAdd.target}`,
        source: newNode.id,
        target: edgeForNodeAdd.target,
        type: 'custom'
      }
    ]);

    // 关闭菜单
    setEdgeForNodeAdd(null);
    setPositionForNodeAdd(null);
  }, [edgeForNodeAdd, nodes, reactFlowInstance]);

  // 在画布上添加节点
  const addNodeOnPane = useCallback((nodeType: string, position: { x: number; y: number }) => {
    setMenu(null);

    if (!reactFlowInstance) return;

    // 查找节点定义
    const nodeDefinition = localNodeData.find(n => n.nodeType === nodeType);
    if (!nodeDefinition) return;

    // 创建新节点
    const newNode = {
      id: `${nodeType}-${Date.now()}`,
      type: nodeType,
      position,
      data: {
        ...nodeDefinition.data,
        title: nodeDefinition.nodeName,
        type: nodeType
      }
    };

    // 将未定义的节点动态追加进nodeTypes
    const nodeMap = Array.from(Object.values(nodeTypeMap).map(key => key));
    // 目前默认添加的都是系统组件/本地组件
    if (!nodeMap.includes(nodeType)) registerNodeType(nodeType, LocalNode, nodeDefinition.nodeName);

    setNodes((nds) => [...nds, newNode]);
  }, [reactFlowInstance]);

  // 处理添加节点的统一方法
  const handleAddNode = useCallback((nodeType: string) => {
    // 如果是通过边添加节点
    if (edgeForNodeAdd) {
      addNodeOnEdge(nodeType);
    }
    // 如果是通过画布添加节点
    else if (positionForNodeAdd) {
      addNodeOnPane(nodeType, positionForNodeAdd);
    }

    // 清除状态
    setEdgeForNodeAdd(null);
    setPositionForNodeAdd(null);
  }, [edgeForNodeAdd, positionForNodeAdd, addNodeOnEdge, addNodeOnPane]);

  // 保存所有节点和边数据到服务器
  const saveFlowDataToServer = useCallback(async () => {
    try {
      // 准备要发送到服务器的数据
      const flowData = {
        nodes: nodes,
        edges: edges
      };
      // TODO 接口对接后修改后续的更新操作
      console.log('flowData:', flowData);
      return;
      // 发送到服务器的示例代码（需要根据您的实际API进行调整）
      const response = await fetch('/api/flow/save', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(flowData)
      });

      if (response.ok) {
        console.log('Flow data saved successfully');
        // 可以添加成功提示
      }
      else {
        console.error('Failed to save flow data');
        // 可以添加失败提示
      }
    } catch (error) {
      console.error('Error saving flow data:', error);
      // 可以添加错误提示
    }
  }, [nodes, edges]);

  return (
    <div ref={reactFlowWrapper} style={{ width: '100%', height: '100%', position: 'relative' }}
         onContextMenu={(e) => e.preventDefault()}>
      <ReactFlow
        id={new Date().getTime().toString()}
        nodes={nodes}
        edges={edges}
        nodeTypes={nodeTypes}
        edgeTypes={edgeTypes}
        snapToGrid={true}
        snapGrid={[2, 2]}
        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 />
        {/*<Controls />*/}
        <Panel position="top-center">
          <Button onClick={saveFlowDataToServer} type="primary">保存</Button>
        </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}
          />
        </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);
              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 }) => {
              addNodeOnPane(nodeType, position);
              setMenu(null); // 关闭上下文菜单
            }}
          />
        </div>
      )}

      {/*节点双击/节点编辑上下文*/}
      <NodeEditModal
        popupContainer={reactFlowWrapper}
        node={editingNode}
        isOpen={isEditModalOpen}
        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) => {
              handleAddNode(nodeType);
              // 关闭菜单
              setEdgeForNodeAdd(null);
              setPositionForNodeAdd(null);
            }}
            position={positionForNodeAdd || undefined}
            edgeId={edgeForNodeAdd?.id}
          />
        </div>
      )}

    </div>
  );

};

export default FlowEditorWithProvider;