<template>
  <canvas ref="canvasRef" style="border:1px solid #ccc; cursor: grab;"></canvas>
</template>
<script lang='ts' setup>
import { onMounted, PropType, ref, watch } from 'vue'

const props = defineProps({
  cardData: {
    type: Object as PropType<API.Card>,
    default: () => ({})
  },
  config: {
    type: Object as PropType<API.CardJson>,
    default: () => ({})
  }
})

const canvasRef = ref<HTMLCanvasElement | null>(null)
const img = new window.Image()
img.src = props.cardData.img

// 矩形参数
const rectWidth = 180
const rectHeight = 240
const rects = [] as { id: number, name: string, x: number, y: number, width: number, height: number }[]
const rectGapX = 127 // 矩形间横向间隔
const rectGapY = 146 // 矩形间纵向间隔
const startX = 112 // 图片内第一个矩形的x偏移
const startY = -56 // 图片内第一个矩形的y偏移

// 生成矩形数据
function generateRects () {
  rects.length = 0
  const firstRowGapX = 96
  props.config.touch_key.forEach(item => {
    if (item.id < 3) {
      for (let i = 0; i < 3; i++) {
        rects.push({
          id: item.id,
          name: item.name,
          x: startX + item.id * (rectWidth - 40 + firstRowGapX) + 1166,
          y: startY + 116,
          width: rectWidth - 40,
          height: rectHeight - 100
        })
      }
    } else {
      rects.push({
        id: item.id,
        name: item.name,
        x: startX + item.col * (rectWidth + rectGapX),
        y: startY + item.row * (rectHeight + rectGapY),
        width: rectWidth,
        height: rectHeight
      })
    }
  })
}

// 图片状态
const state = {
  scale: 0.3, // 初始缩放为0.5
  minScale: 0.2,
  maxScale: 5,
  offsetX: 0,
  offsetY: 0,
  dragging: false,
  lastX: 0,
  lastY: 0,
  selectedRectId: null as number | null
}

// 选择框状态
const selection = {
  selecting: false,
  startX: 0,
  startY: 0,
  endX: 0,
  endY: 0
}

// 多选集合
const selectedRectIds = ref<number[]>([])

const emits = defineEmits(['operation'])

// 框选操作 and 点选操作
const handleOperation = (ids: number[]) => {
  emits('operation', { ids })
}

function centerImage () {
  const canvas = canvasRef.value
  if (!canvas) return
  const imgW = img.width * state.scale
  const imgH = img.height * state.scale
  state.offsetX = (canvas.width - imgW) / 2
  state.offsetY = (canvas.height - imgH) / 2
}

function resizeCanvas () {
  const canvas = canvasRef.value
  if (!canvas) return
  canvas.width = window.innerWidth
  canvas.height = window.innerHeight
  centerImage()
  draw()
}

// 绘制网格、图片和矩形
function draw () {
  const canvas = canvasRef.value
  if (!canvas) return
  const ctx = canvas.getContext('2d')!
  ctx.clearRect(0, 0, canvas.width, canvas.height)

  // 画网格
  const gridSize = 20
  ctx.save()
  ctx.strokeStyle = '#eee'
  for (let x = 0; x < canvas.width; x += gridSize) {
    ctx.beginPath()
    ctx.moveTo(x, 0)
    ctx.lineTo(x, canvas.height)
    ctx.stroke()
  }
  for (let y = 0; y < canvas.height; y += gridSize) {
    ctx.beginPath()
    ctx.moveTo(0, y)
    ctx.lineTo(canvas.width, y)
    ctx.stroke()
  }
  ctx.restore()

  // 画图片
  if (img.complete) {
    const imgW = img.width * state.scale
    const imgH = img.height * state.scale
    ctx.drawImage(img, state.offsetX, state.offsetY, imgW, imgH)

    // 画矩形（随图片缩放和移动）
    rects.forEach(rect => {
      const rx = state.offsetX + rect.x * state.scale
      const ry = state.offsetY + rect.y * state.scale
      const rw = rect.width * state.scale
      const rh = rect.height * state.scale
      ctx.save()
      ctx.lineWidth = 2
      const isSelected = rect.id === state.selectedRectId || props.config.touch_key.find(item => item.id === rect.id)?.selected
      ctx.strokeStyle = isSelected ? '#ff6600' : '#007bff'
      ctx.globalAlpha = 0.5
      ctx.fillStyle = isSelected ? '#ff660033' : '#007bff22'
      ctx.fillRect(rx, ry, rw, rh)
      ctx.globalAlpha = 1
      ctx.strokeRect(rx, ry, rw, rh)
      // 绘制序号
      ctx.font = `bold ${Math.floor(rh / 1.7)}px sans-serif`
      ctx.fillStyle = isSelected ? '#ff6600' : '#333'
      ctx.textAlign = 'center'
      ctx.textBaseline = 'middle'
      ctx.fillText(rect.name, rx + rw / 2, ry + rh / 2)
      ctx.restore()
    })

    // 画选择框
    if (selection.selecting) {
      ctx.save()
      ctx.strokeStyle = '#1890ff'
      ctx.setLineDash([6, 4])
      ctx.lineWidth = 2
      ctx.globalAlpha = 0.7
      const x = Math.min(selection.startX, selection.endX)
      const y = Math.min(selection.startY, selection.endY)
      const w = Math.abs(selection.endX - selection.startX)
      const h = Math.abs(selection.endY - selection.startY)
      ctx.strokeRect(x, y, w, h)
      ctx.restore()
    }
  }
}

