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 imgUrl from '@/assets/images/icons/closeBlue.png';
const { confirm } = Modal;
let diagram = null;
const FlowChart = props => {
  const { flowData, flowID, chartLoading, leaveCallBack } = props;
  const [visible, setVisible] = useState(false);
  const [editMsg, setEditMsg] = useState({}); // 编辑节点的信息
  const [modalType, setModalType] = useState(''); // 存入弹窗是编辑还是新增
  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,
    });
  }, [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 }),
      ), // 去掉节点点击时的边框颜色
    });
    // 节点配置
    diagram.nodeTemplate = objGo(
      go.Node,
      'Auto',
      new go.Binding('location', 'points', go.Point.parse).makeTwoWay(go.Point.stringify),
      // 节点样式配置
      objGo(
        go.Panel,
        objGo(
          go.Shape,
          new go.Binding('width', 'NodeType', v => (v === '0' ? 135 : 105)),
          new go.Binding('height', 'NodeType', v => (v === '0' ? 75 : 105)),
          new go.Binding('figure', 'NodeType', v => (v === '0' ? 'RoundedRectangle' : 'Ellipse')),
          new go.Binding('strokeWidth', 'NodeType', v => (v === '0' ? 1 : 15)),
          new go.Binding('stroke', 'NodeType', v => {
            // 普通节点
            if (v === '0') {
              return '#0587E0';
            }
            // 开始节点
            if (v === '1') {
              return '#d7efff';
            }
            // 结束节点
            if (v === '2') {
              return '#d7efff';
            }
            return '';
          }),
          new go.Binding('fill', 'NodeType', v => {
            // 普通节点
            if (v === '0') {
              return '#DCF2FE';
            }
            // 开始节点
            if (v === '1') {
              return '#0AC03D';
            }
            // 结束节点
            if (v === '2') {
              return '#8585FF';
            }
            return '';
          }),
        ),
      ),
      // 节点文案
      objGo(
        go.TextBlock,
        { maxSize: new go.Size(130, NaN), wrap: go.TextBlock.WrapFit },
        new go.Binding('text', 'NodeName', v => v.slice(0, 6)),
        new go.Binding('stroke', 'NodeType', v => (v === '0' ? '#077BD6' : '#fff')),
      ),
      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, stroke: '#1685FF' },
      ),
      objGo(
        go.Shape, // 箭头
        { toArrow: 'Standard', stroke: '#1685FF', fill: '#1685FF' },
      ),
    );
    // 初始化流程的节点数组
    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 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 => {
    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 } = obj;
      nodeData.NodeName = NodeName;
      nodeData.NodeType = NodeType;
      nodeData.NodeId = nodeKey;
      nodeData.roleList = roleList;
      nodeData.SerialNo = SerialNo;
      nodeData.aheadHandle = aheadHandle;
      nodeData.NodeHandling = NodeHandling;
      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 getFlowData = () => {
    GetFlowNode({ flowID }).then(res => {
      if (res.code === 0) {
        // 保存后离开不用提醒要修改数据了
        setShowLeaveTip(false);
        leaveCallBack(false);
        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>
      <Spin spinning={chartLoading}>
        <div
          id="myDiagramDiv"
          className={styles.myDiagramDiv}
          style={{ backgroundColor: '#EFF8FA' }}
        />
      </Spin>

      <NodeModal
        visible={visible}
        editMsg={editMsg}
        newSerialNo={newSerialNo}
        nodeNum={nodeLength}
        modalType={modalType}
        handleCancel={() => setVisible(false)}
        onSubumit={obj => nodeCallBack(obj)}
      />
    </>
  );
};

export default FlowChart;