import { Graph, Shape } from '@antv/x6';
import { WorkflowNodeToolbar } from './workflow_node_toolbar';
import { Selection } from '@antv/x6-plugin-selection';
import { Transform } from '@antv/x6-plugin-transform'
import { EDGE } from '../shape/gengral-config';
import { WorkflowEdgeToolbar } from './workflow_edge_toolbar';
import { message, Modal } from 'ant-design-vue';
import { createVNode } from 'vue';
import { DeleteOutlined } from '@ant-design/icons-vue';
import { Scroller } from '@antv/x6-plugin-scroller';
import { Keyboard } from '@antv/x6-plugin-keyboard';
import { Snapline } from '@antv/x6-plugin-snapline'
import { useWorkflowStore } from '@/store/modules/workflow';
import router from '@/router/index';
import { defaultEdgeData, conditionEdgeData, IllogicalEdgeData, noticeEdgeData, relation1EdgeData, relation2EdgeData } from './edge_type_data';
import { FlowDesignApi } from '../../mid/workflow/design/api/FlowDesignApi';

const { stroke: lineColor } = EDGE;

export class WorkflowGraph {
  graph;
  edge;
  clickNodeCallback;
  nodeAddedCallback;
  workflowNodeToolbar;
  workflowEdgeToolbar;
  selfProxy;
  selectionRef = null;
  transformRef = null;
  scrollerRef = null;
  elementScroller = null;
  elementShape = null;
  elementImmovable = null;
  spaceKeyActive = false;
  isSpace = false;
  upImg = 'url(/hand.png), auto';
  downImg = 'url(/hold.png), auto';
  backUrl = '';

