<template>
  <div class="roi-canvas-wrapper" ref="wrapper" tabindex="0" @keydown="onKeyDown">
    <img
      v-if="snapUrl"
      ref="bgImage"
      :src="snapUrl"
      class="bg-image"
      @load="onImageLoad"
      @error="onImageError"
    />
    <div v-else class="video-placeholder">
      <span v-if="loading">正在截取画面...</span>
      <span v-else>{{ errorMsg || '暂无画面' }}</span>
    </div>
    <canvas
      ref="canvas"
      class="roi-overlay"
      :class="{ drawing: drawMode === 'polygon' }"
      @mousedown="onMouseDown"
      @mousemove="onMouseMove"
      @dblclick="onDoubleClick"
      @contextmenu.prevent="onContextMenu"
    ></canvas>
    <!-- 绘制中浮动提示条 -->
    <div v-if="drawMode === 'polygon'" class="draw-hint-bar">
      单击添加顶点 | 双击或右键完成选区 | Esc取消 | Ctrl+Z撤销
    </div>
  </div>
</template>

<script>
export default {
  name: 'RoiCanvas',
  props: {
    rois: { type: Array, default: () => [] },
    drawMode: { type: String, default: null },
    selectedRoiId: { type: String, default: null },
    snapUrl: { type: String, default: '' }
  },
  data() {
    return {
      ctx: null,
      canvasWidth: 0,
      canvasHeight: 0,
      polygonPoints: [],
      mouseMovePoint: null,
      loading: true,
      errorMsg: '',
      resizeObserver: null
    }
  },
  watch: {
    rois: { handler() { this.redraw() }, deep: true },
    selectedRoiId() { this.redraw() },
    drawMode(newVal) {
      this.polygonPoints = []
      this.mouseMovePoint = null
      this.redraw()
      // 进入绘制模式时聚焦 wrapper 以接收键盘事件
      if (newVal && this.$refs.wrapper) {
        this.$refs.wrapper.focus()
      }
    },
    snapUrl() {
      this.loading = true
      this.errorMsg = ''
      this.$nextTick(() => this.initCanvas())
    }
  },
  mounted() {
    this.$nextTick(() => {
      this.initCanvas()
      if (this.$refs.wrapper && typeof ResizeObserver !== 'undefined') {
        this.resizeObserver = new ResizeObserver(() => {
          if (this.$refs.wrapper && this.$refs.wrapper.clientWidth > 0) {
            this.initCanvas()
          }
        })
        this.resizeObserver.observe(this.$refs.wrapper)
      }
      window.addEventListener('resize', this.handleResize)
    })
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.handleResize)
    if (this.resizeObserver) {
      this.resizeObserver.disconnect()
      this.resizeObserver = null
    }
  },
  methods: {
    onImageLoad() {
      this.loading = false
      this.$nextTick(() => this.initCanvas())
    },
    onImageError() {
      this.loading = false
      this.errorMsg = '截图加载失败，请确认摄像头正在拉流'
      this.$nextTick(() => this.initCanvas())
    },
    initCanvas() {
      const canvas = this.$refs.canvas
      const wrapper = this.$refs.wrapper
      if (!canvas || !wrapper) return
      this.canvasWidth = wrapper.clientWidth
      this.canvasHeight = wrapper.clientHeight
      canvas.width = this.canvasWidth
      canvas.height = this.canvasHeight
      this.ctx = canvas.getContext('2d')
      this.redraw()
    },
    handleResize() {
      this.initCanvas()
    },
    getCanvasPoint(e) {
      const rect = this.$refs.canvas.getBoundingClientRect()
      return {
        x: (e.clientX - rect.left) / this.canvasWidth,
        y: (e.clientY - rect.top) / this.canvasHeight
      }
    },

    // ---- 鼠标事件 ----
    onMouseDown(e) {
      if (e.button !== 0) return
      const pt = this.getCanvasPoint(e)

      if (this.drawMode === 'polygon') {
        // 多边形模式：添加顶点
        this.polygonPoints.push(pt)
        this.redraw()
        this.drawPolygonInProgress()
      } else if (!this.drawMode) {
        // 非绘制模式：点击选中 ROI
        const clickedRoi = this.findRoiAtPoint(pt)
        this.$emit('roi-selected', clickedRoi ? clickedRoi.roiId || clickedRoi.roi_id : null)
      }
    },
    onMouseMove(e) {
      if (this.drawMode !== 'polygon' || this.polygonPoints.length === 0) return
      this.mouseMovePoint = this.getCanvasPoint(e)
      this.redraw()
      this.drawPolygonInProgress()
    },
    onDoubleClick() {
      if (this.drawMode === 'polygon' && this.polygonPoints.length >= 3) {
        // 双击完成：移除最后一个重复点（双击会触发两次 mousedown）
        this.finishPolygon()
      }
    },
    onContextMenu(e) {
      if (this.drawMode === 'polygon' && this.polygonPoints.length >= 3) {
        // 右键完成选区
        this.finishPolygon()
        return
      }
      // 非绘制模式：右键删除 ROI
      if (!this.drawMode) {
        const pt = this.getCanvasPoint(e)
        const roi = this.findRoiAtPoint(pt)
        if (roi) {
          this.$emit('roi-deleted', roi.roiId || roi.roi_id)
        }
      }
    },

    // ---- 键盘事件 ----
    onKeyDown(e) {
      if (this.drawMode === 'polygon') {
        if (e.key === 'Escape') {
          // Esc 取消绘制
          this.polygonPoints = []
          this.mouseMovePoint = null
          this.$emit('draw-cancelled')
          this.redraw()
        } else if ((e.ctrlKey && e.key === 'z') || e.key === 'Backspace') {
          // Ctrl+Z 或 Backspace 撤销上一个顶点
          e.preventDefault()
          if (this.polygonPoints.length > 0) {
            this.polygonPoints.pop()
            this.redraw()
            if (this.polygonPoints.length > 0) {
              this.drawPolygonInProgress()
            }
          }
        }
      }
    },

    // ---- 多边形完成 ----
    finishPolygon() {
      const points = this.polygonPoints.map(p => ({ x: p.x, y: p.y }))
      this.$emit('roi-drawn', {
        roi_type: 'polygon',
        coordinates: JSON.stringify(points)
      })
      this.polygonPoints = []
      this.mouseMovePoint = null
      this.redraw()
    },

    // ---- ROI 查找 ----
    findRoiAtPoint(pt) {
      for (let i = this.rois.length - 1; i >= 0; i--) {
        const roi = this.rois[i]
        try {
          const coords = typeof roi.coordinates === 'string' ? JSON.parse(roi.coordinates) : roi.coordinates
          const type = roi.roiType || roi.roi_type
          if (type === 'rectangle' || type === 'fullscreen') {
            if (pt.x >= coords.x && pt.x <= coords.x + coords.w &&
                pt.y >= coords.y && pt.y <= coords.y + coords.h) {
              return roi
            }
          } else if (type === 'polygon') {
            if (this.isPointInPolygon(pt, coords)) return roi
          }
        } catch (e) { /* skip */ }
      }
      return null
    },
    isPointInPolygon(pt, polygon) {
      let inside = false
      for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
        const xi = polygon[i].x, yi = polygon[i].y
        const xj = polygon[j].x, yj = polygon[j].y
        const intersect = ((yi > pt.y) !== (yj > pt.y)) &&
          (pt.x < (xj - xi) * (pt.y - yi) / (yj - yi) + xi)
        if (intersect) inside = !inside
      }
      return inside
    },

    // ---- 绘制 ----
    redraw() {
      if (!this.ctx) return
      this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
      this.rois.forEach(roi => {
        try {
          const coords = typeof roi.coordinates === 'string' ? JSON.parse(roi.coordinates) : roi.coordinates
          const color = roi.color || '#FF0000'
          const isSelected = (roi.roiId || roi.roi_id) === this.selectedRoiId
          const type = roi.roiType || roi.roi_type

          this.ctx.strokeStyle = color
          this.ctx.lineWidth = isSelected ? 3 : 2
          this.ctx.fillStyle = color + '33'

          if (type === 'rectangle' || type === 'fullscreen') {
            const rx = coords.x * this.canvasWidth
            const ry = coords.y * this.canvasHeight
            const rw = coords.w * this.canvasWidth
            const rh = coords.h * this.canvasHeight
            this.ctx.fillRect(rx, ry, rw, rh)
            this.ctx.strokeRect(rx, ry, rw, rh)
            if (roi.name) {
              this.ctx.fillStyle = color
              this.ctx.font = '12px Arial'
              this.ctx.fillText(roi.name, rx + 4, ry + 14)
            }
          } else if (type === 'polygon') {
            this.ctx.beginPath()
            coords.forEach((p, idx) => {
              const px = p.x * this.canvasWidth
              const py = p.y * this.canvasHeight
              idx === 0 ? this.ctx.moveTo(px, py) : this.ctx.lineTo(px, py)
            })
            this.ctx.closePath()
            this.ctx.fill()
            this.ctx.stroke()
            if (roi.name && coords.length > 0) {
              this.ctx.fillStyle = color
              this.ctx.font = '12px Arial'
              this.ctx.fillText(roi.name, coords[0].x * this.canvasWidth + 4, coords[0].y * this.canvasHeight + 14)
            }
          }
        } catch (e) { /* skip */ }
      })
    },
    drawPolygonInProgress() {
      if (this.polygonPoints.length < 1) return
      this.ctx.strokeStyle = '#00FF00'
      this.ctx.lineWidth = 2
      this.ctx.setLineDash([5, 5])
      this.ctx.beginPath()
      this.polygonPoints.forEach((p, idx) => {
        const px = p.x * this.canvasWidth
        const py = p.y * this.canvasHeight
        idx === 0 ? this.ctx.moveTo(px, py) : this.ctx.lineTo(px, py)
        // 顶点圆点
        this.ctx.fillStyle = '#00FF00'
        this.ctx.fillRect(px - 4, py - 4, 8, 8)
      })
      // 鼠标跟随线（到当前鼠标位置）
      if (this.mouseMovePoint) {
        this.ctx.lineTo(
          this.mouseMovePoint.x * this.canvasWidth,
          this.mouseMovePoint.y * this.canvasHeight
        )
      }
      // 首尾闭合预览线（淡色）
      if (this.polygonPoints.length >= 3) {
        const first = this.polygonPoints[0]
        const last = this.mouseMovePoint || this.polygonPoints[this.polygonPoints.length - 1]
        this.ctx.moveTo(last.x * this.canvasWidth, last.y * this.canvasHeight)
        this.ctx.lineTo(first.x * this.canvasWidth, first.y * this.canvasHeight)
      }
      this.ctx.stroke()
      this.ctx.setLineDash([])
    }
  }
}
</script>

<style scoped>
.roi-canvas-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
  min-height: 400px;
  background: #000;
  outline: none;
}
.bg-image {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}
.video-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #666;
  font-size: 18px;
  background: #1a1a2e;
}
.roi-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
.roi-overlay.drawing {
  cursor: crosshair;
}
.draw-hint-bar {
  position: absolute;
  bottom: 10px;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(0, 0, 0, 0.75);
  color: #fff;
  padding: 6px 16px;
  border-radius: 4px;
  font-size: 13px;
  white-space: nowrap;
  pointer-events: none;
  z-index: 10;
}
</style>
