<template>
  <div class="detection-area-view">
    <canvas ref="canvasRef" width="500" height="500"></canvas>

    <div class="overlay-layer">
      <template v-if="mode === 'view'">
        <div class="furniture-container" :class="{ 'clip-overflow': mode === 'view' }">
          <div v-for="item in localFurnitureItems" :key="item.nanoid" class="furniture-item">
            <div class="furniture-rotated-container" :style="getRotatedContainerStyle(item)">
              <furnitureIcon :icon="item.type" :width="item.width" :height="item.length" />
            </div>
          </div>
        </div>

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

      <template v-else>
        <slot name="furnitures"> </slot>

        <div class="subregion-container">
          <slot name="subregion"></slot>
        </div>
      </template>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, watch, computed, type CSSProperties } from 'vue'
import type { TargetPoint } from '@/types/radar'
import {
  convert_region_r2c,
  convert_region_c2r,
  convert_furniture_r2c,
  convert_furniture_c2r,
  type RadarRect,
  type CanvasRect,
  type RadarPosition,
  type RadarFurniture,
  rotateRect,
} from '@/utils/coordTransform'
import radarUrl from '@/assets/furnitures/radar.png'
import type { LocalFurnitureItem } from '@/api/room/types'

defineOptions({ name: 'DetectionAreaView' })

/**
 * 组件属性接口定义
 * @property coordinates - 检测区域坐标 [x起始, x结束, y起始, y结束]，单位：厘米
 * @property direction - 设备方向角度，0-360度，默认90度（东向）
 * @property furnitureItems - 家具配置项列表
 * @property targets - 目标点位数据
 * @property mode - 组件工作模式：view(展示) 或 edit(编辑)
 */
interface Props {
  coordinates: [number, number, number, number]
  direction?: number
  furnitureItems?: LocalFurnitureItem[]
  targets?: TargetPoint[]
  mode?: 'view' | 'edit'
}

// 属性默认值配置
const props = withDefaults(defineProps<Props>(), {
  direction: 90,
  furnitureItems: () => [],
  targets: () => [],
  mode: 'view',
})

// 画布配置常量
const CANVAS_SIZE = 500 // 画布尺寸（像素）
const RADAR_RANGE = 500 // 雷达检测范围（厘米）

// Canvas 相关引用
const canvasRef = ref<HTMLCanvasElement | null>(null)
let ctx: CanvasRenderingContext2D | null = null

// 雷达图片加载处理
const radarImage = new Image()
radarImage.src = radarUrl
let isRadarImageLoaded = false

radarImage.onload = () => {
  isRadarImageLoaded = true
  drawDetectionArea()
}

// 雷达在画布中的中心点位置
const radarPosition: RadarPosition = {
  x_radar: CANVAS_SIZE / 2,
  y_radar: CANVAS_SIZE / 2,
}

// 设备显示配置
const device = {
  x: CANVAS_SIZE / 2, // 设备在画布中的x坐标
  y: CANVAS_SIZE / 2, // 设备在画布中的y坐标
  size: 20, // 设备图标尺寸
}

const localFurnitureItems = computed(() => {
  return props.furnitureItems.map((item) => {
    const itemConvert = convert_furniture_r2c(
      {
        x: item.x,
        y: item.y,
        width: item.width,
        height: item.length,
      },
      radarPosition
    )
    const rotatedRect = rotateRect(
      {
        left: itemConvert.left,
        top: itemConvert.top,
        width: item.width,
        height: item.length,
      },
      {
        x: CANVAS_SIZE / 2,
        y: CANVAS_SIZE / 2,
      },
      props.direction
    )
    return {
      ...item,
      left: rotatedRect.left,
      top: rotatedRect.top,
      width: rotatedRect.width,
      length: rotatedRect.height,
    }
  })
})

watch(localFurnitureItems, (newItems) => {
  console.log('🔥🔥🔥🔥🔥🔥🔥🔥🔥localFurnitureItems', newItems)
})

/**
 * 计算旋转后的边界框（基于左上角基准）
 */
