<template>
  <div class="flex flex-col h-full">
    <!-- 头部 -->
    <div class="flex items-center gap-3 px-4 py-2 bg-base-300 text-xs text-base-content/60 shrink-0">
      <span>相关图</span>
      <span v-if="store.selectedNodeId" class="text-primary font-medium">{{ currentNodeName }}</span>
      <div class="flex-1"></div>
      <button v-if="store.selectedNodeId" @click="showConfig = !showConfig" class="btn btn-ghost btn-xs">
        {{ showConfig ? '隐藏筛选' : '筛选' }}
      </button>
      <template v-if="showExpand && store.selectedNodeId">
        <button
          v-if="store.expandedPanel !== 'graph'"
          @click="store.expandPanel('graph')"
          class="btn btn-ghost btn-xs"
          title="放大"
        >⤢</button>
        <button
          v-if="store.expandedPanel !== 'default'"
          @click="store.resetLayout()"
          class="btn btn-ghost btn-xs"
          title="恢复"
        >⊡</button>
      </template>
    </div>

    <!-- 人设节点筛选配置 -->
    <div v-show="showConfig && isPersonaWalk" class="px-4 py-2 bg-base-200 border-b border-base-300 text-xs space-y-3 max-h-64 overflow-y-auto relative z-50">
      <!-- 步数设置 -->
      <div class="flex items-center gap-2">
        <span class="text-base-content/60 w-16">筛选步数:</span>
        <input type="number" :min="1" :max="5" v-model.number="store.walkSteps" class="input input-xs input-bordered w-16 text-center" />
      </div>

      <!-- 分步设置 -->
      <div class="space-y-2">
        <div v-for="step in store.walkSteps" :key="step" class="pl-4 space-y-1 border-l-2 border-secondary/30">
          <div class="flex items-center gap-2">
            <span class="font-medium text-secondary">第 {{ step }} 步</span>
            <button @click="selectAllEdgeTypes(step-1)" class="btn btn-ghost btn-xs text-base-content/50">全选</button>
            <button @click="clearEdgeTypes(step-1)" class="btn btn-ghost btn-xs text-base-content/50">清空</button>
            <button @click="resetEdgeTypes(step-1)" class="btn btn-ghost btn-xs text-base-content/50">默认</button>
          </div>
          <div class="flex items-center gap-2 flex-wrap">
            <span class="text-base-content/60 w-14">边类型:</span>
            <label v-for="et in store.allEdgeTypes" :key="et" class="flex items-center gap-1 cursor-pointer">
              <input type="checkbox" v-model="store.stepConfigs[step-1].edgeTypes" :value="et" class="checkbox checkbox-xs" />
              <span :style="{ color: edgeTypeColors[et] }">{{ et }}</span>
            </label>
          </div>
          <div class="flex items-center gap-2">
            <span class="text-base-content/60 w-14">最小分:</span>
            <input type="number" :min="0" :max="1" :step="0.1" v-model.number="store.stepConfigs[step-1].minScore" class="input input-xs input-bordered w-16 text-center" />
          </div>
        </div>
      </div>
    </div>

    <!-- 帖子标签节点筛选配置 -->
    <div v-show="showConfig && isPostWalk" class="px-4 py-2 bg-base-200 border-b border-base-300 text-xs space-y-2">
      <div class="flex items-center gap-2">
        <span class="text-base-content/60 w-20">最大步数:</span>
        <input type="number" :min="2" :max="10" v-model.number="store.postWalkConfig.maxSteps" class="input input-xs input-bordered w-16 text-center" />
      </div>
      <div class="flex items-center gap-2">
        <span class="text-base-content/60 w-20">最后步分数:</span>
        <input type="number" :min="0" :max="1" :step="0.1" v-model.number="store.postWalkConfig.lastStepMinScore" class="input input-xs input-bordered w-16 text-center" />
      </div>
      <div class="flex items-center gap-2">
        <span class="text-base-content/60 w-20">中间边类型:</span>
        <button @click="selectAllMiddleEdgeTypes" class="btn btn-ghost btn-xs text-base-content/50">全选</button>
        <button @click="clearMiddleEdgeTypes" class="btn btn-ghost btn-xs text-base-content/50">清空</button>
        <button @click="resetMiddleEdgeTypes" class="btn btn-ghost btn-xs text-base-content/50">默认</button>
      </div>
      <div class="flex items-center gap-2 flex-wrap pl-20">
        <label v-for="t in middleEdgeTypeOptions" :key="t" class="flex items-center gap-1 cursor-pointer">
          <input type="checkbox" :value="t" v-model="store.postWalkConfig.middleEdgeTypes" class="checkbox checkbox-xs checkbox-primary" />
          <span>{{ t }}</span>
        </label>
      </div>
      <div class="flex items-center gap-2">
        <span class="text-base-content/60 w-20">中间步分数:</span>
        <input type="number" :min="0" :max="1" :step="0.1" v-model.number="store.postWalkConfig.middleMinScore" class="input input-xs input-bordered w-16 text-center" />
      </div>
      <div class="flex items-center gap-2 text-base-content/50">
        <span>路径: 帖子标签</span>
        <span class="text-primary">--{{ store.postWalkConfig.firstEdgeType }}--></span>
        <span>人设图谱</span>
        <span class="text-primary">--{{ store.postWalkConfig.lastEdgeType }}--></span>
        <span>其他标签</span>
      </div>
      <div v-if="store.postWalkedPaths.length > 0" class="text-success">
        找到 {{ store.postWalkedPaths.length }} 条路径
      </div>
    </div>

    <!-- SVG 容器 -->
    <div ref="containerRef" class="flex-1 relative overflow-hidden">
      <svg ref="svgRef" class="w-full h-full transition-opacity duration-200"></svg>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'
