<template>
  <div id="bloodRelationG6" style="width: 100%;height: 100%;overflow: auto;position: relative"></div>
  <div id="bloodmini-container"></div>
</template>
<script setup>
import G6 from '@antv/g6';
import {watch} from "vue";
const props = defineProps({
  data: {
    type: Object,
    default: () => {}
  },
  currentTable: {
    type:Object,
    default:()=>{}
  }
})
const g6data = ref([])

function initG6() {
  const {
    Util,
    registerBehavior,
    registerEdge,
    registerNode
  } = G6;
  const isInBBox = (point, bbox) => {
    const {
      x,
      y
    } = point;
    const {
      minX,
      minY,
      maxX,
      maxY
    } = bbox;

    return x < maxX && x > minX && y > minY && y < maxY;
  };
  const itemHeight = 20;
  registerBehavior("dice-er-scroll", {
    getDefaultCfg() {
      return {
        multiple: true,
      };
    },
    getEvents() {
      return {
        itemHeight,
        wheel: "scorll",
        click: "click",
        "node:mousemove": "move",
        "node:mousedown": "mousedown",
        "node:mouseup": "mouseup"
      };
    },
    scorll(e) {},
    click(e) {
      const {
        graph
      } = this;
      const item = e.item;
      const shape = e.shape;
      if (!item) {
        return;
      }
if (shape.get("name") === "collapse") {
  graph.updateItem(item, {
    collapsed: true,
    size: [300, 50],
  });
  setTimeout(() => {
    graph.layout();
  }, 50);
} else if (shape.get("name") === "expand") {
  graph.updateItem(item, {
    collapsed: false,
    size: [300, 120],
  });
  setTimeout(() => {
    graph.layout();
  }, 50);
}

else if (shape.get("name") && shape.get("name").startsWith("item")) {
        let edges = graph.getEdges()
        let columnName = ''
        g6data.value.forEach(data => {
          if (data.id === item.getModel().id) {
            columnName = data.attrs[shape.get("name").split("-")[1]].key
          }
        })
        edges.forEach(edg => {
          if (edg.getModel().sourceKey === columnName && edg.getModel().source === item.getModel().id) {
            edg.show()
          } else if(edg.getModel().targetKey === columnName && edg.getModel().target === item.getModel().id){
            edg.show()
          } else{
            edg.hide()
          }
        })
        let nodes = graph.getNodes()
        let index = Number(shape.get("name").split("-")[1])
        nodes.forEach(node => {
          let model = node.getModel()
          model.selectedIndex = NaN
          graph.updateItem(node, model)
        })
        this.graph.updateItem(item, {
          selectedIndex: index,
        });
      } else {
        graph.updateItem(item, {
          selectedIndex: NaN,
        });
        let edges = graph.getEdges()
        edges.forEach(edg => {
          edg.show()
        })
      }
    },
    mousedown(e) {},
    mouseup(e) {},
    move(e) {},
  });

  registerEdge("dice-er-edge", {
    draw(cfg, group) {
      const edge = group.cfg.item;
      const sourceNode = edge.getSource().getModel();
      const targetNode = edge.getTarget().getModel();

      const sourceIndex = sourceNode.attrs.findIndex(
          (e) => e.key === cfg.sourceKey
      );

      const sourceStartIndex = sourceNode.startIndex || 0;

      let sourceY = 15;

      if (!sourceNode.collapsed && sourceIndex > sourceStartIndex - 1) {
        sourceY = 30 + (sourceIndex - sourceStartIndex + 0.5) * itemHeight;
      }

      const targetIndex = targetNode.attrs.findIndex(
          (e) => e.key === cfg.targetKey
      );

      const targetStartIndex = targetNode.startIndex || 0;

      let targetY = 15;

      if (!targetNode.collapsed && targetIndex > targetStartIndex - 1) {
        targetY = (targetIndex - targetStartIndex + 0.5) * itemHeight + 30;
      }

      const startPoint = {
        ...cfg.startPoint
      };
      const endPoint = {
        ...cfg.endPoint
      };

      startPoint.y = startPoint.y + sourceY;
      endPoint.y = endPoint.y + targetY;

      let shape;
      if (sourceNode.id !== targetNode.id) {
        shape = group.addShape("path", {
          attrs: {
            stroke: "#5B8FF9",
            path: [
              ["M", startPoint.x, startPoint.y],
              [
                "C",
                endPoint.x / 3 + (2 / 3) * startPoint.x,
                startPoint.y,
                endPoint.x / 3 + (2 / 3) * startPoint.x,
                endPoint.y,
                endPoint.x,
                endPoint.y,
              ],
            ],
            endArrow: true,
          },
          // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
          name: "path-shape",
        });
      } else {
        let gap = Math.abs((startPoint.y - endPoint.y) / 3);
        if (startPoint["index"] === 1) {
          gap = -gap;
        }
        shape = group.addShape("path", {
          attrs: {
            stroke: "#5B8FF9",
            path: [
              ["M", startPoint.x, startPoint.y],
              [
                "C",
                startPoint.x - gap,
                startPoint.y,
                startPoint.x - gap,
                endPoint.y,
                startPoint.x,
                endPoint.y,
              ],
            ],
            endArrow: props.type === 'er'? {path: G6.Arrow.triangle(10,-10,6),fill:'#5B8FF9'} : false//cfg.endArrow,
          },
          // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
          name: "path-shape",
        });
      }
      return shape;
    },
    afterDraw(cfg, group) {
      const labelCfg = cfg.labelCfg || {};
      const edge = group.cfg.item;
      const sourceNode = edge.getSource().getModel();
      const targetNode = edge.getTarget().getModel();
      if (sourceNode.collapsed && targetNode.collapsed) {
        return;
      }
      const path = group.find(
          (element) => element.get("name") === "path-shape"
      );

      const labelStyle = Util.getLabelPosition(path, 0.5, 0, 0, true);
      const label = group.addShape("text", {
        attrs: {
          ...labelStyle,
          text: cfg.label || '',
          fill: "#000",
          textAlign: "center",
          stroke: "#fff",
          lineWidth: 1,
        },
      });
      label.rotateAtStart(labelStyle.rotate);
    },
  });

  registerNode("dice-er-box", {
    draw(cfg, group) {
      const width = 300;
      const {
        attrs = [],
        startIndex = 0,
        selectedIndex,
        collapsed,
        icon,
      } = cfg;
      let currentTableLabel = props.currentTable.tabEngName
      if (props.currentTable.tabCnName && props.currentTable.tabCnName.length>0){
        currentTableLabel += "("+props.currentTable.tabCnName+")"
      }else if (props.currentTable.tabCrrctName && props.currentTable.tabCnName.tabCrrctName>0){
        currentTableLabel += "("+props.currentTable.tabCrrctName+")"
      }
      const list = attrs;
      const itemCount = list.length;
      const boxStyle = {
        stroke: currentTableLabel === cfg.label?"#67C23A":"#096DD9",
        radius: 4,
      };
      const afterList = list.slice(
          Math.floor(startIndex),
          Math.floor(startIndex + itemCount)
      );
      const offsetY = (0.5 - (startIndex % 1)) * itemHeight + 30;
      //表头盒子
      group.addShape("rect", {
        attrs: {
          fill: boxStyle.stroke,
          height: 30,
          width,
          radius: [boxStyle.radius, boxStyle.radius, 0, 0],
        },
        draggable: true,
      });

      let fontLeft = 12;
      //图标
      if (icon && icon.show !== false) {
        group.addShape("image", {
          attrs: {
            x: 8,
            y: 8,
            height: 16,
            width: 16,
            ...icon,
          },
        });
        fontLeft += 18;
      }
      //表名
      group.addShape("text", {
        attrs: {
          y: 22,
          x: fontLeft,
          fill: "#fff",
          text: cfg.label,
          fontSize: 12,
          fontWeight: 500,
        },
      });

      //展开div
      group.addShape("rect", {
        attrs: {
          x: 0,
          y: collapsed ? 30 : (list.length + 1) * itemHeight + 15,
          height: 15,
          width,
          fill: "#eee",
          radius: [0, 0, boxStyle.radius, boxStyle.radius],
          cursor: "pointer",
        },
        // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
        name: collapsed ? "expand" : "collapse",
      });

      //展开图标
      group.addShape("text", {
        attrs: {
          x: width / 2 - 6,
          y: (collapsed ? 30 : (list.length + 1) * itemHeight + 15) + 12,
          text: collapsed ? "+" : "-",
          width,
          fill: "#000",
          radius: [0, 0, boxStyle.radius, boxStyle.radius],
          cursor: "pointer",
        },
        // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
        name: collapsed ? "expand" : "collapse",
      });
      //表格外框
      const keyshape = group.addShape("rect", {
        attrs: {
          x: 0,
          y: 0,
          width,
          height: collapsed ? 45 : (list.length + 1) * itemHeight + 15 + 15,
          ...boxStyle,
        },
        draggable: true,
      });

      if (collapsed) {
        return keyshape;
      }

      const listContainer = group.addGroup({});
      //字段内容
      listContainer.setClip({
        type: "rect",
        attrs: {
          x: -8,
          y: 30,
          width: width + 16,
          height: (list.length + 1) * itemHeight + 15 - 30,
        },
      });
      //字段背景框
      listContainer.addShape({
        type: "rect",
        attrs: {
          x: 1,
          y: 30,
          width: width - 2,
          height: (list.length + 1) * itemHeight + 15 - 30,
          fill: "#fff",
        },
        draggable: true,
      });
      if (afterList) {
        afterList.forEach((e, i) => {
          const isSelected =
              Math.floor(startIndex) + i === Number(selectedIndex);
          let {
            key = "", type
          } = e;
          if (type) {
            key += " - " + type;
          }
          const label = key;
          //字段框
          listContainer.addShape("rect", {
            attrs: {
              x: 1,
              y: i * itemHeight - itemHeight / 2 + offsetY,
              width: width - 4,
              height: itemHeight,
              radius: 2,
              lineWidth: 1,
              cursor: "pointer",
            },
            // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
            name: `item-${Math.floor(startIndex) + i}-content`,
            draggable: true,
          });
          listContainer.addShape("line", {
            attrs: {
              x1: 0,
              y1: i * itemHeight - itemHeight / 2 + offsetY,
              x2: width,
              y2: i * itemHeight - itemHeight / 2 + offsetY,
              stroke: 'black',
              lineWidth: 0.1,
              cursor: "pointer",
            },
            name: `item-${Math.floor(startIndex) + i}-top-border`,
          });
          //字段文字
          listContainer.addShape("text", {
            attrs: {
              x: 12,
              y: i * itemHeight + offsetY + 6,
              text: label,
              fontSize: 12,
              fill: "#000",
              fontFamily: "Avenir,-apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol",
              full: e,
              fontWeight: isSelected ? 500 : 100,
              cursor: "pointer",
            },
            // must be assigned in G6 3.3 and later versions. it can be any string you want, but should be unique in a custom item type
            name: `item-${Math.floor(startIndex) + i}`,
          });
        });
      }


      return keyshape;
    },
    getAnchorPoints() {
      return [
        [0, 0],
        [1, 0],
      ];
    },
  });

  const dataTransform = (data) => {
    const nodes = [];
    let edges = [];
    data.map((node) => {
      nodes.push({
        ...node
      });
      if (node.attrs) {
        node.attrs.forEach((attr) => {
          if (attr.relation) {
            attr.relation.forEach((relation) => {
              edges.push({
                source: node.id,
                target: relation.nodeId,
                sourceKey: attr.key,
                endArrow: relation.endArrow,
                targetKey: relation.key,
                label: relation.label,
              });
            });
          }

        });
      }
    });
    return {
      nodes,
      edges,
    };
  }

  const container = document.getElementById("bloodRelationG6");
  const mini_container = document.getElementById("bloodmini-container");
const width = container.scrollWidth;
const height = container.scrollHeight || container.offsetHeight || 500;

  // 实例化 minimap 插件
  const minimap = new G6.Minimap({
    size: [200, 200],
    container: mini_container,
    type: 'delegate',
  });
  const graph = new G6.Graph({
    container: container,
    plugins: [minimap],
    width,
    height,
    defaultNode: {
      size: [350, 200],
      type: 'dice-er-box',
      color: '#5B8FF9',
      style: {
        fill: '#9EC9FF',
        lineWidth: 3,
      },
      labelCfg: {
        style: {
          fill: 'black',
          fontSize: 20,
        },
      },
    },
    defaultEdge: {
      type: 'dice-er-edge',
      style: {
        stroke: '#e2e2e2',
        lineWidth: 4,
        endArrow: {path: G6.Arrow.triangle(10,-10,6),fill:'#5B8FF9'},
      },
    },
    modes: {
      default: ['dice-er-scroll', 'drag-node', 'drag-canvas', 'zoom-canvas'],
    },
    layout: {
      type: 'dagre',
      rankdir: 'LR',
      align: 'UL',
      controlPoints: true,
      nodesep: 1,
      ranksep: 1
    },
    animate: true,
    // fitView: true
  })
  graph.data(dataTransform(g6data.value))
  graph.render();
}


