<template>
  <div
    style="height:100%; position: relative; font-size: 16px;"
    v-loading="loading"
    class="d-flex align-center justify-center"
  >
    <div class="legend d-flex pa-3 justify-space-between">
      <!-- 图例 -->
      <div class="d-flex align-center">
        <div
          v-for="item in legend"
          :key="item.title"
          class="d-flex mr-5"
        >
          <div class="pa-3 mr-3 rounded-circle" :style="`background-color: ${item.color};`"></div>
          {{ item.title }}
        </div>
      </div>
    </div>
    <MEmpty v-if="empty"></MEmpty>
    <RelationGraph
      v-show="!empty"
      ref="graphRef"
      :options="graphOptions"
      :on-node-click="onNodeClick"
      :on-line-click="onLineClick"
    >
      <template #node="{node}">
        <!-- <v-tooltip left :color="node.color || 'primary'"> -->
          <!-- <template v-slot:activator="{ on, attrs }"> -->
            <div @contextmenu.prevent="handleContextmenu($event, node)" style="cursor: pointer;">
              <div
                :style="{ width: node.width + 'px', height: node.height + 'px' }"
                :class="{ 'node-active':  menu.activeId === +node.id }"
                class="rounded-circle"
              >
              </div>
              <div
                :style="{ 'background-color': node.color + '44', width: 20 * ((node.text || '').length) + 'px' }"
                class="node-text"
                :class="{ 'node-active':  menu.activeId === +node.id }"
              >
                {{ node.text || '' }}
              </div>
            </div>
          <!-- </template> -->
          <!-- 浮窗展示节点详情 -->
          <!-- <div class="d-flex">
            <ul style="color: #fff;text-align:right;">
              <template v-for="key in Object.keys(detailKeys)">
                <li v-if="node.data[key]" :key="key">{{ detailKeys[key] }} ：</li>
              </template>
            </ul>
            <ul>
              <template v-for="key in Object.keys(detailKeys)">
                <li v-if="node.data[key]" :key="key">
                  <span v-if="key === 'labels'">{{ node.data[key].join(',') }}</span>
                  <span v-else-if="key === 'matched_data'">
                    <v-simple-table dense v-if="getMatchDataArray(node.data[key]) && getMatchDataArray(node.data[key]).length">
                      <template v-slot:default>
                        <thead>
                          <tr>
                            <th v-for="header in getMatchDataHeaders(node.data[key])" :key="header.value" class="text-left">
                              {{ header.text }}
                            </th>
                          </tr>
                        </thead>
                        <tbody>
                          <tr v-for="(item, index) in getMatchDataArray(node.data[key])" :key="index">
                            <td v-for="header in getMatchDataHeaders(node.data[key])" :key="header.value">
                              {{ item[header.value] }}
                            </td>
                          </tr>
                        </tbody>
                      </template>
                    </v-simple-table>
                  </span>
                  <span v-else>{{ node.data[key] }}</span>
                </li>
              </template>
            </ul>
          </div> -->
        <!-- </v-tooltip> -->
      </template>
      <template #graph-plug>
        <v-menu v-model="menu.show" attach :position-x="menu.x" :position-y="menu.y" absolute offset-y min-width="200">
          <v-list dense>
            <v-list-item v-for="(k, i) in menu.items" :key="i" @click="k.handle">
              <v-list-item-title>{{ k.title }}</v-list-item-title>
            </v-list-item>
          </v-list>
        </v-menu>
      </template>
    </RelationGraph>

    <!-- 右侧抽屉展示节点详情 -->
    <v-navigation-drawer
      v-model="drawer.show"
      fixed
      temporary
      right
      width="50%"
      style="z-index: 300;"
    >
      <template v-slot:prepend>
        <v-toolbar color="primary" dark>
          <v-toolbar-title>节点详情</v-toolbar-title>
          <v-spacer></v-spacer>
          <v-btn icon @click="drawer.show = false">
            <v-icon>mdi-close</v-icon>
          </v-btn>
        </v-toolbar>
      </template>
      <v-container v-if="drawer.nodeData">
        <div class="d-flex">
          <ul class="ml-0 pl-0" style="color: #333;text-align:right; padding-right: 16px; min-width: 120px;">
            <template v-for="key in Object.keys(detailKeys)">
              <li v-if="drawer.nodeData[key]" :key="key" style="margin-bottom: 12px;">{{ detailKeys[key] }} ：</li>
            </template>
          </ul>
          <ul style="flex: 1; overflow-x: auto;">
            <template v-for="key in Object.keys(detailKeys)">
              <li v-if="drawer.nodeData[key]" :key="key" style="margin-bottom: 12px;">
                <span v-if="key === 'labels'">{{ drawer.nodeData[key].join(',') }}</span>
                <span v-else-if="key === 'matched_data'">
                  <v-simple-table fixed-header height="60vh" v-if="getMatchDataArray(drawer.nodeData[key]) && getMatchDataArray(drawer.nodeData[key]).length">
                    <template v-slot:default>
                      <thead>
                        <tr>
                          <th v-for="header in getMatchDataHeaders(drawer.nodeData[key])" :key="header.value" class="text-left">
                            {{ header.text }}
                          </th>
                        </tr>
                      </thead>
                      <tbody>
                        <tr v-for="(item, index) in getMatchDataArray(drawer.nodeData[key])" :key="index">
                          <td v-for="header in getMatchDataHeaders(drawer.nodeData[key])" :key="header.value">
                            {{ item[header.value] }}
                          </td>
                        </tr>
                      </tbody>
                    </template>
                  </v-simple-table>
                  <!-- <v-data-iterator
                    :items="getMatchDataArray(drawer.nodeData[key])"
                    hide-default-footer
                    hide-default-header
                  >
                    <template v-slot:default="props">
                      <v-row>
                        <v-col v-for="item in props.items" :key="item.id" cols="6">
                          <v-card elevation="3">
                            <v-list dense>
                              <v-list-item v-for="(key, index) in Object.keys(item)" :key="index">
                                <v-list-item-content>{{ key }}:</v-list-item-content>
                                <v-list-item-content class="align-end">{{ item[key] }}</v-list-item-content>
                              </v-list-item>
                            </v-list>
                          </v-card>
                        </v-col>
                      </v-row>
                    </template>
                  </v-data-iterator> -->
                </span>
                <span v-else>{{ drawer.nodeData[key] }}</span>
              </li>
            </template>
          </ul>
        </div>
      </v-container>
    </v-navigation-drawer>

  </div>