import * as d3 from 'd3'
import { useGraphStore } from '../stores/graph'
import { getNodeStyle, applyNodeShape } from '../config/nodeStyle'
import { edgeTypeColors, getEdgeStyle } from '../config/edgeStyle'
import { applyHighlight, findPath, applyHoverHighlight, clearHoverHighlight } from '../utils/highlight'

const props = defineProps({
  collapsed: { type: Boolean, default: false },
  showExpand: { type: Boolean, default: false }
})

const store = useGraphStore()
const containerRef = ref(null)
const svgRef = ref(null)
const showConfig = ref(false)


// 中间步骤可选的边类型（排除匹配边）
const middleEdgeTypeOptions = computed(() => {
  return store.allEdgeTypes.filter(t => t !== '匹配')
})

// 中间边类型操作
function selectAllMiddleEdgeTypes() {
  store.postWalkConfig.middleEdgeTypes = [...middleEdgeTypeOptions.value]
}

function clearMiddleEdgeTypes() {
  store.postWalkConfig.middleEdgeTypes = []
}

function resetMiddleEdgeTypes() {
  store.postWalkConfig.middleEdgeTypes = ['属于', '包含', '分类共现']
  store.postWalkConfig.middleMinScore = 0.3
}

let simulation = null

// 游走配置操作（直接操作 store）
function selectAllEdgeTypes(stepIndex) {
  store.stepConfigs[stepIndex].edgeTypes = [...store.allEdgeTypes]
}

function clearEdgeTypes(stepIndex) {
  store.stepConfigs[stepIndex].edgeTypes = []
}

function resetEdgeTypes(stepIndex) {
  store.stepConfigs[stepIndex].edgeTypes = stepIndex === 0 ? [...store.allEdgeTypes] : ['属于']
  store.stepConfigs[stepIndex].minScore = 0
}

const currentNodeName = computed(() => {
  if (!store.selectedNodeId) return '点击左侧节点查看'
  const node = store.getNode(store.selectedNodeId)
  return node ? node.name : store.selectedNodeId
})

// 判断当前是哪种游走类型
const isPersonaWalk = computed(() => store.selectedNodeId && store.shouldWalk(store.selectedNodeId))
const isPostWalk = computed(() => store.selectedNodeId && store.shouldPostWalk(store.selectedNodeId))