const calculateBoundingBox = (width: number, length: number, rotate: number) => {
  const rad = (rotate * Math.PI) / 180

  if (rotate === 0) {
    return {
      left: 0,
      right: width,
      top: 0,
      bottom: length,
      width: width,
      height: length,
    }
  }

  // 计算旋转后的四个角点（相对于左上角）
  const corners = [
    { x: 0, y: 0 }, // 左上
    { x: width, y: 0 }, // 右上
    { x: width, y: length }, // 右下
    { x: 0, y: length }, // 左下
  ]

  // 旋转角点（围绕左上角旋转）
  const rotatedCorners = corners.map((corner) => ({
    x: corner.x * Math.cos(rad) - corner.y * Math.sin(rad),
    y: corner.x * Math.sin(rad) + corner.y * Math.cos(rad),
  }))

  // 计算边界框
  const xs = rotatedCorners.map((c) => c.x)
  const ys = rotatedCorners.map((c) => c.y)

  const minX = Math.min(...xs)
  const maxX = Math.max(...xs)
  const minY = Math.min(...ys)
  const maxY = Math.max(...ys)

  return {
    left: minX,
    right: maxX,
    top: minY,
    bottom: maxY,
    width: maxX - minX,
    height: maxY - minY,
  }
}

/**
 * 地理坐标转换为像素坐标（左上角基准）
 */
const geoToPixel = (geoX: number, geoY: number): { x: number; y: number } => {
  const radarFurniture: RadarFurniture = {
    x: geoX,
    y: geoY,
    width: 0,
    height: 0,
  }

  const canvasRect = convert_furniture_r2c(radarFurniture, radarPosition)
  return {
    x: canvasRect.left,
    y: canvasRect.top,
  }
}

/**
 * 获取旋转容器样式 - 调整位置使内容在边界框中正确显示
 */
const getRotatedContainerStyle = (item: LocalFurnitureItem) => {
  const cssObj = {
    position: 'absolute',
    left: `${item.left}px`,
    top: `${item.top}px`,
    width: `${item.width}px`,
    height: `${item.length}px`,
    transform: `rotate(${item.rotate || 0}deg)`,
    transformOrigin: '0 0',
  } as CSSProperties

  return cssObj
}

const pixelToGeo = (pixelX: number, pixelY: number): { x: number; y: number } => {
  const canvasRect: CanvasRect = {
    left: pixelX,
    top: pixelY,
    width: 0,
    height: 0,
  }

  const radarFurniture = convert_furniture_c2r(canvasRect, radarPosition)
  return {
    x: radarFurniture.x,
    y: radarFurniture.y,
  }
}

/**
 * 根据设备方向转换检测区域坐标
 * 将原始检测区域坐标转换为设备当前朝向下的实际坐标
 * @param area - 原始检测区域坐标 [xStart, xEnd, yStart, yEnd]
 * @param direction - 设备方向角度（0-360度）
 * @returns 转换后的检测区域坐标
 */
const convertAreaByDirection = (
  area: [number, number, number, number],
  direction: number
): [number, number, number, number] => {
  const [xStart, xEnd, yStart, yEnd] = area
  const normalizedDirection = ((direction % 360) + 360) % 360

  switch (normalizedDirection) {
    case 0: // 设备朝东：保持原始坐标系（x轴朝右）
      return [xStart, xEnd, yStart, yEnd]
    case 90: // 设备朝南：y轴反向
      return [yEnd, yStart, -xEnd, -xStart]
    case 180: // 设备朝西：x轴反向
      return [-xEnd, -xStart, -yEnd, -yStart]
    case 270: // 设备朝北：x轴反向，y轴反向
      return [-yEnd, -yStart, xStart, xEnd]
    default: // 其他角度使用任意角度转换
      return convertAreaForArbitraryAngle(area, direction)
  }
}

/**
 * 任意角度的检测区域坐标转换
 * 通过旋转矩阵计算区域四个角点在新方向下的坐标范围
 * @param area - 原始检测区域坐标
 * @param direction - 设备方向角度
 * @returns 旋转后的检测区域边界坐标
 */
const convertAreaForArbitraryAngle = (
  area: [number, number, number, number],
  direction: number
): [number, number, number, number] => {
  const [xStart, xEnd, yStart, yEnd] = area

  // 定义检测区域的四个角点
  const corners = [
    { x: xStart, y: yStart }, // 左下角
    { x: xEnd, y: yStart }, // 右下角
    { x: xStart, y: yEnd }, // 左上角
    { x: xEnd, y: yEnd }, // 右上角
  ]

  const rotationAngle = (-direction * Math.PI) / 180
  const cosA = Math.cos(rotationAngle)
  const sinA = Math.sin(rotationAngle)

  const rotatedCorners = corners.map((corner) => {
    return {
      x: corner.x * cosA - corner.y * sinA,
      y: corner.x * sinA + corner.y * cosA,
    }
  })

  const xValues = rotatedCorners.map((c) => c.x)
  const yValues = rotatedCorners.map((c) => c.y)

  return [Math.min(...xValues), Math.max(...xValues), Math.min(...yValues), Math.max(...yValues)]
}