  constructor(proxy, container, clickNodeCallback, isPreview = false, nodeAddedCallback = () => { }, backUrl = '') {
    this.selfProxy = proxy;
    const containerParentEl = container.parentElement;
    const { clientWidth: width, clientHeight: height } = containerParentEl;
    this.clickNodeCallback = clickNodeCallback;
    this.nodeAddedCallback = nodeAddedCallback;
    this.backUrl = backUrl;

    // 初始化画布
    this.graph = new Graph({
      background: {
        color: '#f8f8f8'
      },
      // 画布缩放
      mousewheel: {
        enabled: false,
        modifiers: ['ctrl', 'meta']
      },
      container,
      width,
      height,
      async: true,
      // 绘制网格背景
      grid: false,
      // 自动更新画布大小
      autoResize: true,
      // 确保你的 Graph 配置中启用了 panning 和 scroller
      panning: {
        enabled: false, // 初始时不启用 panning
        eventTypes: ['leftMouseDown'] // 仅在左键按下时允许拖动
      },
      // 是否禁用拖动
      interacting: cellView => {
        if (cellView.cell.shape == 'rect' && !cellView.cell.data) {
          return false;
        }
        if (this.spaceKeyActive) {
          return false;
        }
        // 如果是预览模式则禁用拖动
        return !isPreview;
      },
      connecting: {
        // 通过高亮+允许多边机制，实现修改边的起点或终点时，确定可连接的连接桩
        highlight: true,
        allowMulti: true,
        anchor: 'center',
        connectionPoint: 'anchor',
        allowBlank: () => {
          // 隐藏所有连接桩
          this.hideAllPorts();

          // 禁止连接到画布空白位置的点
          return false;
        },
        // 禁止创建循环连线，即边的起始节点和终止节点为同一节点
        allowLoop: false,
        // 禁止边链接到节点（非节点上的链接桩）
        allowNode: false,
        // 禁止边链接到另一个边
        allowEdge: false,
        snap: {
          radius: 20
        },
        createEdge(e) {
          const edgeType = useWorkflowStore().edgeType;
          let edgeData = {};
          if (edgeType == 251) {
            // 带条件
            edgeData = conditionEdgeData;
          } else if (edgeType == 252) {
            // 无逻辑
            edgeData = IllogicalEdgeData;
          } else if (edgeType == 253) {
            // 带消息
            edgeData = noticeEdgeData;
          } else if (edgeType == 254) {
            // 关联1
            edgeData = relation1EdgeData;
          } else if (edgeType == 255) {
            // 关联2
            edgeData = relation2EdgeData;
          } else {
            // 默认箭头
            edgeData = defaultEdgeData;
          }
          this.edge = new Shape.Edge(edgeData);
          return this.edge
        },
        validateEdge: ({ edge, type, previous }) => {
          // 移除虚线
          const edgeType = useWorkflowStore().edgeType;
          if ([250, 251].includes(edgeType)) {
            edge.removeAttrByPath('line/strokeDasharray');
          }
          // 设置颜色
          edge.setAttrByPath('line/stroke', lineColor._default);

          return true;
        },
        validateMagnet: ({ magnet, cell }) => {
          const nodeData = JSON.parse(cell.data);
          // 如果新增节点边的节点类型是结束节点则不允许新增
          if (nodeData.type === 11) {
            return false;
          }

          // 显示全部ports
          this.showAllPorts();

          // 如果新增节点边的节点类型是 条件 则隐藏 其他条件节点的port
          if (nodeData.type === 60) {
            this.graph.getNodes().forEach(node => {
              if (node.data) {
                let nodeData = JSON.parse(node.data);
                if (nodeData.type === 60) {
                  if (cell.id !== node.id) {
                    this.showOrHiddenNodePorts(node, false);
                  }
                }
              }
            });
          }

          // 如果新增节点板的节点类型是 条件网关 则只显示可以连接的条件节点
          if (nodeData.type === 50) {
            this.graph.getNodes().forEach(node => {
              if (node.data) {
                let nodeData = JSON.parse(node.data);
                if (nodeData.type !== 60) {
                  if (cell.id !== node.id) {
                    this.showOrHiddenNodePorts(node, true);
                  }
                }
              }
            });
          }

          return true;
        }
      },
      highlighting: {
        // 连线过程中，自动吸附到链接桩时被使用
        magnetAdsorbed: {
          name: 'stroke',
          args: {
            padding: 0,
            attrs: {
              stroke: '#096DD9'
            }
          }
        }
      },
      resizing: true,
      rotating: false,
      keyboard: true,
      clipboard: true
    });

    // 初始化节点工具栏
    this.workflowNodeToolbar = new WorkflowNodeToolbar(proxy, this.graph);
    // 初始化边工具栏
    this.workflowEdgeToolbar = new WorkflowEdgeToolbar(this.graph);

    if (this.selfProxy.container) {
      this.selfProxy.container.style.cursor = 'auto';
    }

    // 如果不是预览模式则绑定事件
    this.scrollerRef = new Scroller({
      enabled: true,
      minVisibleWidth: 1000,
      minVisibleHeight: 500,
      padding: undefined,
      pannable: true
    });

    // 框选
    this.graph.use(this.scrollerRef);
    this.graph.use(new Snapline({
      enabled: true,
    }),);

    this.graph.disablePanning(); // 禁用 Scroller 的拖拽功能
    if (!isPreview) {
      this.selectionRef = new Selection({
        className: 'guns-selection',
        enabled: true,
        showNodeSelectionBox: true,
        rubberband: true,
      });

      // 框选
      this.graph.use(this.selectionRef);

      this.transformRef = new Transform({
        resizing: true,
        rotating: true,
      })

      // 旋转、拉伸
      this.graph.use(this.transformRef);

      // 禁止框选
      this.graph.setSelectionFilter(cell => {
        if (cell.data) {
          return true;
        }
        return false;
      });

      // // 绑定事件
      this.bindEvent();

      // // 快捷键
      this.graph.use(
        new Keyboard({
          enabled: true
        })
      );
      // // 绑定快捷键
      this.bindKey();
    } else {
      this.setNullNodeData();
    }

    this.elementScroller = document.getElementsByClassName('x6-graph-scroller-content');
    this.elementShape = document.getElementsByClassName('x6-vue-shape');
    this.elementImmovable = document.getElementsByClassName('x6-node-immovable');

    document.addEventListener('mousemove', e => this.mousemove(e));

    // 监听空格键按下和释放
    document.addEventListener('keydown', e => this.spaceKeydown(e));

    // 空格抬起事件
    document.addEventListener('keyup', e => this.spaceKeyup(e));
  }