</template>

<script>
import RelationGraph from 'relation-graph'
import MEmpty from '@/components/Common/empty'
const defaultNodeColor = 'rgba(238, 178, 94, 1)'
const NODES_SIZE = {
  width: 30,
  height: 30
}
export default {
  name: 'details-graph',
  components: { RelationGraph, MEmpty },
  props: {
    graphData: {
      type: Object,
      default: null
    }
  },
  data () {
    return {
      menu: {
        x: 0,
        y: 0,
        show: false,
        items: [
          { title: '查看', handle: this.handleView }
        ],
        activeId: +this.$route.params.id,
        item: {}
      },
      drawer: {
        show: false,
        nodeData: null
      },
      empty: true,
      loading: false,
      graphOptions: {
        // defaultJunctionPoint: 'lr',
        // 这里可以参考"Graph 图谱"中的参数进行设置 https://www.relation-graph.com/#/docs/graph
        debug: false, // 是否开始调试模式，调试模式下会在控制台打印额外的日志信息
        showDebugPanel: false, // 是否显示调试按钮，通过此按钮可以打印配置、数据等
        backgroundImage: '', // 图谱水印url,如：https://ssl.relation-graph.com/images/relatioon-graph-canvas-bg.png
        downloadImageFileName: '', // 下载图片时，图片的名称
        disableZoom: false, // 是否禁用图谱的缩放功能
        disableDragNode: false, // 是否禁用图谱中节点的拖动
        moveToCenterWhenRefresh: true, // 当图谱刷新后（调用setJsonData或refresh方法都会触发），让图谱根据节点居中（图片会默认将根节点作为中心展示，此选项会根据节点分布寻找中心）
        zoomToFitWhenRefresh: true, // 当图谱刷新后（调用setJsonData或refresh方法都会触发），是否让图谱缩放到适合可见区域大小，此选项不适用于fixed和force布局
        useAnimationWhenRefresh: true, // 当图谱刷新后（调用setJsonData或refresh方法都会触发），使用动画让图居中、缩放
        useAnimationWhenExpanded: true,
        defaultFocusRootNode: true, // 默认为根节点添加一个被选中的样式
        disableNodeClickEffect: false, // 是否禁用节点默认的点击效果（选中、闪烁）
        disableLineClickEffect: false, // 是否禁用线条默认的点击效果（选中、闪烁）
        allowShowZoomMenu: true, // 是否在右侧菜单栏显示放大缩小的按钮，此设置和disableZoom不冲突
        allowAutoLayoutIfSupport: true, // 是否在工具栏中显示【自动布局】按钮（只有在布局支持且此选项为true时才会显示的按钮）
        allowShowRefreshButton: true, // 是否在工具栏中显示【刷新】按钮
        allowShowDownloadButton: true, // 是否在工具栏中显示【下载图片】按钮
        backgroundImageNoRepeat: false, // 只在右下角显示水印，不重复显示水印
        allowSwitchLineShape: true, // 是否在工具栏中显示切换线条形状的按钮
        allowSwitchJunctionPoint: true, // 是否在工具栏中显示切换连接点位置的按钮
        isMoveByParentNode: false, // 是否在拖动节点后让子节点跟随
        defaultExpandHolderPosition: 'hide', // 默认的节点展开/关闭按钮位置（left/top/right/bottom/hide）
        defaultNodeColor, // 默认的节点背景颜色
        checkedLineColor: '#FD8B37', // 当线条被选中时的颜色
        defaultNodeFontColor: '#ffffff', // 默认的节点文字颜色
        defaultNodeBorderColor: '#90EE90', // 默认的节点边框颜色
        defaultNodeBorderWidth: 0, // 默认的节点边框粗细（像素）
        defaultLineColor: '#cccccc', // 默认的线条颜色
        defaultLineWidth: 2, // 默认的线条粗细（像素）
        defaultLineShape: 2, // 默认的线条样式（1:直线/2:样式2/3:样式3/4:折线/5:样式5/6:样式6）使用示例
        defaultNodeShape: 0, // 默认的节点形状，0:圆形；1:矩形
        defaultShowLineLabel: true, // 默认是否显示连线文字，v2版本此选项已无效，主要是这个选项没什么用
        hideNodeContentByZoom: true, // 是否根据缩放比例隐藏节点内容
        // disableDragCanvas: false,
        // lineUseTextPath: false,
        defaultLineMarker: { // 默认的线条箭头样式，示例参考：配置工具中的选项：连线箭头样式
          markerWidth: 24,
          markerHeight: 24,
          refX: 6,
          refY: 6,
          data: 'M2,2 L10,6 L2,10 L6,6 L2,2'
        },
        layouts: [
          {
            label: '自动布局',
            layoutName: 'center', // 布局方式（tree树状布局/center中心布局/force自动布局）
            from: 'left',
            maxLayoutTimes: 20,
            layoutClassName: 'seeks-layout-force',
            useLayoutStyleOptions: false,
            defaultNodeColor: '#FFC5A6',
            defaultNodeFontColor: '#000000',
            defaultNodeBorderColor: '#efefef',
            defaultNodeBorderWidth: 1,
            defaultLineColor: '#FD8B37',
            defaultLineWidth: 1,
            defaultShowLineLabel: true,
            defaultLineMarker: {
              markerWidth: 12,
              markerHeight: 12,
              refX: 6,
              refY: 6,
              data: 'M2,2 L10,6 L2,10 L6,6 L2,2'
            }
          }
        ]
      },
      config: {
        BusinessDomain: {
          color: '#9FA8DA',
          title: '业务域',
          className: 'sourceNode',
          ...NODES_SIZE
        },
        DataResource: {
          color: '#4CAF50',
          title: '数据资源',
          className: 'sourceNode',
          ...NODES_SIZE
        },
        DataFlow: {
          color: '#FF9800',
          title: '数据流程',
          className: 'dataFlowNode',
          ...NODES_SIZE
        },
        data_standard: {
          color: '#009688',
          title: '数据标准',
          className: 'standardNode',
          ...NODES_SIZE
        },
        DataLabel: {
          color: '#9C27B0',
          title: '数据标签',
          className: 'labelNode',
          ...NODES_SIZE
        },
        DataMeta: {
          color: defaultNodeColor,
          title: '元数据',
          className: '',
          ...NODES_SIZE
        }
      },
      // 节点详情
      detailKeys: {
        // id: '节点ID',
        name_zh: '中文名称',
        name_en: '英文名称',
        node_type: '节点类型',
        labels: '节点标签',
        is_target: '是否目标节点',
        is_source: '是否源节点',
        matched_data: '匹配数据'
      }
    }
  },
  computed: {
    legend () {
      return Object.values(this.config)
    }
  },
  watch: {
    graphData: {
      handler (newVal) {
        if (newVal && newVal.nodes && newVal.nodes.length) {
          this.drawWithData(newVal)
        } else if (newVal === null) {
          // 当 graphData 被清空时，重置状态
          this.empty = true
          this.loading = false
        }
      },
      immediate: false,
      deep: true
    }
  },
  mounted () {
    this.init()
  },
  methods: {
    handleContextmenu (v, node) {
      const { left, top } = this.$refs.graphRef.$el.getBoundingClientRect()
      this.menu.x = v.clientX - left
      this.menu.y = v.clientY - top
      this.menu.item = node
      this.menu.show = true
    },
    handleView () {
      this.draw({ id: +this.menu.item.id }, () => {
        this.menu.activeId = +this.menu.item.id
      })
    },
    changeType () {
      this.init()
    },
    handleClick (node) {
      console.log(node)
    },
    async init () {
      this.drawWithData(this.graphData)
    },
    drawWithData (data, successCallback = () => {}) {
      // 清空再渲染
      this.loading = true
      this.empty = false
      try {
        if (!data.nodes || !data.nodes.length) {
          this.empty = true
          this.loading = false
          return
        }
        this.graphOptions.downloadImageFileName = data.rootId ?? ''

        data.nodes.forEach(ele => {
          if (!this.config[ele.node_type]) {
            return
          }
          ele.text = ele.name_zh || ele.name_en
          ele.data = { ...ele }
          Object.assign(ele, this.config[ele.node_type])
        })

        // data.lines.forEach(ele => {
        //   ele.color = LINE_COLOR_MAP[ele.text]
        // })
        this.$nextTick(() => {
          this.$refs.graphRef.setOptions(this.graphOptions, async (graphInstance) => {
            if (!this.$refs.graphRef || !this.$refs.graphRef.setJsonData) {
              return
            }
            this.$refs.graphRef.setJsonData(data, async (_graphInstance) => {
              await _graphInstance.setZoom(75)
              successCallback()
              this.loading = false
            })
          })
        })
      } catch (error) {
        this.empty = true
        this.loading = false
        this.$snackbar.error(error)
      }
    },
    // 节点点击
    onNodeClick (nodeObject, $event) {
      // 设置节点数据并打开抽屉
      this.drawer.nodeData = nodeObject.data
      this.drawer.show = true
    },
    onLineClick (lineObject, $event) {
      console.log('onLineClick:', lineObject)
    },
    // 获取匹配数据的表头
    getMatchDataHeaders (matchData) {
      if (!matchData) return []
      // 统一转换为数组格式
      const dataArray = Array.isArray(matchData) ? matchData : [matchData]
      if (dataArray.length === 0) return []
      // 从第一个对象中提取所有 key 作为表头
      const firstItem = dataArray[0]
      const headers = Object.keys(firstItem).map(key => ({
        text: key,
        value: key
      }))
      return headers
    },
    // 将匹配数据统一转换为数组格式
    getMatchDataArray (matchData) {
      if (!matchData) return []
      return Array.isArray(matchData) ? matchData : [matchData]
    }
  }
}
</script>

<style lang="scss" scoped>
ul{
  list-style: none;
}
.legend {
  pointer-events: none;
  width: 100%;
  user-select: none;
  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
  position: absolute;
  top: 0;
  z-index: 10;
  color: #666;
  .rounded-circle {
    width: 24px;
    height: 24px;
  }
}
.pointerEvents {
  pointer-events: auto;
}
::v-deep .rel-node-checked {
  box-shadow: unset !important;
}
.node-active {
  box-shadow: 0 0 0px 6px #f3f900 !important;
}
.node-text {
  color: #000;
  font-size: 16px;
  position: absolute;
  height:25px;
  transform: translate(-50%, 0);
  line-height: 25px;
  left: 50%;
  margin-top:5px;
  text-align: center;
}

::v-deep .rel-toolbar {
  background-color: #f39930;
  color: #ffffff;
  .c-current-zoom {
    color: #ffffff;
  }
}
</style>