function onWheel (e: WheelEvent) {
  if (!e.ctrlKey) return
  e.preventDefault()
  const { offsetX, offsetY, deltaY } = e
  // 计算缩放中心
  const prevScale = state.scale
  if (deltaY < 0) {
    state.scale = Math.min(state.maxScale, state.scale * 1.1)
  } else {
    state.scale = Math.max(state.minScale, state.scale / 1.1)
  }
  // 缩放时保持鼠标点下的内容不动
  const scaleRatio = state.scale / prevScale
  state.offsetX = offsetX - (offsetX - state.offsetX) * scaleRatio
  state.offsetY = offsetY - (offsetY - state.offsetY) * scaleRatio
  draw()
}

function onMouseDown (e: MouseEvent) {
  // 判断是否按住shift进行多选框选
  if (e.button === 0 && e.shiftKey) {
    selection.selecting = true
    selection.startX = e.offsetX
    selection.startY = e.offsetY
    selection.endX = e.offsetX
    selection.endY = e.offsetY
    draw()
    return
  }
  // 鼠标左键直接拖拽图片（不需要ctrl）
  if (e.button === 0) {
    state.dragging = true
    state.lastX = e.clientX
    state.lastY = e.clientY
    const canvas = canvasRef.value
    if (canvas) canvas.style.cursor = 'grabbing'
    // 判断是否点在某个矩形内，若是则不做任何高亮处理
    const x = e.offsetX
    const y = e.offsetY
    for (const rect of rects) {
      const rx = state.offsetX + rect.x * state.scale
      const ry = state.offsetY + rect.y * state.scale
      const rw = rect.width * state.scale
      const rh = rect.height * state.scale
      if (x >= rx && x <= rx + rw && y >= ry && y <= ry + rh) {
        // 点在矩形内，直接return，不清空高亮
        return
      }
    }
  }
}

let rafId: number | null = null

function scheduleDraw () {
  if (rafId !== null) return
  rafId = requestAnimationFrame(() => {
    draw()
    rafId = null
  })
}

function onMouseMove (e: MouseEvent) {
  if (selection.selecting) {
    selection.endX = e.offsetX
    selection.endY = e.offsetY
    scheduleDraw()
    return
  }
  if (!state.dragging) return
  const dx = e.clientX - state.lastX
  const dy = e.clientY - state.lastY
  if (dx === 0 && dy === 0) return
  state.offsetX += dx
  state.offsetY += dy
  state.lastX = e.clientX
  state.lastY = e.clientY
  scheduleDraw()
}

function onMouseUp (e?: MouseEvent) {
  if (selection.selecting) {
    // 计算选择框范围
    const x1 = Math.min(selection.startX, selection.endX)
    const y1 = Math.min(selection.startY, selection.endY)
    const x2 = Math.max(selection.startX, selection.endX)
    const y2 = Math.max(selection.startY, selection.endY)
    // 判断哪些rect被框选
    const selected: number[] = []
    rects.forEach(rect => {
      const rx = state.offsetX + rect.x * state.scale
      const ry = state.offsetY + rect.y * state.scale
      const rw = rect.width * state.scale
      const rh = rect.height * state.scale
      // 判断矩形中心点是否在选择框内
      const cx = rx + rw / 2
      const cy = ry + rh / 2
      if (cx >= x1 && cx <= x2 && cy >= y1 && cy <= y2) {
        selected.push(rect.id)
      }
    })
    selection.selecting = false
    draw()
    handleOperation(selected)
    return
  }
  state.dragging = false
  const canvas = canvasRef.value
  if (canvas) canvas.style.cursor = 'grab'
}

function onClick (e: MouseEvent) {
  // 计算点击点在图片坐标系下的位置
  const canvas = canvasRef.value
  if (!canvas) return
  // 如果正在批量框选（shift按下），不处理单选逻辑
  if (e.shiftKey) return
  const x = e.offsetX
  const y = e.offsetY
  let found: number | null = null
  for (const rect of rects) {
    const rx = state.offsetX + rect.x * state.scale
    const ry = state.offsetY + rect.y * state.scale
    const rw = rect.width * state.scale
    const rh = rect.height * state.scale
    if (x >= rx && x <= rx + rw && y >= ry && y <= ry + rh) {
      found = rect.id
      break
    }
  }
  handleOperation([found!])
  draw()
}

onMounted(() => {
  img.onload = () => {
    resizeCanvas()
  }
  const canvas = canvasRef.value
  if (!canvas) return
  resizeCanvas()
  window.addEventListener('resize', resizeCanvas)
  canvas.addEventListener('wheel', onWheel, { passive: false })
  canvas.addEventListener('mousedown', onMouseDown)
  window.addEventListener('mousemove', onMouseMove)
  window.addEventListener('mouseup', onMouseUp)
  canvas.addEventListener('click', onClick)
})

const delSelectedRectIds = () => draw()

watch(
  () => props.config,
  () => {
    const ids = props.config.touch_key.filter(item => item.music_name).map(_ => _.id)
    selectedRectIds.value = ids
    generateRects()
    draw()
  }, {
    deep: true
  }
)

defineExpose({
  delSelectedRectIds
})

</script>
<style lang='less' scoped>
canvas {
  background: #fff;
  display: block;
  position: fixed;
  left: 0;
  top: 0;
  width: 100vw;
  height: 100vh;
  z-index: 10;
}
</style>