  /**
   * 显示或隐藏节点的ports
   * @param node
   * @param showOrHidden
   */
  showOrHiddenNodePorts(node, showOrHidden) {
    node.getPorts().forEach(port =>
      node.portProp(port.id, {
        attrs: {
          circle: {
            r: 0,
            // 连接桩在连线交互时不可被连接
            magnet: showOrHidden,
            fill: '#FFFFFF'
          }
        }
      })
    );
  }

  /**
   * 绑定快捷键
   */
  bindKey() {
    // 绑定 delete 按键  删除框选的节点
    this.graph.bindKey(['delete'], () => {
      const cells = this.graph.getSelectedCells();
      if (cells.length) {
        cells.forEach(cell => {
          this.graph.removeNode(cell.id);
        });
      }
      return false;
    });

    // 绑定 ctrl + s / cmd + s 快捷键
    this.graph.bindKey(['ctrl+s', 'command+s'], () => {
      let definitionId = useWorkflowStore().definitionId;
      if (definitionId) {
        const params = {
          definitionId: definitionId,
          sixGraphDesign: {
            flowGlobalConfig: useWorkflowStore().flowGlobalConfig,
            nodeGraph: this.graph.toJSON()
          }
        };
        FlowDesignApi.saveSixGraphDesign(params).then(() => {
          message.info('保存成功！');
        });
      }
    });

    // 监听 backspace 返回模型设计列表页
    this.graph.bindKey(['backspace'], () => {
      router.push(
        this.backUrl
      );
    });

    // 修改按下alt 修改鼠标样式
    this.graph.bindKey(
      ['Space'],
      () => {
        this.selfProxy.container.style.cursor = 'auto';
      },
      'keyup'
    );
    this.graph.bindKey(
      ['Space'],
      () => {
        this.selfProxy.container.style.cursor = this.upImg;
      },
      'keydown'
    );
  }

