<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, 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 isPlay = ref(false)
let graphVis = null
let forceSimulator = null
let currentSelectNode = ref(null)
const storeId = props.store.$id
const defaultConfig = {
  node: {
    label: {
      show: true,
      font: "normal 14px KaiTi",
      color: "250,250,250",
      textPosition: "Middle_Center", //Middle_Center
      textOffsetY: 10
    },
    shape: "circle",
    size: storeId == "anomalousGroup" ? 15 : 40,
    borderColor: "200,50,50",
    borderWidth: 0,
    selected: {
      borderWidth: 5,
      borderColor: "100,250,100",
      showShadow: true, // 是否展示阴影
      shadowBlur: 5, //阴影范围大小
      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: 1,
    colorType: "both",
    color: "240,240,240",
    selected: {
      color: "100,250,100"
    }
  },
  highLightNeiber: true // 相邻节点高亮开关
}
const registCustomePaintFunc = (curStoreId) => {
  graphVis.definedNodePaintFunc(paintNodeFunction(curStoreId)) //自定义节点绘图方法
  graphVis.definedLinkPaintFunc(paintLineFunction) //自定义关系绘图方法
}
// 处理时间轴点击事件和拉动
const handlePointerDown = (time) => {
  const utcTime = convertToUtcIsoString(time)
  emit("click:pointerDownAndSlide", utcTime)
}

const registEvents = () => {
  const simulation = graphVis.getSimulationLayout()
  forceSimulator = simulation.forceSimulation()
  //全局记录包裹层元素
  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)
      //如果拖动结束需要固定拖拽的节点，则注释下面两行，保留最后拖动的位置即可
      currentSelectNode.value.fx = null
      currentSelectNode.value.fy = null
      currentSelectNode.value = null
    }
  })
}

//公用连线或节点高亮函数
const highLightAboutNodesOrLinks = (type) => {
  graphVis.cancelAllSelected()
  const { newNodes, newLinks } = graph.value
  if (type == "nodes") {
    //实现高亮节点逻辑
    graphVis.nodes.forEach((node) =>
      newNodes.forEach((newNode) => {
        if (node.id === newNode.name) {
          node.selected = true
        }
      })
    )
  } else if (type == "links") {
    //实现连线高亮逻辑
    graphVis.links.forEach((link) =>
      newLinks.forEach((newLink) => {
        if (link.source.id === newLink.source && link.target.id === newLink.target) {
          link.selected = true
        }
      })
    )
  } else {
    return
  }
}
const runDiffForceLayout = (layoutConfig, layoutType, isAsync) => {
  function handleLayoutSuccess() {
    //处理四个关系图的差异函数
    const handleGroupDiscoveryDiff = () => {
      return
    }

    const handleGroupStructureDiff = () => {
      highLightAboutNodesOrLinks("links")
    }

    const handleGroupMemberDiff = () => {
      highLightAboutNodesOrLinks("nodes")
    }

    const handleAnomalousGroup = () => {
      // 当前时间从 store 取；没有就用 T0
      const now = props.store.currentUtc
      const TA = "2024-06-19T08:57:55Z" // A
      const TB = "2024-06-19T10:58:03Z" // B
      const TC = "2024-06-19T12:58:04Z" // C
      // 组色（与你现有 colorMap 一致）
      const GROUP_ALPHA = 0.3
      const RED = "220,50,60"
      // 时间门控：达到阈值就把各组异常节点染红
      const shouldA = now >= TA
      const shouldB = now >= TB
      const shouldC = now >= TC
      if (shouldA) {
        graphVis.nodes = graphVis.nodes.map((n) => {
          if (props.store.graphAbnormalData.groupA.includes(n.id)) {
            n.fillColor = RED
          }
          return n
        })
        graphVis.addNodesInGroup(
          graphVis.nodes.filter((n) => props.store.graphAbnormalData.groupA.includes(n.id)),
          {
            shape: "circle",
            color: RED,
            alpha: GROUP_ALPHA
          }
        )
      }
      if (shouldB) {
        graphVis.nodes = graphVis.nodes.map((n) => {
          if (props.store.graphAbnormalData.groupB.includes(n.id)) {
            n.fillColor = RED
          }
          return n
        })
        graphVis.addNodesInGroup(
          graphVis.nodes.filter((n) => props.store.graphAbnormalData.groupB.includes(n.id)),
          {
            shape: "circle",
            color: RED,
            alpha: GROUP_ALPHA
          }
        )
      }
      if (shouldC) {
        graphVis.nodes = graphVis.nodes.map((n) => {
          if (props.store.graphAbnormalData.groupC.includes(n.id)) {
            n.fillColor = RED
          }
          return n
        })
        graphVis.addNodesInGroup(
          graphVis.nodes.filter((n) => props.store.graphAbnormalData.groupC.includes(n.id)),
          {
            shape: "circle",
            color: RED,
            alpha: GROUP_ALPHA
          }
        )
      }
      // graphVis.autoGroupLayout(graphVis.nodes)
    }

    new Map([
      ["groupDiscovery", () => handleGroupDiscoveryDiff()],
      ["groupStructure", () => handleGroupStructureDiff()],
      ["groupMember", () => handleGroupMemberDiff()],
      ["anomalousGroup", () => handleAnomalousGroup()]
    ]).get(storeId)?.()

    graphVis.zoomFit() //场景视图大小自适应缩放
  }
  graphVis.excuteWorkerLayout(graphVis.getGraphData(), layoutType, layoutConfig, isAsync, () =>
    handleLayoutSuccess()
  )
}
// 根据节点的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)
  })
  let colorMap = {
    0: "75,241,184", // 绿色
    1: "250,222,37", // 黄色
    6: "69,192,242" // 蓝色
  }
  clusterNodesMap.forEach((nodes, cluster) => {
    const color = colorMap[cluster]
    nodes.forEach((node) => {
      node.fillColor = color
      node.color = color
    })
    if (storeId !== "anomalousGroup") {
      graphVis.addNodesInGroup(nodes, {
        shape: "polygon", //circle|rect|polygon|bubbleset
        color: color,
        alpha: 0.2
      })
    }
  })
  // graphVis.autoGroupLayout(graphVis.nodes)
}

// 仅对“异常群体模块”生效：时间变化时强制重绘一次
if (storeId === "anomalousGroup") {
  watch(
    () => props.store.currentUtc,
    () => {
      // 不改 graph 数据结构，直接用当前 graph 强制走一遍：addGraph → clusterAnalyze → runForceLayout
      if (graphVis) {
        updateChart(toRaw(graph.value))
      }
    }
  )
}

// 实例化 GraphVis、注册自定义绘制/事件
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(storeId) //注册自定义绘图方法
  registEvents()
}

const initChart = () => {
  createGraph()
  graphVis.addGraph({ ...toRaw(graph.value) })
  clusterAnalyze()
  runDiffForceLayout({ strength: -500, ajustCluster: true }, "simulation", true)
}

// 添加更新图表的函数
const updateChart = (newGraphData) => {
  if (!graphVis) {
    initChart()
    return
  }
  graphVis.clearAll()
  graphVis.addGraph({ ...toRaw(newGraphData) })
  // 重新运行力导向布局
  clusterAnalyze()
  runDiffForceLayout({ strength: -500, ajustCluster: true }, "simulation", true)
}

watch(
  graph,
  (newValue) => {
    if (newValue) {
      updateChart(newValue)
    }
  },
  { deep: true }
)
</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>
