import React, { useState, useEffect } from 'react';
import { Button, Modal, notification, Spin } from 'antd';
import { SaveNodeChange, GetFlowNode } from '@/services/workflow/workflow';

import { ExclamationCircleOutlined } from '@ant-design/icons';
import { Prompt } from 'react-router-dom';
import * as go from 'gojs';
import styles from '../workflow.less';
import NodeModal from './flowChartComponents/NodeModal';
import LineModal from './flowChartComponents/LineModal';
import imgUrl from '@/assets/images/icons/closeBlue.png';
import imgEnd from '@/assets/images/workFlow/end.png';
import imgGeneral from '@/assets/images/workFlow/general.png';
import imgStart from '@/assets/images/workFlow/start.png';
import cc from '@/assets/images/workFlow/cc.png';
import gatewayExclusive from '@/assets/images/workFlow/gatewayExclusive.png';
import gatewayConfluence from '@/assets/images/workFlow/gatewayConfluence.png';
import gatewayInclude from '@/assets/images/workFlow/gatewayInclude.png';
const { confirm } = Modal;
let diagram = null;
const FlowChart = props => {
  const { flowData, flowID, chartLoading, leaveCallBack } = props;
  const [visible, setVisible] = useState(false);
  const [lineVisible, setLineVisible] = useState(false);
  const [editMsg, setEditMsg] = useState({}); // 编辑节点的信息
  const [lineMsg, setLineMsg] = useState({});
  const [modalType, setModalType] = useState(''); // 存入弹窗是编辑还是新增
  const [lineId, setLineId] = useState(''); //  存入编辑线id
  const [nodeKey, setNodeKey] = useState(''); // 存入编辑节点的key
  const [DeleteNodes, setDeleteNodes] = useState([]); // 删除节点数组
  const [DeleteLines, setDeleteLines] = useState([]); // 删除线数组
  const [deleteLine, setDeleteLine] = useState(); // 删除的线id
  const [deleteNode, setDeleteNode] = useState(); // 删除的节点id
  const [AddNodes, setAddNodes] = useState([]); // 新增数组
  const [initFlowData, setInitFlowData] = useState({}); // 初始数据，用来比对是否有修改流程图
  const [currentFlowData, setCurrentFlowData] = useState({
    Nodes: [],
    Lines: [],
  }); // 组件内得流程图数据
  const [showLeaveTip, setShowLeaveTip] = useState(false); // 离开路由是否又提醒
  const [newSerialNo, setNewSerialNo] = useState(0);
  const [nodeLength, setNodeLength] = useState();
  const objGo = go.GraphObject.make;
  // 监听删除，给删除数组里添加删除id
  useEffect(() => {
    if (deleteLine) {
      setDeleteLines([...DeleteLines, deleteLine]);
    }
  }, [deleteLine]);
  useEffect(() => {
    if (deleteNode) {
      setDeleteNodes([...DeleteNodes, deleteNode]);
    }
  }, [deleteNode]);
  // 初始化
  useEffect(() => {
    // 初始化流程图
    init();
    // 监听节点或线的删除事件
    diagram.addDiagramListener('SelectionDeleted', e => {
      e.subject.each(n => {
        // 如果删除得节点不是新增得就给id放入到删除节点数组中
        if (n.data.NodeId && !AddNodes.some(item => item === n.data.NodeId)) {
          setTimeout(() => {
            setDeleteNode(n.data.NodeId);
          }, 0);
        }
        if (n.data.LineId) {
          setTimeout(() => {
            setDeleteLine(n.data.LineId);
          }, 0);
        }
      });
    });
    // 监听节点或线的删除前事件
    diagram.commandHandler.canDeleteSelection = () =>
      // 用例获取选中的节点或线
      diagram.selection.all(() => {
        // 判断是否存在不允许删除的节点或线
        showDeleteConfirm();
        return false;
      });
  }, []);
  useEffect(() => {
    if (flowData) {
      // 每次切换时清空删除得id数组跟新增得id数组
      setDeleteNodes([]);
      setDeleteLines([]);
      setAddNodes([]);
      setDeleteNode('');
      setDeleteLine('');
      setCurrentFlowData(JSON.parse(JSON.stringify(flowData)));
      setShowLeaveTip(false);
    }
  }, [flowData]);
  // 存入在树形流程中选择得流程数据
  useEffect(() => {
    let nodeDataArray;
    if (currentFlowData.Nodes.length === 0) {
      nodeDataArray = [];
    } else {
      // 处理老数据，让老数据可以正常展示
      nodeDataArray = currentFlowData.Nodes.map((item, index) => {
        let obj;
        obj = item;
        obj.key = item.NodeId;
        if (obj.points === '') {
          if (obj.NodeType === '1') {
            obj.points = `${(index * 200).toString()}" 100"`;
          } else {
            obj.points = `${(index * 200).toString()}" -22"`;
          }
        }
        return obj;
      });
    }
    // 保存初始数据
    setInitFlowData(
      JSON.parse(
        JSON.stringify({
          Nodes: nodeDataArray,
          Lines: currentFlowData.Lines,
        }),
      ),
    );
    diagram.model = go.Model.fromJson({
      linkFromPortIdProperty: 'fromPort', // 所需信息：
      linkToPortIdProperty: 'toPort', // 标识数据属性名称
      nodeDataArray,
      linkDataArray: currentFlowData.Lines,
    });
    // diagram.model.linkKeyProperty = 'LineId';
    // diagram.model.makeUniqueLinkKeyFunction = (model, data) => {
    //   let i = model.linkDataArray.length * 2 + 2;
    //   while (model.findLinkDataForKey(i) !== null) i += 2;
    //   return i;
    // };
  }, [currentFlowData]);
  // 删除提醒
  const showDeleteConfirm = () => {
    confirm({
      title: '确定要删除所选中的节点吗？',
      icon: <ExclamationCircleOutlined />,
      content: '',
      okText: '是',
      okType: 'danger',
      cancelText: '否',
      onOk() {
        delNode();
      },
      onCancel() {},
    });
  };
  // 删除节点
  const delNode = () => {
    setShowLeaveTip(true);
    leaveCallBack(true);
    diagram.commandHandler.deleteSelection();
  };
  // 流程图初始化
  const init = () => {
    diagram = objGo(go.Diagram, 'myDiagramDiv', {
      'undoManager.isEnabled': true,
      allowDragOut: false,
      'dragSelectingTool.isEnabled': false, // 禁止多选
      allowCopy: false, // 禁止复制
      nodeSelectionAdornmentTemplate: objGo(
        go.Adornment,
        'Auto',
        objGo(go.Shape, 'Rectangle', { fill: 'white', stroke: null }),
      ), // 去掉节点点击时的边框颜色
      scale: '0.8',
    });
    // 节点配置
    diagram.nodeTemplate = objGo(
      go.Node,
      'Auto',
      new go.Binding('location', 'points', go.Point.parse).makeTwoWay(go.Point.stringify),
      // 节点样式配置
      objGo(
        go.Panel,
        objGo(
          go.Picture,
          new go.Binding('source', 'NodeType', v => {
            switch (v) {
              case '1':
                return imgStart;
              case '2':
                return imgEnd;
              case '0':
                return imgGeneral;
              case '4':
                return cc;
              case '20':
                return gatewayExclusive;
              case '21':
                return gatewayInclude;
              case '22':
                return gatewayConfluence;
              default:
                return null;
            }
          }),
          new go.Binding('width', 'NodeType', v => {
            switch (v) {
              case '1':
                return 126;
              case '2':
                return 126;
              case '0':
                return 210;
              case '4':
                return 210;
              case '20':
                return 52;
              case '21':
                return 52;
              case '22':
                return 52;
              default:
                return null;
            }
          }),

          new go.Binding('height', 'NodeType', v => {
            switch (v) {
              case '1':
                return 126;
              case '2':
                return 126;
              case '0':
                return 110;
              case '4':
                return 110;
              case '20':
                return 52;
              case '21':
                return 52;
              case '22':
                return 52;
              default:
                return null;
            }
          }),
        ),
      ),

      // 节点文案
      objGo(
        go.TextBlock,
        { maxSize: new go.Size(130, NaN), wrap: go.TextBlock.WrapFit, font: 'bold 15pt serif' },
        new go.Binding('text', 'nodeDetail', v => {
          const obj = JSON.parse(v);
          if (obj.NodeType === '20' || obj.NodeType === '21') {
            return '';
          }
          return obj.NodeName;
        }),
        new go.Binding('stroke', 'NodeType', v => {
          switch (v) {
            case '1':
              return '#1685FF';
            case '2':
              return '#51C21A';
            case '0':
              return '#1685FF';
            case '4':
              return '#9850F6';
            case '20':
              return null;
            case '21':
              return null;
            case '22':
              return null;

            default:
              return null;
          }
        }),
      ),
      // objGo(
      //   go.Picture,
      //   {
      //     source: imgUrl, // 图片路径
      //     desiredSize: new go.Size(12, 12),
      //     alignment: go.Spot.TopRight, // 对齐主要形状上的端口
      //     alignmentFocus: go.Spot.TopRight, // 就在形状里面
      //     click() {
      //       // 删除节点
      //       showDeleteConfirm();
      //     },
      //   },
      //   new go.Binding('margin', 'NodeType', v => (v === '0' ? 5 : 17)),
      // ),
      // 我们的小命名端口，每侧一个：
      makePort('T', go.Spot.Top),
      makePort('L', go.Spot.Left),
      makePort('R', go.Spot.Right),
      makePort('B', go.Spot.Bottom),
      {
        // 处理鼠标进入/离开事件以显示/隐藏端口
        mouseEnter(e, node) {
          showSmallPorts(node, true);
        },
        mouseLeave(e, node) {
          showSmallPorts(node, false);
        },
        // 处理双击
        doubleClick(e, node) {
          // 双击事件
          handlerDC(e, node); // 双击执行的方法
        },
      },
    );
    // 链接设置
    diagram.linkTemplate = objGo(
      go.Link,
      {
        routing: go.Link.Orthogonal,
        curve: go.Link.JumpOver,
        corner: 5,
        toShortLength: 4,
      },
      new go.Binding('points').makeTwoWay(),
      objGo(
        go.Shape, // 链接路径形状
        {
          isPanelMain: true,
          strokeWidth: 2,
        },

        new go.Binding('stroke', 'from', v => {
          console.log(diagram.model.findNodeDataForKey(v));
          const msg = diagram.model.findNodeDataForKey(v);
          if (msg.NodeType === '20' || msg.NodeType === '22') {
            return 'red';
          }
          return '#1685FF';
        }),
      ),
      objGo(
        go.Shape, // 箭头
        { toArrow: 'Standard' },
        new go.Binding('stroke', 'from', v => {
          console.log(diagram.model.findNodeDataForKey(v));
          const msg = diagram.model.findNodeDataForKey(v);
          if (msg.NodeType === '20' || msg.NodeType === '22') {
            return 'red';
          }
          return '#1685FF';
        }),
        new go.Binding('fill', 'from', v => {
          console.log(diagram.model.findNodeDataForKey(v));
          const msg = diagram.model.findNodeDataForKey(v);
          if (msg.NodeType === '20' || msg.NodeType === '22') {
            return 'red';
          }
          return '#1685FF';
        }),
      ),
      // {
      //   // 处理双击
      //   doubleClick(e, node) {
      //     addLineMsg(e, node);
      //     // 双击事件
      //     // handlerDC(e, node); // 双击执行的方法
      //   },
      // },
    );
    // 初始化流程的节点数组
    diagram.model = objGo(go.GraphLinksModel, {
      linkFromPortIdProperty: 'fromPort', // 所需信息：
      linkToPortIdProperty: 'toPort', // 标识数据属性名称
      nodeDataArray: currentFlowData.Nodes,
      linkDataArray: currentFlowData.Lines,
    });
  };
  // 是否显示端口
  const showSmallPorts = (node, show) => {
    node.ports.each(port => {
      if (port.portId !== '') {
        // 不要更改默认端口，这是大形状
        port.fill = show ? 'rgba(5,135,224,.3)' : null;
      }
    });
  };
  // 创建节点端口
  const makePort = (name, spot) =>
    // 端口基本上只是一个小的透明 方块
    objGo(
      go.Shape,
      'Circle',
      {
        fill: null, // 默认情况下不可见； 由 showSmallPorts 设置为半透明灰色，定义如下
        stroke: null,
        desiredSize: new go.Size(8, 8),
        alignment: spot, // 对齐主要形状上的端口
        alignmentFocus: spot, // 就在形状里面
        portId: name, // 将此对象声明为“端口”
        fromSpot: spot,
        toSpot: spot, // 声明链接可以在此端口连接的位置
        cursor: 'pointer', // 显示不同的光标以指示潜在的链接点
      },
      new go.Binding('fromLinkable', 'NodeType', v => v !== '2'), // 是否允许用户绘制的链接到这里
      new go.Binding('toLinkable', 'NodeType', v => v !== '1'), // 声明用户是否可以从这里绘制链接
    );
  // 双击节点
  const handlerDC = (e, node) => {
    setNodeKey(node.part.data.key);
    setEditMsg(node.part.data);
    setModalType('edit');
    setVisible(true);
  };
  // 双击线
  const addLineMsg = (e, node) => {
    // setLineId(node.part.data.__gohashid);
    setLineMsg(node.part.data);
    setLineVisible(true);
  };
  // 新增节点
  const addNode = () => {
    const list = JSON.parse(diagram.model.toJson()).nodeDataArray;
    console.log(list, 'list');
    let newNum;

    if (list.length > 0) {
      // eslint-disable-next-line prefer-spread
      newNum = Math.max.apply(Math, list.map(item => item.SerialNo)) + 1;
    } else {
      newNum = 1;
    }
    setNodeLength(list.length);
    console.log(newNum);
    setNewSerialNo(newNum);
    setModalType('add');
    setVisible(true);
  };
  // 节点配置回调
  const nodeCallBack = obj => {
    console.log(obj, 'obj');
    let nameIsRepeat;
    let { nodes } = diagram;
    let keyArr = [];
    // 遍历输出节点对象
    nodes.each(node => {
      keyArr = [...keyArr, Number(node.data.key)];
      if (obj.NodeName === node.data.NodeName) {
        nameIsRepeat = true;
        if (modalType === 'edit' && obj.NodeName === editMsg.NodeName) {
          nameIsRepeat = false;
        }
      }
    });
    if (nameIsRepeat) {
      notification.error({
        message: '提示',
        duration: 3,
        description: '节点名称不能重复',
      });
      return;
    }
    if (modalType === 'add') {
      // 新增节点
      // 新增得key比最大得key值+1
      let newKey;
      if (keyArr.length === 0) {
        newKey = 1;
      } else {
        newKey = keyArr.reduce((num1, num2) => (num1 > num2 ? num1 : num2)) + 1;
      }
      diagram.model.addNodeData({
        key: newKey,
        NodeId: newKey,
        ...obj,
      });
      setAddNodes([...AddNodes, newKey]);
    }
    if (modalType === 'edit') {
      // 编辑节点
      let nodeData = diagram.model.findNodeDataForKey(nodeKey);
      const {
        NodeName,
        NodeType,
        roleList,
        SerialNo,
        aheadHandle,
        NodeHandling,
        nodeDetail,
        RuleList,
      } = obj;
      nodeData.NodeName = NodeName;
      nodeData.NodeType = NodeType;
      nodeData.NodeId = nodeKey;
      nodeData.roleList = roleList;
      nodeData.SerialNo = SerialNo;
      nodeData.aheadHandle = aheadHandle;
      nodeData.NodeHandling = NodeHandling;
      nodeData.nodeDetail = nodeDetail;
      nodeData.RuleList = RuleList;
      diagram.model.updateTargetBindings(nodeData);
    }
    // 关闭时进行数据比对看数据是否改变
    let diagramObj = JSON.parse(diagram.model.toJson());
    let stageJson = {
      Nodes: diagramObj.nodeDataArray,
      Lines: diagramObj.linkDataArray,
    };
    if (JSON.stringify(stageJson.Nodes) === JSON.stringify(initFlowData.Nodes)) {
      setShowLeaveTip(false);
      leaveCallBack(false);
    } else {
      leaveCallBack(true);
      setShowLeaveTip(true);
    }
    setVisible(false);
  };
  // 线配置回调函数
  const lineCallBack = obj => {
    console.log(obj, 'obj');
    console.log(lineId, 'lineId');
    let node = diagram.findLinkDataForKey(lineId);
    console.log(node, 'linkemsg');
    // 关闭时进行数据比对看数据是否改变
    let diagramObj = JSON.parse(diagram.model.toJson());
    let stageJson = {
      Nodes: diagramObj.nodeDataArray,
      Lines: diagramObj.linkDataArray,
    };

    if (JSON.stringify(stageJson.Nodes) === JSON.stringify(initFlowData.Nodes)) {
      setShowLeaveTip(false);
      leaveCallBack(false);
    } else {
      leaveCallBack(true);
      setShowLeaveTip(true);
    }
    setLineVisible(false);
  };
  // 获取保存后的流程数据
  const getFlowData = () => {
    GetFlowNode({ flowID }).then(res => {
      if (res.code === 0) {
        // 保存后离开不用提醒要修改数据了
        setShowLeaveTip(false);
        leaveCallBack(false);
        res.data.Nodes.forEach(item => {
          item.nodeDetail = JSON.stringify(item);
        });
        setCurrentFlowData(res.data);
      } else {
        notification.error({
          title: '提示',
          duration: 3,
          description: res.msg,
        });
      }
    });
  };
  const isRepeat = (arr, key) => {
    let obj = {};
    for (let i = 0; i < arr.length; i++) {
      if (obj[arr[i][key]]) {
        return false;
      }
      obj[arr[i][key]] = arr[i];
    }
    return obj;
  };

  // 保存流程
  const saveFlow = () => {
    let diagramObj = JSON.parse(diagram.model.toJson());
    // let list = isRepeat(diagramObj.nodeDataArray, 'SerialNo');

    // if (!list) {
    //   notification.error({
    //     message: '提示',
    //     duration: 3,
    //     description: '请检查序号是否重复',
    //   });
    //   return;
    // }
    SaveNodeChange({
      FlowId: flowID,
      DeleteNodes,
      DeleteLines,
      Lines: diagramObj.linkDataArray,
      Nodes: diagramObj.nodeDataArray,
    })
      .then(res => {
        if (res.code === 0) {
          setDeleteNodes([]);
          setDeleteLines([]);
          setAddNodes([]);
          setDeleteNode('');
          setDeleteLine('');
          getFlowData();
          notification.success({
            message: '提示',
            duration: 3,
            description: '保存成功',
          });
        } else {
          notification.error({
            message: '提示',
            duration: 8,
            description: res.msg,
          });
        }
      })
      .catch(() => {
        notification.error({
          message: '提示',
          duration: 3,
          description: '网络异常请稍后重试',
        });
      });
  };
  return (
    <>
      <Prompt message="编辑的内容还未保存，确定要离开该页面吗?" when={showLeaveTip} />
      <div className={styles.buttonList}>
        <Button onClick={() => addNode()}>添加节点</Button>
        <Button type="primary" onClick={() => saveFlow()}>
          保存
        </Button>
      </div>
      <div className={styles.chartBox}>
        <Spin spinning={chartLoading}>
          <div
            id="myDiagramDiv"
            className={styles.myDiagramDiv}
            style={{ backgroundColor: '#EFF8FA' }}
          />
        </Spin>
      </div>
      <NodeModal
        flowID={flowID}
        visible={visible}
        editMsg={editMsg}
        newSerialNo={newSerialNo}
        nodeNum={nodeLength}
        modalType={modalType}
        handleCancel={() => setVisible(false)}
        onSubumit={obj => nodeCallBack(obj)}
        flowData={diagram ? JSON.parse(diagram.model.toJson()) : {}}
      />
      {/* <LineModal
        visible={lineVisible}
        lineMsg={lineMsg}
        handleCancel={() => setLineVisible(false)}
        onSubumit={obj => lineCallBack(obj)}
      /> */}
    </>
  );
};

export default FlowChart;
