<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: 10,
  offsetY: 20,
  getContent(evt) {
    if (!evt) return t('views.monitor.topologyBuild.graphNotInfo');
    const { id, label, neState, neInfoList, neStateMap }: any = evt.item?.getModel();
    //console.log(neInfoList,neState,neInfoList);
    if (notNeNodes.includes(id)) {
      return `<div><span>${label || id}</span></div>`;
    }
    if (!neState) {
      return `<div><span>${label || id}</span></div>`;
    }

    // 获取同类型网元列表
    const sameTypeNes = neInfoList || [];

    // 如果没有网元或只有一个网元，显示原来的信息
    if (sameTypeNes.length <= 1) {
      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>
        `;
    }

    // 如果有多个网元，聚合显示
    let content = `
      <div
      style="
          display: flex;
          flex-direction: column;
          width: 300px;
      "
      >
      <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>`;

    // 为每个同类型网元添加信息
    sameTypeNes.forEach((ne: any, index: number) => {
      // 获取该网元的状态信息
      const neStateInfo = neStateMap?.[ne.neId] ||
        (ne.neId === neState.neId ? neState : {});

      content += `
      <div style="margin-top: 8px;"><strong>${t('views.monitor.topology.name')}：${ne.neName || id + '_' + ne.neId}</strong></div>
      <div><strong>ID：</strong><span>${ne.neId || '--'}</span></div>
      <div><strong>IP：</strong><span>${neStateInfo.neIP || ne.neIP || '--'}</span></div>
      <div><strong>${t('views.monitor.topology.version')}：</strong><span>
      ${neStateInfo.version || ne.version || '--'}
      </span></div>
      <div><strong>${t('views.monitor.topology.serialNum')}：</strong><span>
      ${neStateInfo.sn || ne.sn || '--'}
      </span></div>
      <div><strong>${t('views.monitor.topology.expiryDate')}：</strong><span>
      ${neStateInfo.expire || ne.expire || '--'}
      </span></div>
      <div><strong>${t('views.monitor.topology.state')}：</strong><span>
      ${
        neStateInfo.online !== undefined
          ? (neStateInfo.online
            ? t('views.monitor.topology.normalcy')
            : t('views.monitor.topology.exceptions'))
          : 'undefined'
      }
      </span></div>
      ${index < sameTypeNes.length - 1 ? '<div>------------------------</div>' : ''}
      `;
    });

    content += '</div>';
    return content;
  },
  itemTypes: ['node'],
});



/**图数据渲染 */
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();


  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 - 20
      );
      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 neTypeMap = new Map();
      res.neList.forEach(ne => {
        if (!ne.neType) return;
        if (!neTypeMap.has(ne.neType)) {
          neTypeMap.set(ne.neType, []);
        }
        neTypeMap.get(ne.neType).push(ne);
      });

      // 节点过滤
      const nf: Record<string, any>[] = nodes.filter(
        (node: Record<string, any>) => {
          Reflect.set(node, 'neState', { online: false });
          Reflect.set(node, 'neStateMap', {});  // 初始化状态映射

          // 图片路径处理
          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;

          // 处理非网元节点
          if (notNeNodes.includes(nodeID)) {
            return true;
          }
          //(neTypeMap.get(nodeID),nodeID,node.neState)
          // 处理网元节点
          if (neTypeMap.has(nodeID)) {
            // all NeInfo
            Reflect.set(node, 'neInfoList', neTypeMap.get(nodeID));

            Reflect.set(node, 'neInfo', neTypeMap.get(nodeID)[0] || {});
            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);
          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>
