<template>
  <div>
    <div ref="g6Dom" :style="{ height: height, width: width }"></div>
    <button @click="actions['Enable/Disable Node States'].Breathing()">
      Breathing()
    </button>
    <button @click="actions['Enable/Disable Node States'].Scaling()">
      Scaling()
    </button>

    <button @click="actions['Enable/Disable Edge States'].Growing()">
      Growing()
    </button>
    <button @click="actions['Enable/Disable Edge States'].Running()">
      Running()
    </button>
  </div>
</template>

<script lang="ts" setup>
import { nextTick, watch, onMounted, onBeforeUnmount, ref } from 'vue';
import { Graph, extend, Extensions } from '@antv/g6';

const props = defineProps({
  /**
   * 图表主题
   *
   * 'dark' | 'light'
   */
  theme: {
    type: String,
    default: 'light', // 'dark' | 'light'
  },
  /**宽度，默认100% */
  width: {
    type: String,
    default: '100%',
  },
  /**高度 */
  height: {
    type: String,
    default: '500px',
  },
});

const g6Dom = ref<HTMLElement | undefined>(undefined);

const ExtGraph = extend(Graph, {
  // layouts: {
  //   dagre: Extensions.DagreLayout,
  // },
  edges: {
    'polyline-edge': Extensions.PolylineEdge,
    'cubic-edge': Extensions.CubicEdge,
    // 'custom-edge': Extensions.CubicEdge,
  },
});

