<template>
  <div class="org-chart-container" ref="container"></div>
</template>

<script setup lang="ts">
  import { ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue';
  import { Graph, treeToGraphData, NodeEvent, CanvasEvent } from '@antv/g6';
  // import { Graph, treeToGraphData, register, ExtensionCategory, NodeEvent, Polyline, CanvasEvent } from '@antv/g6';

  /**
   * @description: 为了确保图的正确渲染和交互，建议按照 G6 标准数据结构组织数据。
   * 每个元素（节点、边、组合）应包含一个 data 字段，用于存放业务数据和自定义属性。
   */

  // 定义 props 接口
  interface TreeData {
    id: string;
    data: { name: string };
    children?: TreeData[];
  }

  const props = defineProps<{
    treeData: TreeData;
  }>();

  const emits = defineEmits<{
    (event: 'node-click', nodeData: any): void;
    (event: 'canvas-click'): void;
  }>();

  let data = treeToGraphData(props.treeData); // 通过 treeToGraphData 方法，将树形结构数据转换为 G6 的标准数据结构
  const container = ref<HTMLDivElement | null>(null); // 图表容器引用
  let graph: any = null;
  let pending = false; // 防止并发 initGraph

  // 初始化图表
  const initGraph = async () => {
    if (pending || !container.value) return;
    pending = true;

    // 销毁旧实例
    if (graph) {
      graph.off();
      graph.destroy();
      graph = null;
    }

    // 等待下一帧，确保销毁完成
    await nextTick();

    // 创建新的 G6 实例
    graph = new Graph({
      container: container.value,
      padding: [20, 20, 20, 20], // 图表内边距
      data,
      node: {
        type: 'rect', // 使用内置的矩形节点类型
        style: {
          labelText: (d: any) => d.data.name, // 节点文本
          labelFill: '#333', // 文本颜色
          labelFontSize: 14, // 文本大小
          size: [250, 50],
          lineWidth: 1, // 边框宽度
          // lineDash: [5, 5], // 虚线边框
          stroke: '#1777FF', // 边框色
          fill: '#E7F1FF', // 填充色
          radius: 8,
          labelPlacement: 'center',
          ports: [{ placement: 'top' }, { placement: 'bottom' }],
        },
        // 节点状态样式
        state: {
          selected: {
            fill: '#1777FF',
            stroke: '#1777FF',
            lineWidth: 1,
            labelFill: '#fff', // 选中状态下文本颜色
            labelFontSize: 16, // 选中状态下文本大小
          },
        },
      },
      edge: {
        type: 'ant-line', // 边类型
        style: {
          stroke: '#1777FF', // 边的颜色
          lineWidth: 1, // 边的宽度
          lineDash: [10, 10],
          endArrow: true, // 是否有箭头
          router: {
            type: 'orth',
          },
        },
      },
      layout: {
        type: 'dagre',
        nodesep: 100,
        ranksep: 120,
        preventOverlap: true, // 防止节点重叠
        nodeStrength: -50, // 节点之间的斥力
        edgeStrength: 0.5, // 边的弹性系数
        iterations: 200, // 迭代次数
        animation: true, // 启用布局动画
      },
      autoFit: {
        type: 'center', // 自适应类型：'view' 或 'center'
        // options: {
        //   // 仅适用于 'view' 类型
        //   when: 'always', // 何时适配：'overflow'(仅当内容溢出时) 或 'always'(总是适配)
        //   direction: 'both', // 适配方向：'x'、'y' 或 'both'
        // },
        // animation: {
        //   // 自适应动画效果
        //   duration: 1000, // 动画持续时间(毫秒)
        //   easing: 'ease-in-out', // 动画缓动函数
        // },
      },
      autoResize: true, // 自动调整大小
      behaviors: [
        'drag-canvas',
        {
          type: 'zoom-canvas',
          sensitivity: 0.5, // 配置灵敏度
          key: 'zoom-behavior', // 为交互指定key，便于后续更新
        },
        'focus-element',
        {
          type: 'click-select',
          state: 'selected',
          unselectedState: 'inactive',
          multiple: true,
          trigger: ['shift'],
        },
      ],
    });

    // 渲染
    graph.render();

    // 监听节点点击事件
    graph.on(NodeEvent.CLICK, (evt) => {
      const { target } = evt;
      const nodeData = graph.getNodeData(target.id); // 获取节点数据
      emits('node-click', nodeData);
    });

    graph.on(CanvasEvent.CLICK, () => {
      graph?.fitCenter();
      emits('canvas-click');
    });

    window.addEventListener('resize', handleResize);

    pending = false;
  };

  // 处理窗口大小变化
  const handleResize = () => {
    if (graph && container.value) {
      graph.resize(container.value.offsetWidth, container.value.offsetHeight);
      graph.fitCenter();
    }
  };

  // 监听 treeData 变化
  watch(
    () => props.treeData,
    () => {
      data = treeToGraphData(props.treeData);
      initGraph();
    },
    { deep: true },
  );

  // 生命周期钩子
  onMounted(() => {
    data = treeToGraphData(props.treeData);
    initGraph();
  });

  onBeforeUnmount(() => {
    window.removeEventListener('resize', handleResize);
    if (graph) {
      graph.off(); // 移除所有事件监听
      graph.destroy();
      graph = null;
    }
  });
</script>

<style lang="scss" scoped>
  .org-chart-container {
    width: 100%;
    height: 100%;
  }
</style>
