<template>
  <div class="container" v-loading="graphLoading">
    <div
      v-if="!graphLoading && Object.keys(treeData)?.length > 0"
      :id="'versionPreview' + versionIndex"
      class="version-container"
    ></div>
    <div v-else-if="!graphLoading" class="w100p flex-center">
      <img class="mt100 w100p h150" src="@/assets/imgs/versionTree/common-no-data.svg" alt="" />
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, nextTick, watchEffect, onBeforeUnmount } from 'vue';
import G6 from '@antv/g6';
import { random } from 'lodash';

interface versionNodeItem {
  label: string;
  isOmit?: boolean;
}

const props = withDefaults(
  defineProps<{
    versionNode:versionNodeItem[];
    treeData: any;
    versionIndex: any;
    graphLoading: boolean;
    currentVersion: string;
    showVisionSelect: boolean;
    showElementList: any;
    showImg: boolean;
    currentNodeIndex: number;
  }>(),
  {
    versionIndex: 0,
    graphLoading: true,
    currentVersion: '',
    showVisionSelect: false,
    showImg: true,
    currentNodeIndex: 1,
  }
);
const emits = defineEmits(['skipRun', 'emitGetCurrentNodeInfo']);
const graph = ref<any>(null);
const versionContainer = ref<any>(null);
watchEffect(() => {
  if (!props.graphLoading) {
    nextTick(() => {
      clearGraph();
      initPreview();
    });
  }
});
// 创建一个新的ResizeObserver实例，并传入一个回调函数
const resizeObserver = new ResizeObserver((entries) => {
  for (const entry of entries) {
    // 每个entry代表一个被观察的元素，并且包含了该元素的大小信息
    // entry.contentRect  输出元素的大小信息
    // 在这里你可以执行任何你需要在元素大小变化时进行的操作
    graph.value?.changeSize(entry.contentRect.width, entry.contentRect.height);
  }
});

const fakeUser = ['admin01', 'pcAdmin', 'user01', 'user02', 'admin02'];

