<template>
  <div class="groupGraph-component">
    <img src="@/assets/images/groupEvolution/graph-title.png" class="titleImage" />
    <div class="container" id="container"></div>
    <div class="timeList">
      <TimeAxis
        v-if="timeList.length"
        :time-list="timeList"
        :is-auto-play="true"
        :start-time="new Date(timeList[0])"
        :end-time="new Date(timeList[timeList.length - 1])"
        @click:pointerDown="handlePointerDown"
        @slide:pointerUp="handlePointerDown"
      ></TimeAxis>
    </div>
  </div>
</template>

<script setup>
import { defineProps, defineEmits, onUnmounted, ref, toRaw, watch } from "vue"
import { storeToRefs } from "pinia"
import { convertToUtcIsoString } from "@/utils/transform"
import { paintNodeFunction, paintLineFunction } from "@/utils/customePaint"
import TimeAxis from "@/components/timeAxis.vue"
import GraphVis from "@/assets/package/graphvis.esm.min.js"
const props = defineProps({
  store: {
    required: true
  }
})
const emit = defineEmits(["click:pointerDownAndSlide"])
const { timeList, graph } = storeToRefs(props.store)
let graphVis = null
let forceSimulator = null
let currentSelectNode = ref(null)
const defaultConfig = {
  node: {
    label: {
      show: true,
      font: "normal 14px KaiTi",
      color: "250,250,250",
      textPosition: "Bottom_Center", //Middle_Center
      textOffsetY: 10
    },
    shape: "circle",
    size: 30,
    color: (node) => colorMap[node.cluster],
    borderColor: "200,50,50",
    borderWidth: 0,
    selected: {
      borderWidth: 2,
      borderColor: "100,250,100",
      showShadow: true, // 是否展示阴影
      shadowBlur: 10, //阴影范围大小
      shadowColor: "50,250,30" // 选中是的阴影颜色
    }
  },
  link: {
    label: {
      // 连线标签
      show: false, // 是否显示
      color: "245,245,245", // 字体颜色
      font: "normal 11px KaiTi", // 字体大小及类型
      background: "255,255,255" //文字背景色（设置后文字居中,一般与画布背景色一致）
    },
    lineType: "straight", // curver
    showArrow: false,
    lineWidth: 2,
    colorType: "both",
    color: "240,240,240",
    selected: {
      color: "100,250,100"
    }
  },
  highLightNeiber: true // 相邻节点高亮开关
}
const registCustomePaintFunc = () => {
  graphVis.definedNodePaintFunc(paintNodeFunction) //自定义节点绘图方法
  graphVis.definedLinkPaintFunc(paintLineFunction) //自定义关系绘图方法
}
// 处理时间轴点击事件和拉动
const handlePointerDown = (time) => {
  const utcTime = convertToUtcIsoString(time)
  emit("click:pointerDownAndSlide", utcTime)
}

const registEvents = () => {
  //全局记录包裹层元素
  const containerDom = document.getElementById("container")
  graphVis.registEventListener("node", "mouseOver", function (event, node) {
    containerDom.style.cursor = "pointer"
  })
  graphVis.registEventListener("node", "mouseOut", function (event, node) {
    containerDom.style.cursor = ""
  })
  //节点开始拖动
  graphVis.registEventListener("node", "mousedrag", function (event, node) {
    currentSelectNode.value = node

    //开始拖动，必须要设置的属性
    currentSelectNode.value.fx = node.x
    currentSelectNode.value.fy = node.y
    forceSimulator.alphaTarget(0.3).restart()
  })

  graphVis.registEventListener("node", "dblClick", function (event, node) {
    node.fx = null
    node.fy = null
    forceSimulator.alphaTarget(0.3).restart()
  })

  //拖动中
  graphVis.registEventListener("scene", "mouseDraging", function (event, client) {
    if (currentSelectNode.value != null) {
      currentSelectNode.value.fx = currentSelectNode.value.x
      currentSelectNode.value.fy = currentSelectNode.value.y
    }
  })

  graphVis.registEventListener("scene", "mouseDragEnd", function (event, client) {
    if (currentSelectNode.value != null) {
      forceSimulator.alphaTarget(0)
      //如果拖动结束需要固定拖拽的节点，则注释下面两行，保留最后拖动的位置即可
      //that.currentSelectNode.fx = null;
      //that.currentSelectNode.fy = null;
      currentSelectNode.value = null
    }
  })
}
const runForceLayout = () => {
  const layoutConfig = { strength: -500, ajustCluster: true }
  //执行异步布局计算
  graphVis.excuteWorkerLayout(
    graphVis.getGraphData(),
    "simulation",
    layoutConfig,
    false,
    function () {
      graphVis.zoomFit() //布局结束缩放居中
    }
  )
}
// 根据节点的cluster属性进行分组
const clusterAnalyze = () => {
  graphVis.removeAllGroup() // 清除原有分组
  // 创建cluster到nodes的映射
  const clusterNodesMap = new Map()
  graphVis.nodes.forEach((node) => {
    const cluster = parseInt(node.type)
    if (!clusterNodesMap.has(cluster)) {
      clusterNodesMap.set(cluster, [])
    }
    clusterNodesMap.get(cluster).push(node)
  })
  const colorMap = {
    0: "50,141,120", // 绿色
    1: "133,129,48", // 黄色
    6: "12,112,144" // 蓝色
  }
  clusterNodesMap.forEach((nodes, cluster) => {
    const color = colorMap[cluster]
    nodes.forEach((node) => {
      node.fillColor = color
      node.color = color
    })
    let group = graphVis.addNodesInGroup(nodes, {
      shape: "polygon", //circle|rect|polygon|bubbleset
      color: color,
      alpha: 0.3
    })
    group.smoothPath = false //拟合平滑曲线（耗性能）
  })
  graphVis.autoGroupLayout(graphVis.nodes)
}

const createGraph = () => {
  if (!graphVis) {
    graphVis = new GraphVis({
      container: document.getElementById("container"),
      licenseKey: "hbsy",
      config: defaultConfig
    })
  }
  graphVis.setDragHideLine(false) //拖拽时隐藏连线
  graphVis.setShowDetailScale(0.1) //展示细节的比例
  graphVis.setZoomRange(0.1, 5) //缩放区间
  registCustomePaintFunc() //注册自定义绘图方法
  registEvents()
}

const initChart = () => {
  createGraph()
  graphVis.addGraph({ ...toRaw(graph.value) })
  runForceLayout()
  clusterAnalyze()
}

// 添加更新图表的函数
const updateChart = (newGraphData) => {
  if (!graphVis) {
    initChart()
    return
  }
  graphVis.clearAll()
  graphVis.addGraph({ ...toRaw(newGraphData) })
  graphVis.zoomFit()
  // 重新运行力导向布局
  runForceLayout()
  clusterAnalyze()
}

let lastLength = 0 //记录上一次的长度
watch(
  graph,
  (newValue) => {
    if (newValue && newValue.nodes.length > lastLength) {
      updateChart(newValue)
    }
    lastLength = newValue.nodes.length
  },
  { deep: true }
)

onUnmounted(() => {
  if (graphVis) {
    graphVis.destroy() // 如果 GraphVis 提供了销毁方法
    graphVis = null
  }
})
</script>

<style scoped lang="less">
.groupGraph-component {
  width: 100%;
  height: 100%;
  position: relative;
  .titleImage {
    margin: 0 auto;
  }
  .container {
    width: 100%;
    height: 503px;
  }
  .timeList {
    width: 95%;
    height: 42px;
    position: absolute;
    left: 20px;
    bottom: 20px;
    z-index: 1;
  }
}
</style>
