<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="false"
        :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,
  onMounted,
  onUnmounted,
  nextTick,
  ref,
  toRaw,
  watchEffect,
  watch
} from "vue"
import { storeToRefs } from "pinia"
import { convertToUtcIsoString } from "@/utils/transform"
import { paintNodeFunction, paintLineFunction } from "@/utils/customePaint"
import { demoData } from "@/assets/customeGraph/data"
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"])
// 解构 store 中的 state
const { timeList, graph } = storeToRefs(props.store)
let graphVis = null
let forceSimulator = null
let currentSelectNode = ref(null)
let isGraphVisReady = false // 添加一个标志位
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: "120,120,240",
    borderColor: "200,50,50",
    borderWidth: 0,
    selected: {
      borderWidth: 2,
      borderColor: "100,250,100",
      showShadow: true, // 是否展示阴影
      shadowBlur: 30, //阴影范围大小
      shadowColor: "50,250,30" // 选中是的阴影颜色
    }
  },
  link: {
    label: {
      // 连线标签
      show: false, // 是否显示
      color: "245,245,245", // 字体颜色
      font: "normal 11px KaiTi", // 字体大小及类型
      background: "255,255,255" //文字背景色（设置后文字居中,一般与画布背景色一致）
    },
    lineType: "curver", //straight
    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 = () => {
  let viewCenter = graphVis.getViewCenter()
  let simulation = graphVis.getSimulationLayout()
  let curForceSimulator = simulation.forceSimulation()
  curForceSimulator
    .nodes(graphVis.nodes)
    .force("center", simulation.forceCenter(viewCenter.x, viewCenter.y))
    .force("charge", simulation.forceManyBody().strength(-550).theta(0.85)) // manyBodyReuse|forceManyBody .distanceMin(300).distanceMax(400).theta(0.9)
    .force("link", simulation.forceLink(graphVis.links).distance(120).strength(0.35)) //.distance(120).strength(0.15)
    .force(
      "collide",
      simulation.forceCollide().radius((d) => d.radius + 5)
    ) //.iterations(5)
    .force("x", simulation.forceX())
    .force("y", simulation.forceY())
    .alphaDecay(0.02) //设置 alpha 衰减率.迭代150，默认0.0228
    //.alphaMin(0.005) //须要在 [0, 1] 之间。若是没有指定 min 则返回当前的最小 alpha 值，默认为 0.001. 在仿真内部，会不断的减少 alpha 值直到 alpha 值小于 最小 alpha
    .velocityDecay(0.15) //默认为 0.4,较低的衰减系数可使得迭代次数更多，其布局结果也会更理性，可是可能会引发数值不稳定从而致使震荡。

  curForceSimulator.alpha(1).restart()

  curForceSimulator.on("tick", () => {
    if (graphVis) {
      graphVis.refreshView() // 刷新视图
    }
  })

  curForceSimulator.on("end", () => {
    curForceSimulator.alpha(0)
    curForceSimulator.stop()
  })
  forceSimulator = curForceSimulator
}

const initChart = () => {
  const getGroupCenters = (groupCount, width, height, radius = 200) => {
    // 三组分布在三角形顶点
    const angleStep = (2 * Math.PI) / groupCount
    const centerX = width / 2
    const centerY = height / 2
    return Array.from({ length: groupCount }).map((_, i) => ({
      x: centerX + Math.cos(i * angleStep) * radius,
      y: centerY + Math.sin(i * angleStep) * radius
    }))
  }
  const assignNodePositions = (nodes, groupCenters) => {
    const groupMap = {}
    nodes.forEach((node) => {
      const groupIdx = node.groupId || 0
      if (!groupMap[groupIdx]) groupMap[groupIdx] = []
      groupMap[groupIdx].push(node)
    })
    Object.entries(groupMap).forEach(([groupIdx, groupNodes]) => {
      const center = groupCenters[groupIdx]
      groupNodes.forEach((node, i) => {
        // 每组节点在各自中心附近随机分布
        node.x = center.x + Math.random() * 80 - 40
        node.y = center.y + Math.random() * 80 - 40
      })
    })
  }

  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 groupCount = 3 // 分组数量
  // const width = 900,
  //   height = 500 // 画布大小
  // const groupCenters = getGroupCenters(groupCount, width, height)
  // assignNodePositions(graph.value.nodes, groupCenters)
  createGraph()
  console.log(graph.value)

  graphVis.addGraph({ ...toRaw(graph.value) })
  runForceLayout()
}
onMounted(() => {
  initChart()
  
})

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>