const data = {
  nodes: [
    // 0 基站
    {
      id: '0',
      data: {
        x: 80,
        y: 150,
        type: 'circle-node',
        color: '#fffff',
        keyShape: {
          r: 24,
          width: 48,
          height: 48,
          fill: '#9EC9FF',
          stroke: '#5B8FF9',
          lineWidth: 2,
        },
        labelShape: {
          text: '基站',
          position: 'bottom',
          maxWidth: '200%',
          offsetY: 10,
        },
        labelBackgroundShape: {},
        iconShape: {
          img: 'https://gw.alipayobjects.com/zos/basement_prod/012bcf4f-423b-4922-8c24-32a89f8c41ce.svg',
          width: 24,
          height: 24,
        },
      },
    },
    // 1 DM
    {
      id: '1',
      data: {
        label: 'DM',
        x: 600,
        y: 350,
      },
    },
    // 2 O&M
    {
      id: '2',
      data: {
        label: 'O&M',
        x: 900,
        y: 100,
      },
    },
    // 5GC控制面
    {
      id: '170',
      data: {
        label: 'NSSF',
        parentId: 'combo-5gc',
        x: 300,
        y: 50,
      },
    },
    {
      id: '130',
      data: {
        label: 'AUSF',
        parentId: 'combo-5gc',
        x: 400,
        y: 50,
      },
    },
    {
      id: '140',
      data: {
        label: 'UDM',
        parentId: 'combo-5gc',
        x: 500,
        y: 50,
      },
    },
    {
      id: '120',
      data: {
        label: 'AMF',
        parentId: 'combo-5gc',
        x: 300,
        y: 150,
      },
    },
    {
      id: '180',
      data: {
        label: 'NRF',
        parentId: 'combo-5gc',
        x: 400,
        y: 150,
      },
    },
    {
      id: '150',
      data: {
        label: 'SMF',
        parentId: 'combo-5gc',
        x: 500,
        y: 250,
      },
    },
    {
      id: '160',
      data: {
        label: 'PCF',
        parentId: 'combo-5gc',
        x: 600,
        y: 250,
      },
    },
    // 5GC用户面
    {
      id: '190',
      data: {
        label: 'UPF',
        parentId: 'combo-upf',
        x: 300,
        y: 350,
      },
    },
    // EP-IMS
    {
      id: '110',
      data: {
        label: 'I/S-CSCF',
        parentId: 'combo-ims',
        x: 800,
        y: 350,
      },
    },
    {
      id: '111',
      data: {
        label: 'P-CSCF',
        parentId: 'combo-ims',
        x: 800,
        y: 400,
      },
    },
    // O&M
    {
      id: '100',
      data: {
        label: 'EMS',
        parentId: 'combo-ems',
        x: 800,
        y: 100,
      },
    },
  ],
  edges: [
    {
      id: '0-5gc',
      source: '0',
      target: 'combo-5gc',
      data: {
        type: 'cubic-edge',
        animates: {
          update: [
            {
              // 在 selected 和 active 状态变化导致的 haloShape opacity 变化时，使 opacity 带动画地更新
              fields: ['opacity'],
              shapeId: 'haloShape',
              states: ['selected', 'active'],
              duration: 500,
            },
          ],
        },
      },
    },
    {
      id: '5gc-ems',
      source: 'combo-5gc',
      target: 'combo-ems',
      data: {},
    },
    {
      id: 'upf-ems',
      source: 'combo-upf',
      target: 'combo-ems',
      data: {},
    },
    {
      id: 'ims-ems',
      source: 'combo-ims',
      target: 'combo-ems',
      data: {},
    },
    {
      id: 'ems-2',
      source: 'combo-ems',
      target: '2',
      data: {},
    },
    {
      id: '170-120',
      source: '170',
      target: '120',
      data: {},
    },
    {
      id: '130-120',
      source: '130',
      target: '120',
      data: {},
    },
    {
      id: '140-120',
      source: '140',
      target: '120',
      data: {},
    },
    {
      id: '140-180',
      source: '140',
      target: '180',
      data: {},
    },
    {
      id: '120-180',
      source: '120',
      target: '180',
      data: {
        type: 'polyline-edge',
        keyShape: {
          endArrow: true,
          routeCfg: {
            /**
             * 目前支持正交路由 'orth' 和地铁路由 'er'
             */
            // name: 'er',
            /**
             * 是否开启自动避障，默认为 false
             * Whether to enable automatic obstacle avoidance, default is false
             */
            enableObstacleAvoidance: true,
          },
          /**
           * 拐弯处的圆角弧度，默认为直角，值为 0
           * The radius of the corner rounding, defaults to a right angle
           */
          // radius: 20,
          /**
           * 拐弯处距离节点最小距离, 默认为 2
           * Minimum distance from the node at the corner, default is 5.
           */
          // offset: 0,
          /**
           * 控制点数组，不指定时根据 A* 算法自动生成折线。若指定了，则按照 controlPoints 指定的位置进行弯折
           * An array of control points that, when not specified, automatically generates the bends according to the A* algorithm. If specified, bends are made at the position specified by controlPoints.
           */
          // controlPoints: [],
        },
      },
    },
    {
      id: '130-180',
      source: '130',
      target: '180',
      data: {
        type: 'polyline-edge',
      },
    },
    {
      id: '140-150',
      source: '140',
      target: '150',
      data: {
        type: 'polyline-edge',
      },
    },
    {
      id: '140-110',
      source: '140',
      target: '110',
      data: {
        type: 'polyline-edge',
      },
    },
    {
      id: '120-150',
      source: '120',
      target: '150',
      data: {},
    },
    {
      id: '150-180',
      source: '150',
      target: '180',
      data: {},
    },
    {
      id: '150-160',
      source: '150',
      target: '160',
      data: { type: 'polyline-edge' },
    },
    {
      id: '160-120',
      source: '160',
      target: '120',
      data: {},
    },
    {
      id: '160-180',
      source: '160',
      target: '180',
      data: {
        keyShape: {
          endArrow: true,
        },
        labelShape: {
          text: 'asdf-arrow',
        },
      },
    },
    {
      id: '160-111',
      source: '160',
      target: '111',
      data: {},
    },
    {
      id: '0-upf',
      source: '0',
      target: 'combo-upf',
      data: {},
    },
    {
      id: '150-190',
      source: '150',
      target: '190',
      data: {},
    },
    {
      id: 'upf-1',
      source: 'combo-upf',
      target: '1',
      data: {},
    },
    {
      id: 'upf-ims',
      source: 'combo-upf',
      target: 'combo-ims',
      data: {},
    },
  ],
  combos: [
    {
      id: 'combo-5gc',
      data: {
        text: '5GC控制面',
      },
    },
    {
      id: 'combo-upf',
      data: {
        label: '5GC用户面',
      },
    },
    {
      id: 'combo-ims',
      data: {
        label: 'EP-IMS用户面',
      },
    },
    {
      id: 'combo-ems',
      data: {
        label: 'EMS',
      },
    },
  ],
};
let graph: any = null;
/**初始化渲染图表 */
function initChart() {
  if (!g6Dom.value) return;
  graph = new ExtGraph({
    container: g6Dom.value,
    height: 500,
    plugins: [
      {
        // lod-controller will be automatically assigned to graph with `disableLod: false` to graph if it is not configured as following
        type: 'lod-controller',
        disableLod: true,
      },
    ] as any,
    modes: {
      default: [
        {
          type: 'drag-node',
          enableTransient: false,
          updateComboStructure: false,
        },
        {
          type: 'click-select',
          itemTypes: ['node', 'edge', 'combo'],
        },
        {
          type: 'drag-combo',
          enableTransient: true,
          updateComboStructure: true,
        },
        // 'drag-combo',
        'drag-canvas',
        // 'click-select',
        'zoom-canvas',
      ] as any,
    },

    theme: {
      type: 'spec',
      base: 'light',
      specification: {
        node: {
          dataTypeField: 'parentId',
        },
      },
    } as any,
    // 全局节点 矩形
    node: model => {
      const { id, data } = model;
      return {
        id,
        data: {
          type: 'rect-node',
          keyShape: {
            width: 80,
            height: 40,
            radius: 8,
          },
          labelShape: {
            position: 'center',
            text: data.label,
          },
          animates: {
            update: [
              {
                fields: ['opacity'],
                shapeId: 'haloShape',
                states: ['breathing'],
                iterations: Infinity,
                direction: 'alternate',
                duration: 500,
              },
              {
                fields: ['lineWidth'],
                shapeId: 'keyShape',
                states: ['breathing'],
                iterations: Infinity,
                direction: 'alternate',
                duration: 500,
              },
              {
                fields: ['height', 'width'],
                shapeId: 'keyShape',
                states: ['scaling'],
                iterations: Infinity,
                direction: 'alternate',
                duration: 500,
              },
            ],
          },
          ...data,
        },
      };
    },
    // 全局边 三次贝塞尔曲线
    edge: model => {
      const { id, source, target, data } = model;
      return {
        id,
        source,
        target,
        data: {
          type: 'cubic-edge',
          animates: {
            update: [
              {
                fields: ['lineDash'],
                shapeId: 'keyShape',
                states: ['growing', 'running'],
                iterations: Infinity,
                duration: 2000,
              },
              {
                fields: ['offsetDistance'],
                shapeId: 'buShape',
                states: ['circleRunning'],
                iterations: Infinity,
                duration: 2000,
              },
            ],
          },
          ...data,
        },
      };
    },
    combo: model => {
      const { id, data } = model;
      return {
        id,
        data: {
          ...data,
          type: 'rect-combo',
          keyShape: {
            opacity: 0.8,
            padding: [20, 20, 20, 20],
            radius: 8,
          },
          labelShape: {
            text: data.label,
            offsetY: 8,
          },
          labelBackgroundShape: {},
          animates: {
            update: [
              {
                fields: ['width', 'height', 'x', 'y'],
                shapeId: 'keyShape',
              },
            ],
          },
        },
      };
    },
    // 节点状态
    nodeState: {
      breathing: {
        haloShape: {
          opacity: 0.25,
          lineWidth: 20,
          visible: true,
        },
        keyShape: {
          radius: 4,
        },
      },
      scaling: {
        keyShape: {
          width: 100,
          height: 60,
        },
      },
    } as any,
    edgeState: {
      growing: {
        keyShape: {
          lineWidth: 2,
          lineDash: ['100%', 0],
        },
      },
      running: {
        keyShape: {
          lineWidth: 2,
          lineDash: [2, 2],
          //  TODO: lineDashOffset
        },
      },
    },
    data,
  });

  graph.on('node:click', (e: any) => {
    const s = graph.getItemState(e.itemId);
    console.log(s);
    // graph.updateData('node', {
    //   id: e.itemId,
    //   data: {
    //     cluster: Math.random(),
    //     keyShape: {
    //       r: 32 + Math.random() * 10 - 5,
    //       lineWidth: 6 + Math.random() * 6 - 3,
    //       stroke: '#000',
    //     },
    //     labelShape: {
    //       fontWeight: 700,
    //     },
    //   },
    // });
  });

  graph.on('node:pointerenter', (e: any) => {
    const { itemId } = e;
    if (graph.getItemState(itemId, 'breathing')) {
      graph.setItemState(itemId, 'breathing', false);
    } else {
      graph.setItemState(itemId, 'scaling', false);
      graph.setItemState(itemId, 'breathing', true);
    }
    // graph.updateData('node', {
    //   id: itemId,
    //   data: {
    //     label: `after been hovered ${itemId}`,
    //     labelShape: {
    //       fill: '#0f0',
    //     },
    //   },
    // });
  });

  graph.on('node:pointerleave', (e: any) => {
    const { itemId } = e;
    if (graph.getItemState(itemId, 'breathing')) {
      graph.setItemState(itemId, 'breathing', false);
    } else {
      graph.setItemState(itemId, 'scaling', false);
      graph.setItemState(itemId, 'breathing', true);
    }
    // graph.updateData('node', {
    //   id: itemId,
    //   data: {
    //     label: 'label before been hovered',
    //     labelShape: {
    //       fill: '#000',
    //     },
    //   },
    // });
  });
}