  /**
   * 绑定事件
   */
  bindEvent() {
    this.graph.on('node:mousedown', ({ node }) => {
      if (node.data) {
        if (!this.spaceKeyActive) {
          // 隐藏节点工具栏
          this.workflowNodeToolbar.hide();
          if (this.selfProxy.container) {
            this.selfProxy.container.style.cursor = 'auto';
          }
        } else {
          this.graph.disableKeyboard(); // 禁用快捷键
          this.graph.enablePanning(); // 启用 Scroller 的拖拽功能
        }
      }
    });

    this.graph.on('node:mouseup', ({ node }) => {
      if (node.data) {
        if (!this.spaceKeyActive) {
          // 显示节点工具栏
          this.workflowNodeToolbar.show(node);
          this.graph.enableKeyboard(); // 启用快捷键

          // 移除节点删除小工具
          if (node.hasTool('button-remove')) {
            node.removeTool('button-remove');
          }
        } else {
          this.graph.disablePanning(); // 禁用 Scroller 的拖拽功能
          if (this.selfProxy.container) {
            this.selfProxy.container.style.cursor = 'auto';
          }
        }
      }
    });

    // 鼠标离开节点
    this.graph.on('node:mouseleave', ({ node }) => {
      if (node.data) {
        if (!this.spaceKeyActive) {
          if (node.hasTool('button-remove')) {
            node.removeTool('button-remove');
          }

          this.hideAllPorts();
        }
      }
    });

    // 鼠标进入节点
    this.graph.on('node:mouseenter', ({ node }) => {
      if (node.data) {
        const nodeData = JSON.parse(node.data)
        if (!this.spaceKeyActive) {
          // 显示节点工具栏
          this.workflowNodeToolbar.show(node);

          let graph = this.graph;
          //removeNode

          // 删除节点是否提示
          const isRemoveConfirm = false;
          if (!node.hasTool('button-remove')) {
            let args = {};
            // 旧ui
            if (nodeData.type < 99) {
              if (node.shape === 'custom-polygon') {
                args = {
                  x: 0,
                  y: 0,
                  offset: { x: 20, y: 20 }
                };
              } else if (node.shape === 'custom-circle') {
                args = {
                  x: 0,
                  y: 0
                };
              } else {
                args = {
                  x: 5,
                  y: 0
                };
              }

              // 业务图
            } else if (nodeData.type == 300) {
              args = {
                x: 5,
                y: 0,
                offset: { x: 20, y: 0 }
              };
            } else if (nodeData.type == 301) {
              args = {
                x: 5,
                y: 5,
              };
            } else if (nodeData.type == 303) {
              args = {
                x: 5,
                y: 10,
                offset: { x: 20, y: 0 }
              };
            } else if (nodeData.type == 304) {
              args = {
                x: 5,
                y: 0,
                offset: { x: 20, y: 0 }
              };
            } else {
              // 新ui

            }

            // 添加删除小工具
            node.addTools([
              {
                name: 'button-remove',
                args: {
                  ...args,
                  onClick({ cell }) {
                    if (isRemoveConfirm) {
                      Modal.confirm({
                        title: '删除节点',
                        content: '确定要删除节点吗',
                        icon: createVNode(DeleteOutlined),
                        maskClosable: true,
                        onOk: () => {
                          graph.removeNode(cell.id);
                        }
                      });
                    } else {
                      graph.removeNode(cell.id);
                    }
                  }
                }
              }
            ]);
          }
        } else {
          this.workflowNodeToolbar.hide();
        }
      }
    });

    // 鼠标单击节点
    this.graph.on('node:click', ({ e, node }) => {
      this.graph.clearTransformWidgets(); // 清空拉伸
      if (node.data) {
        if (!this.spaceKeyActive) {
          if (e.target.getAttribute('class') === 'x6-port-body') {
            // 表示点击连接桩，忽略
            return;
          }
          // 获取节点的所有连接桩
          const ports = node.getPorts();

          // 分类存储连接桩
          const portGroups = {
            top: [],
            right: [],
            bottom: [],
            left: []
          };

          // 将连接桩根据其位置分组
          ports.forEach(port => {
            if (port.group && portGroups[port.group] !== undefined) {
              portGroups[port.group].push(port);
            }
          });

          let groupList = [];

          // 检查每个方向的连接桩是否被连线
          Object.entries(portGroups).forEach(([group, ports]) => {
            ports.forEach(port => {
              const edges = this.graph.getConnectedEdges(node, {
                deep: true,
                portId: port.id
              });
              if (edges.length === 0) {
                groupList.push({ name: group, id: port.id });
              } else {
                if (!edges.find(item => item.source.port == port.id || item.target.port == port.id)) {
                  groupList.push({ name: group, id: port.id });
                }
              }
            });
          });

          let nodeData = {
            nodeId: node.id,
            groupList: groupList
          };
          const workflowStore = useWorkflowStore();

          let currentNodeData = JSON.parse(node.data);
          // 结束节点不显示加号
          if (currentNodeData.type == 11) {
            nodeData.nodeId = '';
            nodeData.groupList = [];
          }

          // 如果是泳道，创建图形变换
          if (currentNodeData.type == 99 || currentNodeData.type == 99.5 || currentNodeData.type > 259 && currentNodeData.type < 270 || currentNodeData.type > 299 && currentNodeData.type < 399) {
            this.graph.createTransformWidget(node);
          }
          // 设置当前选中是否显示加号
          workflowStore.setNodeData(nodeData);
        }
      } else {
        this.setNullNodeData();
      }
    });

    // 鼠标双击节点
    this.graph.on('node:dblclick', ({ e, node }) => {
      if (node.data) {
        const { type } = JSON.parse(node.data);
        if (!this.spaceKeyActive && !(type > 299 && type < 399)) {
          if (e.target.getAttribute('class') === 'x6-port-body') {
            // 表示点击连接桩，忽略
            return;
          }

          this.clickNodeCallback(node.id);

          this.setNullNodeData();
        }
      } else {
        this.setNullNodeData();
      }
    });

    // 节点添加进画布
    this.graph.on('node:added', ({ node }) => {
      this.nodeAddedCallback(node);
    });

    this.graph.on('edge:mouseenter', ({ edge }) => {
      if (!this.spaceKeyActive) {
        // 显示边工具栏
        this.workflowEdgeToolbar.show(edge);
      } else {
        this.graph.disableKeyboard(); // 禁用快捷键
        this.workflowEdgeToolbar.hide();
      }
    });
    this.graph.on('edge:mouseleave', () => {
      if (!this.spaceKeyActive) {
        this.graph.enableKeyboard(); // 启用快捷键
        // 隐藏边工具栏
        this.workflowEdgeToolbar.hide();
      }
      this.workflowEdgeToolbar.hide();
    });

    // 点击空白画布
    this.graph.on('blank:click', () => {
      if (!this.spaceKeyActive) {
        // 清空当前选中
        this.setNullNodeData();
      }
    });
  }

