<template>
  <div
    class="base-radar-view"
    :style="{ width: canvasSize.width + 'px', height: canvasSize.height + 'px' }"
  >
    <canvas ref="canvasRef" :width="canvasSize.width" :height="canvasSize.height"></canvas>

    <div class="overlay-layer">
      <div
        v-for="target in targets"
        :key="target.id"
        class="target-point"
        :style="getTargetStyle(target)"
      >
        <span class="target-id">{{ target.id }}</span>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, ref, watch, type CSSProperties } from 'vue'
import radarUrl from '@/assets/furnitures/radar.png'
import { convert_region_r2c, rotateRect } from '@/utils/coordTransform'
import type { TargetPoint } from '@/types/radar'

defineOptions({ name: 'BaseRadarView' })

interface CanvasSize {
  width: number
  height: number
}

interface Props {
  coordinates: number[] // 检测区域坐标
  angle?: number // 旋转角度，默认 0 度
  targets?: TargetPoint[] // 目标点数组
  canvasSize?: CanvasSize // 画布尺寸，默认 500x500
  mode?: 'view' | 'edit'
}

const props = withDefaults(defineProps<Props>(), {
  canvasSize: () => ({
    width: 500,
    height: 500,
  }),
  angle: 0,
  mode: 'view',
})

const canvasRef = ref<HTMLCanvasElement | null>(null)
let ctx: CanvasRenderingContext2D | null = null

/**
 * 网格选项
 * 用于绘制背景网格的选项
 * @param width 画布宽度
 * @param height 画布高度
 * @param spacing 网格间距，默认 50
 * @param color 网格线颜色，默认 '#d9d9d7'
 * @param lineWidth 网格线宽度，默认 0.5
 */
interface GridOptions {
  width: number
  height: number
  spacing?: number
  color?: string
  lineWidth?: number
}
/**
 * 绘制背景网格
 * 50px间距的灰色网格线，辅助定位
 * @param ctx 画布上下文
 * @param options 网格选项
 */
const drawGrid = (ctx: CanvasRenderingContext2D, options: GridOptions) => {
  const { width, height, spacing = 50, color = '#d9d9d7', lineWidth = 0.5 } = options

  if (!ctx) return

  ctx.strokeStyle = color
  ctx.lineWidth = lineWidth

  // 水平网格线
  for (let y = spacing; y < height; y += spacing) {
    ctx.beginPath()
    ctx.moveTo(0, y)
    ctx.lineTo(width, y)
    ctx.stroke()
  }

  // 垂直网格线
  for (let x = spacing; x < width; x += spacing) {
    ctx.beginPath()
    ctx.moveTo(x, 0)
    ctx.lineTo(x, height)
    ctx.stroke()
  }
}

/**
 * 坐标轴选项
 * 用于绘制坐标轴的选项
 * @param width 画布宽度
 * @param height 画布高度
 * @param angle 旋转角度（单位：度），默认 0
 * @param xColor X轴颜色，默认 'red'
 * @param yColor Y轴颜色，默认 'green'
 */
interface CoordinateOptions {
  width: number
  height: number
  angle?: number
  xColor?: string
  yColor?: string
}
/**
 * 绘制坐标轴
 * 虚线样式的X轴和Y轴，标识坐标系中心
 * @param ctx 画布上下文
 * @param options 坐标轴选项
 */
const drawCoordinateAxes = (ctx: CanvasRenderingContext2D, options: CoordinateOptions) => {
  const { width, height, angle = 0, xColor = '#2c3e50', yColor = '#2c3e50' } = options

  if (!ctx) return

  const centerX = width / 2
  const centerY = height / 2
  // const arrowSize = 10

  // 只接受 0, 90, 180, 270，其他归为 0
  const validAngles: number[] = [0, 90, 180, 270]
  const rotationDeg: number = validAngles.includes(angle) ? angle : 0
  const rotationRad = (rotationDeg * Math.PI) / 180

  ctx.save()
  ctx.translate(centerX, centerY)
  ctx.rotate(rotationRad)
  ctx.translate(-centerX, -centerY)

  ctx.lineWidth = 1
  ctx.setLineDash([5, 5])

  // 绘制X轴（水平线）
  ctx.strokeStyle = xColor
  ctx.beginPath()
  ctx.moveTo(0, centerY)
  ctx.lineTo(width, centerY)
  ctx.stroke()

  // X轴箭头（右端）
  // ctx.beginPath()
  // ctx.moveTo(width, centerY)
  // ctx.lineTo(width - arrowSize, centerY - arrowSize / 2)
  // ctx.lineTo(width - arrowSize, centerY + arrowSize / 2)
  // ctx.closePath()
  // ctx.fillStyle = xColor
  // ctx.fill()

  // 绘制Y轴（垂直线）
  ctx.strokeStyle = yColor
  ctx.beginPath()
  ctx.moveTo(centerX, 0)
  ctx.lineTo(centerX, height)
  ctx.stroke()

  // Y轴箭头（顶部）
  // ctx.beginPath()
  // ctx.moveTo(centerX, 0)
  // ctx.lineTo(centerX - arrowSize / 2, arrowSize)
  // ctx.lineTo(centerX + arrowSize / 2, arrowSize)
  // ctx.closePath()
  // ctx.fillStyle = yColor
  // ctx.fill()

  ctx.setLineDash([])
  ctx.restore()
}

/**
 * 雷达图图片选项
 * 用于绘制雷达图图片的选项
 * @param width 画布宽度
 * @param height 画布高度
 * @param radarImage 雷达图图片
 * @param angle 旋转角度，默认 0
 * @param size 图片尺寸（宽高），默认 20
 * @param offset 图片偏移角度，默认 90 度 指向X轴
 */