// 渲染相关图
function renderGraph() {
  // 停止旧的 simulation
  if (simulation) {
    simulation.stop()
    simulation = null
  }

  const svg = d3.select(svgRef.value)
  svg.selectAll('*').remove()

  // 有选中节点或选中边时才渲染
  if (!store.selectedNodeId && !store.selectedEdgeId) return

  // 选中节点时，只有配置的节点类型才显示相关图
  if (store.selectedNodeId && !store.shouldWalk(store.selectedNodeId) && !store.shouldPostWalk(store.selectedNodeId)) return

  const container = containerRef.value
  if (!container) return

  const width = container.clientWidth
  const height = container.clientHeight
  if (width <= 0 || height <= 0) return

  svg.attr('viewBox', `0 0 ${width} ${height}`)

  // 中心节点（选中节点，或边的第一个端点）
  const centerNodeId = store.selectedNodeId || Array.from(store.highlightedNodeIds)[0]

  // 准备节点和边数据
  const nodes = []
  const links = []
  const nodeSet = new Set()

  // 显示所有高亮节点
  for (const nodeId of store.highlightedNodeIds) {
    const nodeData = store.getNode(nodeId)
    if (nodeData) {
      nodes.push({
        id: nodeId,
        ...nodeData,
        isCenter: nodeId === centerNodeId,
        isHighlighted: store.highlightedNodeIds.size > 1
      })
      nodeSet.add(nodeId)
    }
  }

  // 如果没有节点，不渲染
  if (nodes.length === 0) return

  // 使用游走时记录的边（只显示两端节点都存在的边）
  // 优先使用 postWalkedEdges（帖子游走），否则用 walkedEdges（人设游走）
  const edges = store.postWalkedEdges.length > 0 ? store.postWalkedEdges : store.walkedEdges
  for (const edge of edges) {
    if (nodeSet.has(edge.source) && nodeSet.has(edge.target)) {
      links.push({ ...edge })
    }
  }

  const g = svg.append('g')

  // 缩放
  const zoom = d3.zoom()
    .scaleExtent([0.3, 3])
    .on('zoom', (e) => g.attr('transform', e.transform))
  svg.call(zoom)

  // 找到中心节点并固定在容器中心
  const centerNodeData = nodes.find(n => n.isCenter)
  if (centerNodeData) {
    centerNodeData.fx = width / 2
    centerNodeData.fy = height / 2
  }

  // 力导向模拟（中心节点已固定，其他节点围绕它布局）
  simulation = d3.forceSimulation(nodes)
    .force('link', d3.forceLink(links).id(d => d.id).distance(80))
    .force('charge', d3.forceManyBody().strength(-150))
    .force('collision', d3.forceCollide().radius(30))

  // 边
  const link = g.append('g')
    .selectAll('line')
    .data(links)
    .join('line')
    .attr('class', 'graph-link')
    .attr('stroke', d => getEdgeStyle(d).color)
    .attr('stroke-width', 1.5)
    .style('cursor', 'pointer')
    .on('click', (e, d) => {
      e.stopPropagation()
      // 传入完整边数据
      store.selectEdge({
        source: d.source.id || d.source,
        target: d.target.id || d.target,
        type: d.type,
        score: d.score
      })
    })

  // 边的分数标签
  const linkLabelData = links.filter(d => getEdgeStyle(d).scoreText)
  const linkLabel = g.append('g')
    .selectAll('g')
    .data(linkLabelData)
    .join('g')
    .attr('class', 'graph-link-label')

  linkLabel.append('rect')
    .attr('x', -14)
    .attr('y', -6)
    .attr('width', 28)
    .attr('height', 12)
    .attr('rx', 2)
    .attr('fill', '#1d232a')
    .attr('opacity', 0.9)

  linkLabel.append('text')
    .attr('text-anchor', 'middle')
    .attr('dy', '0.35em')
    .attr('fill', d => getEdgeStyle(d).color)
    .attr('font-size', '8px')
    .text(d => getEdgeStyle(d).scoreText)

  // 节点组
  const node = g.append('g')
    .selectAll('g')
    .data(nodes)
    .join('g')
    .attr('class', 'graph-node')
    .call(d3.drag()
      .on('start', (e, d) => {
        if (!e.active) simulation.alphaTarget(0.3).restart()
        d.fx = d.x
        d.fy = d.y
      })
      .on('drag', (e, d) => {
        d.fx = e.x
        d.fy = e.y
      })
      .on('end', (e, d) => {
        if (!e.active) simulation.alphaTarget(0)
        d.fx = null
        d.fy = null
      }))
    .on('click', (e, d) => {
      e.stopPropagation()
      store.selectNode(d.id)
    })
    .on('mouseenter', (e, d) => {
      if (d.isCenter) return  // 中心节点不处理
      // 找从中心到 hover 节点的路径
      const pathNodes = findPath(centerNodeId, d.id, links)
      if (pathNodes.size > 0) {
        applyHoverHighlight(node, link, linkLabel, pathNodes)
      }
    })
    .on('mouseleave', () => {
      clearHoverHighlight(node, link, linkLabel)
    })

  // 节点形状（使用统一配置）
  node.each(function(d) {
    const el = d3.select(this)
    const style = getNodeStyle(d, { isCenter: d.isCenter })
    applyNodeShape(el, style)
  })

  // 节点标签
  node.append('text')
    .attr('dy', d => getNodeStyle(d, { isCenter: d.isCenter }).size / 2 + 12)
    .attr('text-anchor', 'middle')
    .text(d => d.name.length > 8 ? d.name.slice(0, 8) + '...' : d.name)

  // 更新位置
  simulation.on('tick', () => {
    link
      .attr('x1', d => d.source.x)
      .attr('y1', d => d.source.y)
      .attr('x2', d => d.target.x)
      .attr('y2', d => d.target.y)

    // 分数标签位置（边的中点）
    linkLabel.attr('transform', d => {
      const midX = (d.source.x + d.target.x) / 2
      const midY = (d.source.y + d.target.y) / 2
      return `translate(${midX},${midY})`
    })

    node.attr('transform', d => `translate(${d.x},${d.y})`)
  })

  // 应用初始高亮状态
  nextTick(updateHighlight)
}

