<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { listAllNeInfo } from '@/api/ne/neInfo';
import { message } from 'ant-design-vue/es';
import { getGraphData } from '@/api/monitor/topology';
import { Graph, GraphData, Tooltip } from '@antv/g6';
import { parseBasePath } from '@/plugins/file-static-url';
import { edgeLineAnimateState } from '@/views/monitor/topologyBuild/hooks/registerEdge';
import { nodeImageAnimateState } from '@/views/monitor/topologyBuild/hooks/registerNode';
import {
  graphG6,
  graphState,
  graphNodeClickID,
  notNeNodes,
} from '../../hooks/useTopology';
import useI18n from '@/hooks/useI18n';
const { t } = useI18n();

/**图DOM节点实例对象 */
const graphG6Dom = ref<HTMLElement | undefined>(undefined);

/**图节点展示 */
const graphNodeTooltip = new Tooltip({
  offsetX: 20,
  offsetY: 20,
  getContent(evt) {
    if (!evt) return t('views.monitor.topologyBuild.graphNotInfo');
    const { id, label, neState }: any = evt.item?.getModel();
    if (notNeNodes.includes(id)) {
      return `<div><span>${label || id}</span></div>`;
    }
    if (!neState) {
      return `<div><span>${label || id}</span></div>`;
    }
    return `
        <div
        style="
            display: flex;
            flex-direction: column;
            width: 200px;
        "
        >
        <div><strong>${t('views.monitor.topology.state')}：</strong><span>
        ${
          neState.online
            ? t('views.monitor.topology.normalcy')
            : t('views.monitor.topology.exceptions')
        }
        </span></div>
        <div><strong>${t('views.monitor.topology.refreshTime')}：</strong><span>
        ${neState.refreshTime ?? '--'}
        </span></div>
        <div>========================</div>
        <div><strong>ID：</strong><span>${neState.neId}</span></div>
        <div><strong>${t('views.monitor.topology.name')}：</strong><span>
        ${neState.neName ?? '--'}
        </span></div>
        <div><strong>IP：</strong><span>${neState.neIP}</span></div>
        <div><strong>${t('views.monitor.topology.version')}：</strong><span>
        ${neState.version ?? '--'}
        </span></div>
        <div><strong>${t('views.monitor.topology.serialNum')}：</strong><span>
        ${neState.sn ?? '--'}
        </span></div>
        <div><strong>${t('views.monitor.topology.expiryDate')}：</strong><span>
        ${neState.expire ?? '--'}
        </span></div> 
        </div>
        `;
  },
  itemTypes: ['node'],
});

/**图绑定事件 */
function fnGraphEvent(graph: Graph) {
  // 节点点击
  graph.on('node:click', evt => {
    // 获得鼠标当前目标节点
    const node = evt.item?.getModel();
    if (node && node.id && !notNeNodes.includes(node.id)) {
      graphNodeClickID.value = node.id;
    }
  });
}

/**图数据渲染 */
function handleRanderGraph(
  container: HTMLElement | undefined,
  data: GraphData
) {
  if (!container) return;
  const { clientHeight, clientWidth } = container;

  edgeLineAnimateState();
  nodeImageAnimateState();

  const graph = new Graph({
    container: container,
    width: clientWidth,
    height: clientHeight - 36,
    fitCenter: true,
    fitView: true,
    fitViewPadding: [20],
    autoPaint: true,
    modes: {
      default: ['drag-canvas', 'zoom-canvas'],
    },
    groupByTypes: false,
    nodeStateStyles: {
      selected: {
        fill: 'transparent',
      },
    },
    plugins: [graphNodeTooltip],
    animate: true, // 是否使用动画过度，默认为 false
    animateCfg: {
      duration: 500, // Number，一次动画的时长
      easing: 'linearEasing', // String，动画函数
    },
  });
  graph.data(data);
  graph.render();

  fnGraphEvent(graph);

  graphG6.value = graph;

  // 创建 ResizeObserver 实例
  var observer = new ResizeObserver(function (entries) {
    // 当元素大小发生变化时触发回调函数
    entries.forEach(function (entry) {
      if (!graphG6.value) {
        return;
      }
      graphG6.value.changeSize(
        entry.contentRect.width,
        entry.contentRect.height - 30
      );
      graphG6.value.fitCenter();
    });
  });
  // 监听元素大小变化
  observer.observe(container);

  return graph;
}

/**
 * 获取图组数据渲染到画布
 * @param reload 是否重载数据
 */
function fnGraphDataLoad(reload: boolean = false) {
  Promise.all([
    getGraphData(graphState.group),
    listAllNeInfo({
      bandStatus: false,
    }),
  ])
    .then(resArr => {
      const graphRes = resArr[0];
      const neRes = resArr[1];
      if (
        graphRes.code === RESULT_CODE_SUCCESS &&
        Array.isArray(graphRes.data.nodes) &&
        graphRes.data.nodes.length > 0 &&
        neRes.code === RESULT_CODE_SUCCESS &&
        Array.isArray(neRes.data) &&
        neRes.data.length > 0
      ) {
        return {
          graphData: graphRes.data,
          neList: neRes.data,
        };
      } else {
        message.warning({
          content: t('views.monitor.topology.noData'),
          duration: 5,
        });
      }
    })
    .then(res => {
      if (!res) return;
      const { combos, edges, nodes } = res.graphData;

      // 节点过滤
      const nf: Record<string, any>[] = nodes.filter(
        (node: Record<string, any>) => {
          Reflect.set(node, 'neState', { online: false });
          // 图片路径处理
          if (node.img) node.img = parseBasePath(node.img);
          if (node.icon.show && node.icon?.img) {
            node.icon.img = parseBasePath(node.icon.img);
          }
          // 遍历是否有网元数据
          const nodeID: string = node.id;
          const hasNe = res.neList.some(ne => {
            Reflect.set(node, 'neInfo', ne.neType === nodeID ? ne : {});
            return ne.neType === nodeID;
          });
          if (hasNe) {
            return true;
          }
          if (notNeNodes.includes(nodeID)) {
            return true;
          }
          return false;
        }
      );

      // 边过滤
      const ef: Record<string, any>[] = edges.filter(
        (edge: Record<string, any>) => {
          const edgeSource: string = edge.source;
          const edgeTarget: string = edge.target;
          const hasNeS = nf.some(n => n.id === edgeSource);
          const hasNeT = nf.some(n => n.id === edgeTarget);
          // console.log(hasNeS, edgeSource, hasNeT, edgeTarget);
          if (hasNeS && hasNeT) {
            return true;
          }
          if (hasNeS && notNeNodes.includes(edgeTarget)) {
            return true;
          }
          if (hasNeT && notNeNodes.includes(edgeSource)) {
            return true;
          }
          return false;
        }
      );

      // 分组过滤
      combos.forEach((combo: Record<string, any>) => {
        const comboChildren: Record<string, any>[] = combo.children;
        combo.children = comboChildren.filter(c => nf.some(n => n.id === c.id));
        return combo;
      });

      // 图数据
      graphState.data = { combos, edges: ef, nodes: nf };
    })
    .finally(() => {
      if (graphState.data.length < 0) return;
      // 重载数据
      if (reload) {
        graphG6.value.read(graphState.data);
      } else {
        handleRanderGraph(graphG6Dom.value, graphState.data);
      }
    });
}

onMounted(() => {
  fnGraphDataLoad(false);
});
</script>

<template>
  <div ref="graphG6Dom" class="chart"></div>
</template>

<style lang="less" scoped>
.chart {
  width: 100%;
  height: 100%;
}
</style>