interface RadarImageOptions {
  width: number
  height: number
  radarImage: HTMLImageElement
  angle?: number
  size?: number
  offset?: number
}
/**
 * 绘制雷达图
 * 图片以指定角度旋转，默认指向X轴
 * @param ctx 画布上下文
 * @param options 雷达图图片选项
 */
const drawRadarImage = (ctx: CanvasRenderingContext2D, options: RadarImageOptions) => {
  const { width, height, angle = 0, size = 20, radarImage, offset = 90 } = options

  const centerX = width / 2
  const centerY = height / 2
  const halfSize = size / 2
  const angleRad = ((angle + offset) * Math.PI) / 180

  ctx.save()
  ctx.translate(centerX, centerY)
  ctx.rotate(angleRad)
  ctx.drawImage(radarImage, -halfSize, -halfSize, size, size)
  ctx.restore()
}

/**
 * 检测区域选项
 * 用于绘制检测区域的选项
 * @param area 检测区域坐标 [xStart, xEnd, yStart, yEnd]
 * @param radarPosition 雷达图位置 { x_radar, y_radar }
 * @param angle 旋转角度（单位：度），默认 0
 */
interface DetectionAreaOptions {
  area: number[] // 检测区域坐标 [xStart, xEnd, yStart, yEnd]
  radarPosition: {
    x_radar: number
    y_radar: number
  }
  angle?: number
}
/**
 * 绘制检测区域
 * @param ctx 画布上下文
 * @param options 检测区域选项
 */
const drawDetectionArea = (ctx: CanvasRenderingContext2D, options: DetectionAreaOptions) => {
  const { area, radarPosition, angle = 0 } = options
  const [xStart, xEnd, yStart, yEnd] = area
  const canvasRect = convert_region_r2c(
    {
      x_cm_start: xStart,
      x_cm_stop: xEnd,
      y_cm_start: yStart,
      y_cm_stop: yEnd,
    },
    radarPosition
  )

  const rotatedRect = rotateRect(
    {
      left: canvasRect.left,
      top: canvasRect.top,
      width: canvasRect.width,
      height: canvasRect.height,
    },
    { x: radarPosition.x_radar, y: radarPosition.y_radar },
    angle
  )

  if (!ctx) return

  // 绘制蓝色边框
  ctx.strokeStyle = '#1677ff'
  ctx.lineWidth = 1
  ctx.strokeRect(rotatedRect.left, rotatedRect.top, rotatedRect.width, rotatedRect.height)

  // 添加半透明蓝色填充
  ctx.fillStyle = 'rgba(52, 152, 219, 0.3)'
  ctx.fillRect(rotatedRect.left, rotatedRect.top, rotatedRect.width, rotatedRect.height)
}

/**
 * 绘制画布
 */
const drawCanvans = () => {
  /* 初始化画布 */
  if (!canvasRef.value) return
  ctx = canvasRef.value.getContext('2d')
  if (!ctx) return

  const CANVAS_W = props.canvasSize.width
  const CANVAS_H = props.canvasSize.height

  const CANVAS_SIZE = {
    width: CANVAS_W,
    height: CANVAS_H,
  }

  const radarPosition = {
    x_radar: CANVAS_W / 2,
    y_radar: CANVAS_H / 2,
  }

  /* 清除画布并设置背景色 */
  ctx.clearRect(0, 0, CANVAS_W, CANVAS_H)
  ctx.fillStyle = '#f2f2f0'
  ctx.fillRect(0, 0, CANVAS_W, CANVAS_H)

  /* 绘制网格和坐标轴 */
  drawGrid(ctx, { width: CANVAS_W, height: CANVAS_H })
  drawCoordinateAxes(ctx, { ...CANVAS_SIZE, angle: props.angle })

  /* 绘制雷达图 */
  const radarImage = new Image()
  radarImage.src = radarUrl
  radarImage.onload = () => {
    if (!ctx) return
    drawRadarImage(ctx, { ...CANVAS_SIZE, radarImage, angle: props.angle })
  }

  /* 绘制检测区域 */
  drawDetectionArea(ctx, { area: props.coordinates, radarPosition, angle: props.angle })
}

// 监听角度变化，重新绘制画布
watch(
  () => [props.coordinates, props.angle],
  () => {
    drawCanvans()
  },
  {
    immediate: true,
  }
)

onMounted(() => {
  drawCanvans()
})

/**
 * 获取目标点样式
 * @param target 目标点
 * @returns 目标点样式
 */
const getTargetStyle = (target: TargetPoint) => {
  const colorPalette = ['red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'purple']

  const colorIndex = target.id < colorPalette.length ? target.id : colorPalette.length - 1
  const color = colorPalette[colorIndex]

  return {
    position: 'absolute',
    width: '18px',
    height: '18px',
    background: color,
    borderRadius: '50%',
    transform: `translate3d(${target.displayX}px, ${target.displayY}px, 0) translate(-50%, -50%)`,
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    color: 'white',
    fontSize: '12px',
    fontWeight: '600',
    pointerEvents: 'none',
    zIndex: 10,
    transition: 'transform 1s linear',
    willChange: 'transform',
    boxShadow: '0 0 8px rgba(0, 0, 0, 0.5)',
    userSelect: 'none',
  } as CSSProperties
}
</script>

<style scoped lang="less">
.base-radar-view {
  position: relative;
  display: flex;

  canvas {
    border: 2px solid #ddd;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    pointer-events: none;
  }

  .overlay-layer {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: auto;

    .target-point {
      position: absolute;
      pointer-events: none;
    }
  }
}
</style>