// 点击空白取消激活
function handleSvgClick(event) {
  if (event.target.tagName === 'svg') {
    store.clearSelection()
  }
}

// 统一高亮更新
function updateHighlight() {
  const edgeSet = store.walkedEdgeSet.size > 0 ? store.walkedEdgeSet : store.postWalkedEdgeSet
  applyHighlight(svgRef.value, store.highlightedNodeIds, edgeSet, store.selectedNodeId)
}

// 监听高亮变化（walkedEdges 或 postWalkedEdges 变化时重新渲染）
watch([() => store.walkedEdges.length, () => store.postWalkedEdges.length], () => {
  nextTick(renderGraph)
})

// 监听边选中变化
watch(() => store.selectedEdgeId, () => {
  nextTick(renderGraph)
  nextTick(updateHighlight)
})

// 监听高亮节点集合变化
watch(() => store.highlightedNodeIds.size, updateHighlight)

// 监听配置变化，重新选中触发游走
watch([() => store.walkSteps, () => store.stepConfigs], () => {
  if (store.selectedNodeId && isPersonaWalk.value) {
    store.selectNode(store.selectedNodeId)
  }
}, { deep: true })

// 监听帖子游走配置变化
watch(() => store.postWalkConfig, () => {
  if (store.selectedNodeId && isPostWalk.value) {
    store.selectNode(store.selectedNodeId)
  }
}, { deep: true })

// 监听 CSS 过渡结束后重新渲染
function handleTransitionEnd(e) {
  if (['width', 'height', 'flex', 'flex-grow', 'flex-shrink'].includes(e.propertyName)) {
    if ((store.selectedNodeId || store.selectedEdgeId) && svgRef.value) {
      renderGraph()
      svgRef.value.style.opacity = '1'
    }
  }
}

// 布局变化时先淡出
watch(() => store.expandedPanel, () => {
  if (svgRef.value) {
    svgRef.value.style.opacity = '0'
  }
})

onMounted(() => {
  nextTick(() => {
    renderGraph()

    // 监听父容器的过渡结束事件
    if (containerRef.value) {
      // 向上找到有 transition 的父容器
      let parent = containerRef.value.parentElement
      while (parent && !parent.classList.contains('transition-all')) {
        parent = parent.parentElement
      }
      if (parent) {
        parent.addEventListener('transitionend', handleTransitionEnd)
      }
    }
  })
})

// 组件卸载时清理
onUnmounted(() => {
  if (containerRef.value) {
    let parent = containerRef.value.parentElement
    while (parent && !parent.classList.contains('transition-all')) {
      parent = parent.parentElement
    }
    if (parent) {
      parent.removeEventListener('transitionend', handleTransitionEnd)
    }
  }
})
</script>