watch(
    () => props.data,
    (val) => {
      g6data.value = []
      if (props.data.tableList && props.data.tableList.length>0){
        for (let i = 0; i < props.data.tableList.length; i++) {
          let table = props.data.tableList[i]
          let g6Tab = {
            id: table.ssys_id+"-"+table.mdl_name.toLowerCase()+"-"+table.tab_eng_name.toLowerCase(),
            label: table.tab_eng_name + ((table.tab_cn_name && table.tab_cn_name.length>0)?"("+table.tab_cn_name+")":""),
            attrs:[],
            collapsed:true
            }
          for (let j = 0; j < table.column.length; j++) {
            g6Tab.attrs.push({
              key: table.column[j].fldEngName,
              type: table.column[j].fldType
            })
          }
          g6data.value.push(g6Tab)
        }
        if (props.data.relation && props.data.relation.length>0){
          for (let i = 0; i < props.data.relation.length; i++) {
            let relation = props.data.relation[i]
            let key = relation.targetColName.toLowerCase()
            let tableKey = relation.sourceSysId+"-"+relation.sourceMdlName.toLowerCase()+"-"+relation.sourceTableName.toLowerCase()
            let nodeId = relation.targetSysId+"-"+relation.targetMdlName.toLowerCase()+"-"+relation.targetTableName.toLowerCase()
            if (g6data.value.length > 0){
              for (let j = 0; j < g6data.value.length; j++) {
                if (g6data.value[j].id === tableKey){
                  for (let k = 0; k < g6data.value[j].attrs.length; k++) {
                    if (g6data.value[j].attrs[k].key === relation.sourceColName.toLowerCase()){
                      if (g6data.value[j].attrs[k].relation && g6data.value[j].attrs[k].relation.length>0){
                        let hasRelation = false
                        for (let l = 0; l < g6data.value[j].attrs[k].relation.length; l++) {
                          if (g6data.value[j].attrs[k].relation[l].key === key && g6data.value[j].attrs[k].relation[l].nodeId === nodeId){
                            hasRelation = true
                          }
                        }
                        if (!hasRelation){
                          g6data.value[j].attrs[k].relation.push({
                            key: key,
                            nodeId: nodeId,
                            endArrow: true
                          })
                        }
                      }else {
                        g6data.value[j].attrs[k].relation = [{
                          key: key,
                          nodeId: nodeId,
                          endArrow: true
                        }]
                      }
                    }
                  }
                }
              }
            }
          }
        }

        let g6 = document.getElementById("bloodRelationG6")
        const mini_container = document.getElementById("bloodmini-container");
        if (mini_container){
          mini_container.innerHTML=''
        }
        if (g6){
          g6.innerHTML=''
          initG6()
        }
      }

    },
    { deep: true,immediate: true }
)

</script>

<style scoped lang="scss">
#bloodmini-container{
  position: absolute !important;
  right: 20px;
  bottom: 20px;
  border: 1px solid #e2e2e2;
  border-radius: 4px;
  background-color: rgba(255, 255, 255, 0.9);
  z-index: 10;
}

</style>