<template>
  <div class="process-flow">
    <canvas ref="canvasRef" :width="canvasWidth" :height="height"></canvas>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, computed, watch, nextTick, onUnmounted } from 'vue'

interface Node {
  text: string
}

const props = defineProps<{
  nodes: Node[]
}>()

const canvasRef = ref<HTMLCanvasElement | null>(null)
const canvasWidth = computed(() => window.innerWidth - 40)

const NODES_PER_ROW = 3
const NODE_HEIGHT = 100
const NODE_WIDTH = computed(() => (canvasWidth.value - 60) / NODES_PER_ROW)
const HORIZONTAL_PADDING = 30
const NODE_RADIUS = 8
const LINE_GAP = 16

const height = computed(() => {
  const rows = Math.ceil(props.nodes.length / NODES_PER_ROW)
  return rows * NODE_HEIGHT + 40
})

const drawFlow = () => {
  const canvas = canvasRef.value
  if (!canvas) return

  const ctx = canvas.getContext('2d')
  if (!ctx) return

  ctx.clearRect(0, 0, canvasWidth.value, height.value)
  
  const nodeCount = props.nodes.length
  if (nodeCount <= 1) return

  // 先绘制连接线
  for (let i = 0; i < nodeCount - 1; i++) {
    drawConnection(ctx, i)
  }

  // 再绘制节点和文字
  for (let i = 0; i < nodeCount; i++) {
    const pos = getNodePosition(i)
    drawNode(ctx, pos, props.nodes[i])
  }
}

const drawNode = (
  ctx: CanvasRenderingContext2D, 
  pos: { x: number; y: number }, 
  node: Node
) => {
  const x = pos.x + NODE_WIDTH.value / 2
  const y = pos.y + 16

  // 绘制圆点
  ctx.beginPath()
  ctx.arc(x, y, NODE_RADIUS, 0, Math.PI * 2)
  ctx.fillStyle = '#1989fa'
  ctx.fill()
  ctx.strokeStyle = '#fff'
  ctx.lineWidth = 2
  ctx.stroke()

  // 绘制文字
  ctx.font = '14px Arial'
  ctx.fillStyle = '#1989fa'
  ctx.textAlign = 'center'
  ctx.textBaseline = 'top'
  ctx.fillText(node.text, x, y + 24)
}

const drawConnection = (ctx: CanvasRenderingContext2D, index: number) => {
  const currentRow = Math.floor(index / NODES_PER_ROW)
  const nextRow = Math.floor((index + 1) / NODES_PER_ROW)
  const isRightToLeft = currentRow % 2 !== 0

  const startPos = getNodePosition(index)
  const endPos = getNodePosition(index + 1)

  const startX = startPos.x + NODE_WIDTH.value / 2
  const startY = startPos.y + 16
  const endX = endPos.x + NODE_WIDTH.value / 2
  const endY = endPos.y + 16

  // 设置线条样式
  ctx.beginPath()
  ctx.strokeStyle = '#1989fa'
  ctx.lineWidth = 2

  if (currentRow !== nextRow) {
    // 垂直连接
    const midY = startY + (NODE_HEIGHT / 2)
    ctx.moveTo(startX, startY + LINE_GAP)
    ctx.lineTo(startX, midY)
    ctx.lineTo(endX, midY)
    ctx.lineTo(endX, endY - LINE_GAP)
  } else {
    // 水平连接
    const startOffsetX = isRightToLeft ? -LINE_GAP : LINE_GAP
    const endOffsetX = isRightToLeft ? LINE_GAP : -LINE_GAP
    ctx.moveTo(startX + startOffsetX, startY)
    ctx.lineTo(endX + endOffsetX, endY)
  }
  ctx.stroke()

  // 绘制箭头
  const angle = currentRow !== nextRow ? Math.PI / 2 : (isRightToLeft ? Math.PI : 0)
  const arrowX = currentRow !== nextRow ? endX : (endX + (isRightToLeft ? LINE_GAP : -LINE_GAP))
  const arrowY = currentRow !== nextRow ? endY - LINE_GAP : endY
  drawArrow(ctx, arrowX, arrowY, angle)
}

const drawArrow = (
  ctx: CanvasRenderingContext2D, 
  x: number, 
  y: number, 
  angle: number
) => {
  const arrowSize = 6
  
  ctx.save()
  ctx.translate(x, y)
  ctx.rotate(angle)
  
  ctx.beginPath()
  ctx.moveTo(-arrowSize, -arrowSize/2)
  ctx.lineTo(0, 0)
  ctx.lineTo(-arrowSize, arrowSize/2)
  ctx.closePath()
  ctx.fillStyle = '#1989fa'
  ctx.fill()
  
  ctx.restore()
}

const getNodePosition = (index: number) => {
  const row = Math.floor(index / NODES_PER_ROW)
  const isRightToLeft = row % 2 !== 0
  let col = index % NODES_PER_ROW
  
  if (isRightToLeft) {
    col = NODES_PER_ROW - 1 - col
  }

  return {
    x: col * NODE_WIDTH.value + HORIZONTAL_PADDING,
    y: row * NODE_HEIGHT + 40
  }
}

// 监听窗口大小变化
const handleResize = () => {
  if (canvasRef.value) {
    canvasRef.value.width = canvasWidth.value
    nextTick(drawFlow)
  }
}

onMounted(() => {
  window.addEventListener('resize', handleResize)
  drawFlow()
})

onUnmounted(() => {
  window.removeEventListener('resize', handleResize)
})

watch(
  () => props.nodes.length,
  () => {
    nextTick(drawFlow)
  }
)
</script>

<style scoped lang="scss">
.process-flow {
  position: relative;
  margin: 20px;
  background: #fff;
  border-radius: 12px;
  width: auto;
  box-sizing: border-box;
  min-height: 300px;
}
</style>