const convertedCoordinates = computed(() => {
  return convertAreaByDirection(props.coordinates, props.direction)
})

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
}

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

  ctx = canvasRef.value.getContext('2d')
  if (!ctx) return

  drawDetectionArea()
}

/**
 * 绘制完整的检测区域视图
 * 包含背景、网格、边界、坐标轴、设备和信息文本
 */
const drawDetectionArea = () => {
  if (!ctx || !canvasRef.value) return

  // 清除画布
  ctx.clearRect(0, 0, CANVAS_SIZE, CANVAS_SIZE)

  // 设置浅灰色背景
  ctx.fillStyle = '#f2f2f0'
  ctx.fillRect(0, 0, CANVAS_SIZE, CANVAS_SIZE)

  // 依次绘制各个图层
  drawGrid() // 背景网格
  drawRadarBoundary() // 雷达边界
  drawAreaBorder() // 检测区域边框
  drawCoordinateAxes() // 坐标轴
  drawRadarDevice() // 雷达设备
  drawInfoText() // 信息文本
}

/**
 * 绘制雷达设备图标
 * 根据设备方向旋转显示雷达图标
 */
const drawRadarDevice = () => {
  if (!ctx) return

  // 图片未加载时使用备用绘制方案
  if (!isRadarImageLoaded) {
    drawRadarDeviceFallback()
    return
  }

  // 保存当前画布状态
  ctx.save()

  // 移动到设备中心并应用旋转
  ctx.translate(device.x, device.y)
  const rotation = props.direction + 90
  ctx.rotate((rotation * Math.PI) / 180)

  // 绘制居中的雷达图标
  const imageSize = device.size
  ctx.drawImage(radarImage, -imageSize / 2, -imageSize / 2, imageSize, imageSize)

  // 恢复画布状态
  ctx.restore()
}

/**
 * 雷达设备备用绘制方案
 * 在雷达图片加载失败时使用矢量图形绘制设备
 */
const drawRadarDeviceFallback = () => {
  if (!ctx) return

  // 绘制设备主体（红色圆形）
  ctx.fillStyle = '#e74c3c'
  ctx.beginPath()
  ctx.arc(device.x, device.y, device.size / 2, 0, Math.PI * 2)
  ctx.fill()

  // 保存画布状态以应用旋转
  ctx.save()
  ctx.translate(device.x, device.y)
  const rotation = props.direction
  ctx.rotate((rotation * Math.PI) / 180)

  // 绘制方向指示器（白色三角形）
  ctx.fillStyle = '#fff'
  ctx.strokeStyle = '#e74c3c'
  ctx.lineWidth = 1

  const indicatorLength = device.size * 0.6
  const indicatorWidth = device.size * 0.3

  ctx.beginPath()
  ctx.moveTo(0, -device.size / 2 - indicatorLength)
  ctx.lineTo(-indicatorWidth / 2, -device.size / 2)
  ctx.lineTo(indicatorWidth / 2, -device.size / 2)
  ctx.closePath()
  ctx.fill()
  ctx.stroke()

  ctx.restore()
}

/**
 * 绘制信息文本
 * 在画布左下角显示检测区域坐标信息
 */
const drawInfoText = () => {
  if (!ctx) return

  const [xStart, xEnd, yStart, yEnd] = props.coordinates
  const [convertedXStart, convertedXEnd, convertedYStart, convertedYEnd] =
    convertedCoordinates.value

  ctx.fillStyle = '#2c3e50'
  ctx.font = '12px Arial'
  ctx.textAlign = 'left'

  const baseX = 5
  const baseY = CANVAS_SIZE - 10

  ctx.fillText(`原始区域: [${xStart}, ${xEnd}, ${yStart}, ${yEnd}] cm`, baseX, baseY - 15)
  ctx.fillText(
    `转换区域: [${Math.round(convertedXStart)}, ${Math.round(convertedXEnd)}, ${Math.round(convertedYStart)}, ${Math.round(convertedYEnd)}] cm`,
    baseX,
    baseY
  )
}

/**
 * 绘制背景网格
 * 50px间距的灰色网格线，辅助定位
 */