const actions = {
  'Enable/Disable Node States': {
    Breathing: () => {
      graph.getAllNodesData().forEach((node:any) => {
        if (graph.getItemState(node.id, 'breathing')) {
          graph.setItemState(node.id, 'breathing', false);
        } else {
          graph.setItemState(node.id, 'scaling', false);
          graph.setItemState(node.id, 'breathing', true);
        }
      });
    },
    Scaling: () => {
      graph.getAllNodesData().forEach((node:any) => {
        if (graph.getItemState(node.id, 'scaling')) {
          graph.setItemState(node.id, 'scaling', false);
        } else {
          graph.setItemState(node.id, 'breathing', false);
          graph.setItemState(node.id, 'scaling', true);
        }
      });
    },
  },
  'Enable/Disable Edge States': {
    Growing: () => {
      graph.getAllEdgesData().forEach((edge:any) => {
        if (graph.getItemState(edge.id, 'growing')) {
          graph.setItemState(edge.id, 'growing', false);
        } else {
          graph.setItemState(edge.id, 'running', false);
          graph.setItemState(edge.id, 'growing', true);
        }
      });
    },
    Running: () => {
      graph.getAllEdgesData().forEach((edge:any) => {
        if (graph.getItemState(edge.id, 'running')) {
          graph.setItemState(edge.id, 'running', false);
        } else {
          graph.setItemState(edge.id, 'growing', false);
          graph.setItemState(edge.id, 'running', true);
        }
      });
    },
  },
};

// watch(
//   () => props.option,
//   val => {
//     if (val) {
//       nextTick(() => {
//         initChart();
//       });
//     }
//   }
// );

onMounted(() => {
  nextTick(() => {
    initChart();
  });
});

onBeforeUnmount(() => {});
</script>

<style lang="less" scoped></style>