  /**
   * 隐藏所有连接桩
   */
  hideAllPorts() {
    this.graph.getNodes().forEach(node =>
      node.getPorts().forEach(port =>
        node.portProp(port.id, {
          attrs: {
            circle: {
              r: 0,
              // 连接桩在连线交互时不可被连接
              magnet: false,
              fill: '#FFFFFF'
            }
          }
        })
      )
    );
  }

  showAllPorts() {
    this.graph.getNodes().forEach(node =>
      node.getPorts().forEach(port =>
        node.portProp(port.id, {
          attrs: {
            circle: {
              r: 5,
              // 连接桩在连线交互时不可被连接
              magnet: true,
              fill: '#FFFFFF'
            }
          }
        })
      )
    );
  }

  /**
   * 渲染画布
   */
  render() {
    console.log('渲染画布');
  }

  /**
   * TODO 销毁画布
   */
  destroy() {
    if (this.graph) {
      this.graph.dispose();
      console.log('销毁画布');
    }
  }
  /**
   * 设置空的节点选中
   */
  setNullNodeData() {
    let nodeData = {
      nodeId: '',
      groupList: []
    };
    const workflowStore = useWorkflowStore();
    // 设置当前选中是否显示加号
    workflowStore.setNodeData(nodeData);
  }
  /**
   * 获取鼠标当前位置的元素，是否存在
   * @param {*} e
   */
  mousemove(event) {
    const mouseX = event.clientX; // 鼠标当前位置的X坐标
    const mouseY = event.clientY; // 鼠标当前位置的Y坐标

    const element = document.elementFromPoint(mouseX, mouseY);
    if (hasParentWithClass(element, 'workflow-graph-panel')) {
      // 父级存在指定的样式
      this.isSpace = true;
    } else {
      // 父级不存在指定的样式
      this.isSpace = false;
    }

    function hasParentWithClass(element, className) {
      if (!element || !element.parentElement) {
        return false;
      }

      if (element.parentElement.classList.contains(className)) {
        return true;
      }

      return hasParentWithClass(element.parentElement, className);
    }
  }
  /**
   * 空格按下事件
   * @param {*} e
   */
  spaceKeydown(e, isRemove = false) {
    if (e.code === 'Space' && this.isSpace) {
      e.preventDefault(); // 阻止默认行为
      e.stopPropagation();
      this.spaceKeyActive = true;
      if (this.selfProxy.container) {
        this.selfProxy.container.style.cursor = this.upImg;
      }
      this.selectionRef && this.selectionRef.disable(); // 禁用框选功能
      // 如果鼠标左键也被按下，则启用 Scroller 的拖拽功能
      this.graph.enablePanning(); // 启用画布拖动
      this.graph.disableKeyboard(); // 禁用快捷键
      this.graph.cleanSelection(); // 清空选区
      this.graph.clearTransformWidgets(); // 清空拉伸
      this.scrollerRef && this.scrollerRef.unlockScroller();
      // 隐藏操作
      this.workflowNodeToolbar.hide();
      this.workflowEdgeToolbar.hide();
      // 删除所有节点的工具
      const nodes = this.graph.getNodes();
      nodes.forEach(node => {
        if (node.hasTool('button-remove')) {
          node.removeTool('button-remove');
        }
      });
      // 更改小手状态
      if (this.elementScroller[0]) {
        this.elementScroller[0].style.cursor = this.upImg;
      }
      this.setNullNodeData();
      this.setCursor(this.elementShape, isRemove);
      this.setCursor(this.elementImmovable, isRemove);
      this.setCursor(this.elementScroller, 'container', isRemove);
    }
  }
  /**
   * 设置鼠标样式
   * @param {*} elements
   */
  setCursor(elements, container, isRemove = false) {
    for (let i = elements.length - 1; i >= 0; i--) {
      if (!container) {
        elements[i].style.cursor = this.upImg;
      }
      if (isRemove) {
        elements[i].removeEventListener('mousedown', e => this.leftMousedownOrMouseup(e, elements[i], container));
        elements[i].removeEventListener('mouseup', e => this.leftMousedownOrMouseup(e, elements[i], container, true));
      } else {
        elements[i].addEventListener('mousedown', e => this.leftMousedownOrMouseup(e, elements[i], container));
        elements[i].addEventListener('mouseup', e => this.leftMousedownOrMouseup(e, elements[i], container, true));
      }
    }
  }
  /**
   * 鼠标左键按下或抬起事件
   * @param {*} e
   */
  leftMousedownOrMouseup(e, elements, container, type = false) {
    if (this.spaceKeyActive && e.button === 0) {
      if (container) {
        if (this.selfProxy.container) {
          this.selfProxy.container.style.cursor = this.downImg;
          elements.style.cursor = this.downImg;
        }
      } else {
        elements.style.cursor = type ? this.upImg : this.downImg;
      }
    }
  }
  /**
   * 空格抬起事件
   * @param {*} e
   */
  spaceKeyup(e) {
    if (e.code === 'Space' && this.isSpace) {
      this.spaceKeyActive = false;
      this.selectionRef && this.selectionRef.enable(); // 启用框选功能
      this.graph.disablePanning(); // 禁用 Scroller 的拖拽功能
      this.graph.enableKeyboard(); // 启用快捷键
      if (this.selfProxy.container) {
        this.selfProxy.container.style.cursor = 'auto';
      }

      if (this.elementScroller[0]) {
        this.elementScroller[0].style.cursor = 'auto';
      }

      for (let i = 0; i <= this.elementShape.length - 1; i++) {
        this.elementShape[i].style.cursor = 'move';
      }
      for (let i = 0; i <= this.elementImmovable.length - 1; i++) {
        this.elementImmovable[i].style.cursor = 'auto';
      }
    }
  }
  /**
   * 销毁监听事件
   */
  clearEventListenter() {
    document.removeEventListener('mousemove', e => this.mousemove(e));
    document.removeEventListener('keydown', e => this.spaceKeydown(e, true));
    document.removeEventListener('keyup', e => this.spaceKeyup(e));
  }
}