const drawGrid = () => {
  if (!ctx) return

  ctx.strokeStyle = '#d9d9d7'
  ctx.lineWidth = 0.5

  // 绘制水平网格线
  for (let i = 50; i < CANVAS_SIZE; i += 50) {
    ctx.beginPath()
    ctx.moveTo(0, i)
    ctx.lineTo(CANVAS_SIZE, i)
    ctx.stroke()
  }

  // 绘制垂直网格线
  for (let i = 50; i < CANVAS_SIZE; i += 50) {
    ctx.beginPath()
    ctx.moveTo(i, 0)
    ctx.lineTo(i, CANVAS_SIZE)
    ctx.stroke()
  }
}

/**
 * 绘制雷达检测区域边界
 * 整个画布范围的边界框，表示雷达的最大检测范围
 */
const drawRadarBoundary = () => {
  if (!ctx) return

  ctx.strokeStyle = '#95a5a6'
  ctx.lineWidth = 1
  ctx.strokeRect(0, 0, CANVAS_SIZE, CANVAS_SIZE)
}

/**
 * 绘制检测区域边框
 * 实际的检测子区域，使用蓝色边框和半透明填充
 */
const drawAreaBorder = () => {
  if (!ctx) return

  const [xStart, xEnd, yStart, yEnd] = convertedCoordinates.value

  const clampedXStart = Math.max(xStart, -RADAR_RANGE / 2)
  const clampedXEnd = Math.min(xEnd, RADAR_RANGE / 2)
  const clampedYStart = Math.max(yStart, -RADAR_RANGE / 2)
  const clampedYEnd = Math.min(yEnd, RADAR_RANGE / 2)

  const radarRect: RadarRect = {
    x_cm_start: clampedXStart,
    x_cm_stop: clampedXEnd,
    y_cm_start: clampedYStart,
    y_cm_stop: clampedYEnd,
  }

  const canvasRect = convert_region_r2c(radarRect, radarPosition)

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

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

/**
 * 绘制坐标轴
 * 虚线样式的X轴和Y轴，标识坐标系中心
 */
const drawCoordinateAxes = () => {
  if (!ctx) return

  const center = CANVAS_SIZE / 2

  ctx.strokeStyle = '#2c3e50'
  ctx.lineWidth = 1
  ctx.setLineDash([5, 5]) // 虚线样式

  // 绘制X轴（水平线）
  ctx.beginPath()
  ctx.moveTo(0, center)
  ctx.lineTo(CANVAS_SIZE, center)
  ctx.stroke()

  // 绘制Y轴（垂直线）
  ctx.beginPath()
  ctx.moveTo(center, 0)
  ctx.lineTo(center, CANVAS_SIZE)
  ctx.stroke()

  ctx.setLineDash([]) // 恢复实线样式
}

watch(
  () => [props.coordinates, props.direction, props.mode],
  () => {
    drawDetectionArea()
  },
  { deep: true }
)

// 组件挂载时初始化Canvas
onMounted(() => {
  initCanvas()
})

/**
 * 暴露给父组件的方法和属性
 * 提供坐标转换功能和雷达位置信息
 */
defineExpose({
  geoToPixel,
  pixelToGeo,
  convertAreaByDirection,
  convert_region_r2c: (rect: RadarRect) => convert_region_r2c(rect, radarPosition),
  convert_region_c2r: (rect: CanvasRect) => convert_region_c2r(rect, radarPosition),
  convert_furniture_r2c: (furniture: RadarFurniture) =>
    convert_furniture_r2c(furniture, radarPosition),
  convert_furniture_c2r: (furniture: CanvasRect) => convert_furniture_c2r(furniture, radarPosition),
  radarPosition,
  calculateBoundingBox,
})
</script>

<style scoped lang="less">
.detection-area-view {
  position: relative;
  display: inline-block;
  width: 500px;
  height: 500px;

  canvas {
    border: 1px 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;

    .furniture-container {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;

      &.clip-overflow {
        overflow: hidden;
        pointer-events: none;
      }

      .furniture-item {
        position: absolute;

        .furniture-rotated-container {
          position: absolute;

          .furniture-wrapper {
            width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;

            :deep(*) {
              pointer-events: none;
            }
          }
        }
      }
    }

    .target-point {
      position: absolute;
      pointer-events: none;
    }

    .subregion-container {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      pointer-events: auto;
    }
  }
}
</style>