const exampleList = ref<any>([]);
const registerNode = () => {
  G6.registerNode(
    'tree-node',
    {
      drawShape: function drawShape(cfg: any, group: any) {
        exampleList.value.push(cfg.id);
        if (cfg?.id === 'root') {
          const shape = group.addShape('circle', {
            attrs: {
              x: 900,
              y: (120 + props.versionNode.length * 100 + 20) / 2,
              r: 25,
              fill: '#409eff',
            },
            name: 'circle-shape-root',
          });
          return shape;
        } else {
          const shape = group.addShape('rect', {
            attrs: {
              x: 0,
              y: 0,
              width: 900,
              height: 120 + props.versionNode.length * 100 + 20,
              fill: props.currentVersion === cfg.id || props.currentVersion === cfg.name ? '#447dfd' : '#ecf7ff',
              radius: [15, 15, 15, 15],
              lineWidth: props.currentVersion === cfg.id || props.currentVersion === cfg.name ? 20 : 5,
            },
            name: 'node-box',
            draggable: true,
          });
          group.addShape('rect', {
            attrs: {
              x: 10,
              y: 10,
              width: 880,
              height: 120,
              fill: '#409eff',
              radius: [15, 15, 0, 0],
              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: 'box-title',
            draggable: true,
          });

          group.addShape('text', {
            attrs: {
              text: setOmitString(cfg.name, 28),
              x: 440,
              y: 75,
              textAlign: 'center',
              textBaseline: 'middle',
              fill: '#fff',
              fontSize: 50,
              cursor: 'pointer',
            },
            name: 'version-title',
          });
          props.versionNode?.forEach((item: any, index:any) => {
            group.addShape('rect', {
              attrs: {
                x: 10,
                y: 120 + 100 * index + 10,
                width: 880,
                height: 100,
                fill: index % 2 == 0 ? '#f0f5f9' : '#fff',
                radius: index == props.versionNode.length - 1 ? [0, 0, 15, 15] : 0,
              },
              name: `${item.label}_content-item-left-tooltip_${index}`,
              draggable: true,
            });
            group.addShape('text', {
              attrs: {
                text: item.chineseLabel ? item.chineseLabel + ':' : item.label + ':',
                x: 60,
                y: 120 + 100 * index + 50 + 10,
                textAlign: 'left',
                marginLeft: '10px',
                textBaseline: 'middle',
                fill: '#000',
                fontSize: 40,
              },
              // 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.label}_content-title-tooltip_${index}`,
            });
            let textContent = '';
            let xData: number;
            switch (item.label) {
              case 'user':
                group.addShape('image', {
                  attrs: {
                    x: 310,
                    y: 130 + 100 * index + 22,
                    width: 50,
                    height: 50,
                    img: '',
                  },
                  // 在 G6 3.3 及之后的版本中，必须指定 name，可以是任意字符串，但需要在同一个自定义元素类型中保持唯一性
                  name: 'image-shape' + index,
                });
                xData = 360;
                textContent = fakeUser[random(0, 4)];
                break;
              case 'creator':
                group.addShape('image', {
                  attrs: {
                    x: 310,
                    y: 130 + 100 * index + 22,
                    width: 50,
                    height: 50,
                    img: '',
                  },
                  // 在 G6 3.3 及之后的版本中，必须指定 name，可以是任意字符串，但需要在同一个自定义元素类型中保持唯一性
                  name: 'image-shape' + index,
                });
                xData = 360;
                textContent = cfg.creator;
                break;
              case 'taskStatus':
                group.addShape('circle', {
                  attrs: {
                    x: 330,
                    y: 130 + 100 * index + 45,
                    r: 20,
                    fill: cfg.taskStatus?.color,
                  },
                  // 在 G6 3.3 及之后的版本中，必须指定 name，可以是任意字符串，但需要在同一个自定义元素类型中保持唯一性
                  name: 'circle-shape' + index,
                });
                xData = 360;
                textContent = cfg.taskStatus?.name;
                break;
              default:
                xData = 310;
                textContent = item?.omitLength > 0 ? setOmitString(cfg[item.label], item.omitLength) : cfg[item.label];
            }

            group.addShape('text', {
              attrs: {
                text: textContent,
                x: xData,
                y: 130 + 100 * index + 50,
                textAlign: 'left',
                textBaseline: 'middle',
                fill: '#000',
                fontSize: 40,
                fontWeight: 5,
              },
              // 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.label}_content-value-tooltip_${index}`,
            });
            if (cfg.resultLoadcaseId) {
              // console.log(cfg, 'cfg');
              group.addShape('image', {
                attrs: {
                  x: 720,
                  y: 40,
                  width: 60,
                  height: 60,
                  img: 'StarIcon_Green',
                },
                // 在 G6 3.3 及之后的版本中，必须指定 name，可以是任意字符串，但需要在同一个自定义元素类型中保持唯一性
                name: 'image-result-loadcase-optimize',
              });
            }
            if (props.showImg) {
              group.addShape('image', {
                attrs: {
                  x: 800,
                  y: 40,
                  width: 60,
                  height: 60,
                  img: '',
                  cursor: 'pointer',
                },
                // 在 G6 3.3 及之后的版本中，必须指定 name，可以是任意字符串，但需要在同一个自定义元素类型中保持唯一性
                name: 'image-skip',
              });
            }
          });

          return shape;
        }
      },
      update: (cfg:any, item:any) => {
        const group = item.getContainer();
        const icon = group.find((e:any) => e.get('name') === 'collapse-icon');
        icon?.attr('symbol', cfg.collapsed ? G6.Marker.expand : G6.Marker.collapse);
      },
    },
    'single-node'
  );
};
const tooltip = new G6.Tooltip({
  offsetX: 10,
  offsetY: 20,
  getContent(e: any) {
    // let key = e.target.cfg.name.split('_').shift();
    // const outDiv = document.createElement('div');
    // // if (key === 'name' || key === 'Description') {
    // //   outDiv.innerHTML = `<h4>${e.item._cfg.model[key]}</h4>`;
    // // }
    // if (!props.showElementList || props.showElementList?.includes(key)) {
    //   if (key === 'taskStatus') {
    //     outDiv.innerHTML = `<h4>${e.item._cfg.model[key]?.name}</h4>`;
    //   } else {
    //     outDiv.innerHTML = `<h4>${e.item._cfg.model[key]}</h4>`;
    //   }
    // }
    let name = '';
    if (e.target.cfg.name === 'image-skip') {
      name = '跳转到该任务';
    } else if (e.target.cfg.name === 'image-result-loadcase-original') {
      name = '跳转到该任务';
    } else if (e.target.cfg.name === 'image-result-loadcase-optimize') {
      name = '跳转到该任务';
    }
    const outDiv = document.createElement('div');

    outDiv.innerHTML = `<h4>${name}</h4>`;
    return outDiv;
  },
  shouldBegin(e: any) {
    return (
      e.target.cfg.name === ''
      // ||
      // e.target.cfg.name === 'image-result-loadcase-original' ||
      // e.target.cfg.name === 'image-result-loadcase-optimize'
    );
  },
  itemTypes: ['node'],
});
const initPreview = () => {
  registerNode();
  nextTick(() => {
    versionContainer.value = document.getElementById('versionPreview' + props.versionIndex) as any;
    const width = versionContainer.value.scrollWidth;
    const height = versionContainer.value.scrollHeight || 500;
    // 使用observe方法开始观察myDiv元素
    resizeObserver?.observe(versionContainer.value);
    graph.value = new G6.TreeGraph({
      container: 'versionPreview' + props.versionIndex,
      width,
      height,
      modes: {
        default: ['drag-canvas', 'zoom-canvas'],
      },
      plugins: [tooltip],
      defaultNode: {
        type: 'tree-node',
        anchorPoints: [
          [1, 0.5],
          [0, 0.5],
        ],
      },
      defaultEdge: {
        type: 'cubic-horizontal',
        style: {
          stroke: '#A3B1BF',
          lineWidth: 5,
          // 自定义圆形箭头样式
          // startArrow: {
          //   path: 'M 0,0  a 20,20 0 1 1 40,0 a 20,20 0 1 1 -40,0', // SVG 圆形路径
          //   fill: '#ff0000', // 箭头填充颜色
          //   stroke: '#ff0000', // 箭头描边颜色
          // },
          endArrow: {
            path: G6.Arrow.vee(20, 10, 0), // 使用内置箭头路径函数，参数为箭头的 宽度、长度、偏移量（默认为 0，与 d 对应）
            d: 0,
          },
        },
      },
      nodeStateStyles: {
        selected: {
          stroke: '#447dfd',
          lineWidth: 10,
        },
      },
      layout: {
        type: 'compactBox',
        direction: 'LR',
        getId: function getId(d: any) {
          return d.id;
        },
        getHeight: function getHeight() {
          return 160;
        },
        getWidth: function getWidth() {
          return 160;
        },
        getVGap: function getVGap() {
          return props.versionNode.length * 80;
        },
        getHGap: function getHGap() {
          return 500;
        },
      },
    });
    // G6.Util.traverseTree(props.treeData, function (item: any) {
    //   item.id = item.id + '';
    // });
    graph.value.data(props.treeData);
    graph.value.render();
    graph.value.zoom(0.15);
    graph.value.fitCenter();
    defaultCurrentNodeInfo(props.currentNodeIndex);

    // 给形状添加 mousemove 事件监听器
    // graph.value.on('box-title:dblclick', skipRun);
    // graph.value.on('version-title:dblclick', skipRun);

    graph.value.on('box-title:click', emitGetCurrentNodeInfo);
    // graph.value.on('version-title:click', emitGetCurrentNodeInfo);

    graph.value.on('image-skip:click', skipRun);
    graph.value.on('image-skip:click', emitGetCurrentNodeInfo);
  });
};
const skipRun = (e: any) => {
  console.log('1335', e);
  const nodeInfo = e.item._cfg.model;
  emits('skipRun', {
    ...nodeInfo,
  });
};

const emitGetCurrentNodeInfo = (e: any) => {
  const nodeInfo = e.item._cfg.model;
  const item = e.item;
  const nodeList = graph.value.getNodes();

  if (props.showVisionSelect) {
    for (let i = 0; i < nodeList.length; i++) {
      graph.value.clearItemStates(nodeList[i]);
    }
    graph.value.setItemState(item, 'selected', true);
  }
  emits('emitGetCurrentNodeInfo', nodeInfo);
};

// 默认选中除root以外的第一个节点
const defaultCurrentNodeInfo = (index?: number) => {
  const nodeList = graph.value.getNodes();
  for (let i = 0; i < nodeList.length; i++) {
    graph.value.clearItemStates(nodeList[i]);
    nodeList[i]._cfg.model.index = i;
  }
  if (props.showVisionSelect) {
    let nodeInfo: any;
    if (index) {
      nodeInfo = nodeList[index]._cfg.model;
    } else {
      nodeInfo = nodeList[1]._cfg.model;
    }

    if (!props.graphLoading) {
      graph.value.setItemState(index ? nodeList[index] : nodeList[1], 'selected', true);
      emits('emitGetCurrentNodeInfo', nodeInfo);
    }
  }
};

const clearGraph = () => {
  graph.value?.clear();
  graph.value?.destroy();
  // graph.value?.off('box-title:dblclick', skipRun);
  // graph.value?.off('version-title:dblclick', skipRun);

  graph.value?.off('box-title:click', emitGetCurrentNodeInfo);
  // graph.value?.off('version-title:click', emitGetCurrentNodeInfo);\

  graph.value?.off('image-skip:click', skipRun);
  graph.value?.off('image-skip:click', emitGetCurrentNodeInfo);
};

const setOmitString = (text: string, intercept: number) => {
  if (!text) {
    return '';
  } else if (text.length > intercept) {
    return text.slice(0, intercept) + '...';
  } else {
    return text;
  }
};

onBeforeUnmount(() => {
  // versionContainer.value &&
  if (versionContainer.value) {
    resizeObserver?.unobserve(versionContainer.value);
  }
  clearGraph();
});
</script>

<style lang="scss" scoped>

.container {
  height: 100%;
  width: 100%;
  .version-container {
    height: 100%;
    width: 100%;
    :deep(.ellipsis-text) {
      text-overflow: ellipsis; /* 当内容溢出容器时显示省略号 */
      overflow: hidden; /* 隐藏溢出容器的内容 */
      white-space: nowrap; /* 防止文字换行 */
      /* 可能还需要设置宽度和高度，以确保容器大小合适 */
      width: 100% /* 合适的宽度 */;
      height: 100% /* 合适的高度 */;
    }
  }
}

.ellipsis-text {
  text-overflow: ellipsis;
  /* 当内容溢出容器时显示省略号 */
  overflow: hidden;
  /* 隐藏溢出容器的内容 */
  white-space: nowrap;
  /* 防止文字换行 */
  /* 可能还需要设置宽度和高度，以确保容器大小合适 */
  width: 100% /* 合适的宽度 */;
  height: 100% /* 合适的高度 */;
}

.tag-red {
  background-color: #fae4e5;
  color: #d8232a;
}

.tag-cancle {
  background-color: #fae4e5;
  color: #ac848f;
}

.tag-green {
  background-color: #e0f6eb;
  color: #1eaa39;
}

.tag-blue {
  background-color: #e7f1ff;
  color: #2580fe;
}

.tag-brown {
  background-color: #fbe1d2;
  color: #f29600;
}

.tag-gray {
  background-color: #eceef1;
  color: #888b9c;
}
</style>
