import { Addon, Graph, Shape, FunctionExt } from "@antv/x6";
import "./shape";

export default class FlowGraph {
  static init({ groups = [] } = {}) {
    this.graph = new Graph({
      container: document.getElementById("flowContainer"),
      background: { color: "#e8edf1" },
      grid: {
        size: 20,
        visible: true,
        type: "mesh",
        args: {
          color: "#dee3e8", // 网格线/点颜色
        },
      },
      panning: {
        enabled: true,
      },
      // 鼠标滚轮
      mousewheel: {
        enabled: true,
        modifiers: ["ctrl", "meta"],
        minScale: 0.5,
        maxScale: 2,
      },
      selecting: {
        enabled: true,
        multiple: true,
        rubberEdge: true,
        rubberNode: true,
        modifiers: "shift",
        // showNodeSelectionBox: true,
      },
      connecting: {
        snap: true,
        allowBlank: false,
        allowLoop: false,
        highlight: true,
        connectionPoint: "anchor",
        anchor: "center",
        createEdge() {
          return new Shape.Edge({
            attrs: {
              line: {
                stroke: "#000",
                strokeWidth: 2,
                targetMarkder: {
                  name: "classic",
                  size: 8,
                },
              },
            },
            router: {
              name: "manhattan",
            },
          });
        },
      },
      validateConnection({
        sourceView,
        targetView,
        sourceMagnet,
        targetMagnet,
      }) {
        if (sourceView === targetView) return false;
        if (!sourceMagnet) return false;
        return !!targetMagnet;
      },
      highlighting: {
        magnetAvailable: {
          name: "stroke",
          args: {
            padding: 4,
            attrs: {
              strokeWidth: 4,
              stroke: "rgba(223, 234, 255)",
            },
          },
        },
      },
      snapline: true,
      history: true,
      clipboard: {
        enabled: true,
      },
      keyboard: {
        enabled: true,
      },
      embedding: {
        enabled: true,
        findParent({ node }) {
          const bbox = node.getBBox();
          return this.getNodes().filter((item) => {
            // 只有data.parent为true的节点才是父节点
            const data = item.getData();
            if (data?.parent) {
              const targetBox = item.getBBox();
              return bbox.isIntersectWithRect(targetBox);
            }
            return false;
          });
        },
      },
      // onPortRendered(args) {
      //   const selectors = args.contentSelectors;
      //   const container = selectors && selectors.foContent;
      //   if (container) {
      //     const dom = document.createElement("div");
      //     dom.setAttribute("class", "my-port");
      //     container.appendChild(dom);
      //   }
      // },
    });
    this.initToolBox(groups);
    this.initShape(groups);
    this.initEvent();
    return this.graph;
  }

  // 初始化工具箱
  static initToolBox(_groups) {
    const groups = _groups.map((item) => {
      const { nodeList = [], categoryLabel, categoryValue } = item;
      const graphHeight = nodeList?.length ? 80 * nodeList.length + 15 + 5 : 0;
      return {
        name: categoryValue,
        title: categoryLabel,
        graphHeight,
        layoutOptions: {
          columns: 1,
          marginX: 60,
        },
      };
    });

    this.toolBox = new Addon.Stencil({
      title: "Component",
      target: this.graph,
      search(cell, keyword) {
        if (keyword) {
          return (
            cell.attrs?.text?.text?.includes(keyword) ||
            cell.attrs?.title?.text?.includes(keyword)
          );
        }
        return true;
      },
      stencilGraphWidth: 260,
      collapsable: true,
      stencilGraphOptions: {
        background: { color: "#ffffff" },
      },
      groups,
    });
    const toolBoxContainer = document.getElementById("toolbox");
    // eslint-disable-next-line no-unused-expressions
    toolBoxContainer
      ? toolBoxContainer.appendChild(this.toolBox.container)
      : "";
  }

  // 创建节点
  static initShape(_groups) {
    const { graph } = this;
    _groups.forEach((item) => {
      const arr = [];
      item.nodeList?.forEach((e, i) => {
        const color = e.nodeType === "COMPONENT" ? "#005087" : "#00DC99";
        arr.push(
          graph.createNode({
            shape: "custom-node",
            data: e,
            attrs: {
              head: {
                fill: color,
                stroke: color,
              },
              divide: {
                fill: color,
                stroke: color,
              },
              title: {
                text: e.nodeKey,
              },
              text: {
                text: e.nodeName,
              },
            },
          })
        );
      });

      this.toolBox.load(arr, item.categoryValue);
    });
  }

  static initGraphData(graphData) {
    this.graph.fromJSON(graphData);
  }

  static showPorts(ports, show) {
    for (let i = 0, len = ports.length; i < len; i += 1) {
      // eslint-disable-next-line no-param-reassign
      ports[i].style.visibility = show ? "visible" : "hidden";
    }
  }

  static initEvent() {
    const { graph } = this;
    const container = document.getElementById("flowContainer");
    graph.on(
      "node:mouseenter",
      FunctionExt.debounce(() => {
        const ports = container.querySelectorAll(".x6-port-body");
        this.showPorts(ports, true);
      }),
      500
    );
    graph.on("node:mouseleave", () => {
      const ports = container.querySelectorAll(".x6-port-body");
      this.showPorts(ports, false);
    });

    graph.bindKey("backspace", () => {
      const cells = graph.getSelectedCells();
      if (cells.length) {
        graph.removeCells(cells);
      }
    });

    graph.on("edge:mouseenter", (event) => {
      event.edge.addTools([
        {
          name: "button-remove",
        },
      ]);
    });

    graph.on("edge:mouseleave", (event) => {
      event.edge.removeTools();
    });
  }

  // 销毁
  static destroy() {
    this.graph.dispose();
  }
}
