<script lang="ts" setup>
import type { Region, TemplateInfo } from '../types'
import { Icon } from '@iconify/vue'
import { NButton, NScrollbar, NSpin } from 'naive-ui'
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import VueDraggableResizable from 'vue3-draggable-resizable'
import 'vue3-draggable-resizable/dist/Vue3DraggableResizable.css'

const props = defineProps<{
  templateInfo: TemplateInfo
  regions: Region[]
  selectedRegionIds: Set<string>
  imgSrc: string
  loading: boolean
  showGrid?: boolean
  showRuler?: boolean
  showCoordinates?: boolean
}>()

const emit = defineEmits<{
  (e: 'update:templateInfo', info: TemplateInfo): void
  (e: 'update:regions', regions: Region[]): void
  (e: 'update:selectedRegionIds', ids: Set<string>): void
}>()

// 画布状态
const scale = ref(0.4) // CSS 缩放级别

// 对齐参考线
const guides = ref({
  x: null as number | null,
  y: null as number | null,
})

function resetZoom() {
  scale.value = 0.4
}

// 监听图片变化，自动重置缩放
watch(() => props.imgSrc, () => {
  if (props.imgSrc) {
    nextTick(() => {
      resetZoom()
    })
  }
})

// 拖拽初始状态记录
const dragStartPositions = ref<Map<string, { x: number, y: number }>>(new Map())
const mouseDownPos = ref<{ x: number, y: number } | null>(null)

// --- 鼠标坐标显示 ---
const mouseCoord = ref({ x: 0, y: 0 })
const showMouseCoord = ref(false)

function onCanvasMouseMove(e: MouseEvent) {
  if (!props.showCoordinates) {
    showMouseCoord.value = false
    return
  }

  // 获取画布元素
  const canvasEl = e.currentTarget as HTMLElement
  if (!canvasEl)
    return

  const rect = canvasEl.getBoundingClientRect()

  // 计算相对于画布左上角的像素坐标 (考虑缩放 scale)
  // 注意：e.clientX/Y 是视口坐标，rect.left/top 也是视口坐标
  // 鼠标在 canvas 元素内的像素位置
  const x = (e.clientX - rect.left) / scale.value
  const y = (e.clientY - rect.top) / scale.value

  // 转换为毫米 (1mm = 10px)
  mouseCoord.value = {
    x: Math.round(x / 10),
    y: Math.round(y / 10),
  }
  showMouseCoord.value = true
}

function onCanvasMouseLeave() {
  showMouseCoord.value = false
}

// --- 网格系统 ---
// A4 纸张宽度 210mm
const A4_WIDTH_MM = 210

// 计算 10mm 在当前画布宽度下的像素值
const gridSizePx = computed(() => {
  if (!props.templateInfo.width)
    return 0
  const pixelsPerMm = props.templateInfo.width / A4_WIDTH_MM
  return pixelsPerMm * 10 // 10mm
})

// --- 标尺生成逻辑 ---
const rulerPathH = computed(() => {
  if (!gridSizePx.value || !props.templateInfo.width)
    return ''

  let d = ''
  // 10mm 一格
  const step = gridSizePx.value
  const count = Math.ceil(props.templateInfo.width / step)

  for (let i = 0; i <= count; i++) {
    const x = i * step
    // 大刻度 (10mm)
    d += `M${x} 0 V20 `
    // 中间加 1 个 5mm 刻度
    const half = x + step / 2
    if (half < props.templateInfo.width) {
      d += `M${half} 12 V20 `
    }
  }
  return d
})

const rulerPathV = computed(() => {
  if (!gridSizePx.value || !props.templateInfo.height)
    return ''

  let d = ''
  const step = gridSizePx.value
  const count = Math.ceil(props.templateInfo.height / step)

  for (let i = 0; i <= count; i++) {
    const y = i * step
    d += `M0 ${y} H20 `
    const half = y + step / 2
    if (half < props.templateInfo.height) {
      d += `M12 ${half} H20 `
    }
  }
  return d
})

// --- 拖拽与调整大小逻辑 ---

/**
 * 处理区域点击/选择
 * 支持多选：按住 Shift/Ctrl/Meta 键
 */
function onRegionMouseDown(region: Region, e: MouseEvent) {
  // e.stopPropagation() // 移除阻止冒泡，以便 vue-draggable-resizable 能接收到事件并启动拖拽
  mouseDownPos.value = { x: e.clientX, y: e.clientY }

  const isModifierDown = e.shiftKey || e.ctrlKey || e.metaKey
  const isSelected = props.selectedRegionIds.has(region.id)

  const newIds = new Set(props.selectedRegionIds)

  if (isModifierDown) {
    // 多选模式：切换选中状态
    if (isSelected) {
      newIds.delete(region.id)
    }
    else {
      newIds.add(region.id)
    }
    emit('update:selectedRegionIds', newIds)
  }
  else {
    // 单选模式
    // 如果点击的是未选中的区域，则清除其他选中，只选中当前
    // 如果点击的是已选中的区域（可能是拖拽群组的一部分），则不清除，保留当前选中集合
    if (!isSelected) {
      emit('update:selectedRegionIds', new Set([region.id]))
    }
  }
}

/**
 * 处理区域鼠标松开
 * 用于在未拖拽的情况下，从多选切换为单选
 */
function onRegionMouseUp(region: Region, e: MouseEvent) {
  if (!mouseDownPos.value)
    return

  const dx = Math.abs(e.clientX - mouseDownPos.value.x)
  const dy = Math.abs(e.clientY - mouseDownPos.value.y)
  const isClick = dx < 3 && dy < 3
  const isModifierDown = e.shiftKey || e.ctrlKey || e.metaKey

  // 如果是单纯点击，且没有按修饰键，且已经选中（在 onRegionMouseDown 中处理了未选中的情况）
  // 那么将多选变为单选
  if (isClick && !isModifierDown && props.selectedRegionIds.has(region.id)) {
    // 如果当前选中的数量大于 1，则切换为单选当前这个
    if (props.selectedRegionIds.size > 1) {
      emit('update:selectedRegionIds', new Set([region.id]))
    }
  }

  mouseDownPos.value = null
}

/**
 * 点击画布空白处取消选中
 */
function onCanvasMouseDown(e: MouseEvent) {
  // 检查点击目标是否是区域相关元素
  const target = e.target as HTMLElement
  // 如果点击的是区域（.region-box, .region-content, .vdr-container 等），则忽略
  if (target.closest('.region-box') || target.closest('.region-content') || target.closest('.vdr-container') || target.closest('.vdr-handle')) {
    return
  }

  // 只有点击真正的空白处才取消选中
  emit('update:selectedRegionIds', new Set())
}

// 移除 onActivated 的选中逻辑，完全由 onRegionMouseDown 接管
function onActivated(_id: string) {
  // 空实现，避免覆盖多选逻辑
}

/**
 * 拖拽开始
 * 记录所有选中区域的初始位置，用于计算相对位移
 */
function onDragStart(region: Region, _payload: any) {
  // 确保当前拖拽的区域在选中列表中（防御性编程）
  if (!props.selectedRegionIds.has(region.id)) {
    const newIds = new Set(props.selectedRegionIds)
    newIds.add(region.id)
    emit('update:selectedRegionIds', newIds)
  }

  // 记录所有选中区域的初始位置
  dragStartPositions.value.clear()
  props.regions.forEach((r) => {
    if (props.selectedRegionIds.has(r.id)) {
      dragStartPositions.value.set(r.id, { x: r.x, y: r.y })
    }
  })
}

function onDragging(region: Region, payload: any) {
  // Payload 是 { x, y } (当前拖拽元素的实时坐标)
  const { x, y } = payload

  // 1. 计算对齐参考线 (仅针对当前拖拽的主元素)
  const w = region.w
  const h = region.h
  const centerX = props.templateInfo.width / 2
  const centerY = props.templateInfo.height / 2
  const objCenterX = x + w / 2
  const objCenterY = y + h / 2
  const threshold = 10

  let showGuideX = null
  let showGuideY = null

  if (Math.abs(objCenterX - centerX) < threshold) {
    showGuideX = centerX
  }
  if (Math.abs(objCenterY - centerY) < threshold) {
    showGuideY = centerY
  }
  guides.value = { x: showGuideX, y: showGuideY }

  // 2. 批量移动逻辑
  const startPos = dragStartPositions.value.get(region.id)
  if (!startPos)
    return

  // 计算当前拖拽元素的位移增量
  const deltaX = x - startPos.x
  const deltaY = y - startPos.y

  // 应用位移到所有选中区域
  const newRegions = props.regions.map((r) => {
    if (props.selectedRegionIds.has(r.id)) {
      const initial = dragStartPositions.value.get(r.id)
      if (initial) {
        return {
          ...r,
          x: initial.x + deltaX,
          y: initial.y + deltaY,
        }
      }
    }
    return r
  })

  // 实时更新 props.regions 以实现视觉同步移动
  emit('update:regions', newRegions)
}

function onDragEnd(_region: Region, _payload: any) {
  guides.value = { x: null, y: null }

  // 清理初始位置记录
  dragStartPositions.value.clear()

  // 确保最后一次状态更新 (通常 onDragging 已经处理了，但为了保险)
  // 注意：payload 仅包含当前拖拽元素的最终位置
  // 这里的逻辑其实已经在 onDragging 中通过 delta 完成了所有元素的更新
  // 所以这里主要做清理工作，或者再次确认最终位置（可选）
}

function onResizeEnd(region: Region, payload: any) {
  const { x, y, w, h } = payload
  const newRegions = props.regions.map(r =>
    r.id === region.id
      ? {
          ...r,
          x: Math.round(x),
          y: Math.round(y),
          w: Math.round(w),
          h: Math.round(h),
        }
      : r,
  )
  emit('update:regions', newRegions)
}

/**
 * 处理旋转
 */
function onRotateStart(region: Region, e: MouseEvent) {
  e.preventDefault()
  e.stopPropagation()

  const el = (e.target as HTMLElement).closest('.region-content')
  if (!el)
    return

  const rect = el.getBoundingClientRect()
  const centerX = rect.left + rect.width / 2
  const centerY = rect.top + rect.height / 2

  const startAngle = Math.atan2(e.clientY - centerY, e.clientX - centerX)
  const initialRotation = region.rotation || 0

  const onMove = (moveEvent: MouseEvent) => {
    const currentAngle = Math.atan2(moveEvent.clientY - centerY, moveEvent.clientX - centerX)
    const delta = currentAngle - startAngle
    const deg = (delta * 180) / Math.PI

    // 更新本地旋转状态
    const newRotation = (initialRotation + deg) % 360

    // 我们需要更新区域属性以实时查看更改
    // 因为我们不能修改 props，所以发出 update 事件
    // 但在每次移动时发出事件可能会很重？
    // 对于旋转来说通常是可以的。
    const newRegions = props.regions.map(r =>
      r.id === region.id ? { ...r, rotation: newRotation } : r,
    )
    emit('update:regions', newRegions)
  }

  const onUp = () => {
    window.removeEventListener('mousemove', onMove)
    window.removeEventListener('mouseup', onUp)
  }

  window.addEventListener('mousemove', onMove)
  window.addEventListener('mouseup', onUp)
}

/**
 * 处理对象删除 (通过 UI 或按键)
 */
function handleDelete() {
  if (props.selectedRegionIds.size > 0) {
    const newRegions = props.regions.filter(r => !props.selectedRegionIds.has(r.id))
    emit('update:regions', newRegions)
    emit('update:selectedRegionIds', new Set())
  }
}

function onKeyDown(e: KeyboardEvent) {
  if (e.key === 'Delete' || e.key === 'Backspace') {
    handleDelete()
  }
}

onMounted(() => {
  window.addEventListener('keydown', onKeyDown)
})

onUnmounted(() => {
  window.removeEventListener('keydown', onKeyDown)
})
</script>

<template>
  <div class="checker-bg relative flex flex-1 overflow-hidden bg-[#eef0f4]">
    <NScrollbar>
      <div class="min-h-full min-w-full flex items-center justify-center py-[10px]">
        <!-- 缩放框容器 -->
        <div
          class="relative transition-all duration-200 ease-out" :style="{
            width: `${templateInfo.width * scale}px`,
            height: `${templateInfo.height * scale}px`,
          }"
        >
          <!-- 纸张/画布 -->
          <div
            class="relative origin-top-left bg-white shadow-lg" :style="{
              transform: `scale(${scale})`,
              width: `${templateInfo.width}px`,
              height: `${templateInfo.height}px`,
            }"
          >
            <!-- 标尺 (外部) -->
            <template v-if="showRuler && gridSizePx > 0">
              <!-- 横向标尺 -->
              <div class="absolute left-0 h-[20px] w-full border-b border-gray-300 bg-white/80 backdrop-blur-sm -top-[20px]">
                <svg width="100%" height="20" class="overflow-visible">
                  <path :d="rulerPathH" stroke="#666" stroke-width="1" fill="none" />
                  <!-- 刻度值 -->
                  <text
                    v-for="i in Math.ceil(templateInfo.width / gridSizePx)"
                    :key="`h-${i}`"
                    :x="i * gridSizePx + 2"
                    y="10"
                    font-size="22"
                    fill="#666"
                  >{{ i * 10 }}</text>
                  <text x="2" y="10" font-size="10" fill="#666">0</text>
                </svg>
              </div>
              <!-- 纵向标尺 -->
              <div class="absolute top-0 h-full w-[20px] border-r border-gray-300 bg-white/80 backdrop-blur-sm -left-[20px]">
                <svg width="20" height="100%" class="overflow-visible">
                  <path :d="rulerPathV" stroke="#666" stroke-width="1" fill="none" />
                  <!-- 刻度值 -->
                  <text
                    v-for="i in Math.ceil(templateInfo.height / gridSizePx)"
                    :key="`v-${i}`"
                    x="2"
                    :y="i * gridSizePx + 10"
                    font-size="22"
                    fill="#666"
                    transform-origin="lef"
                    style="writing-mode: vertical-lr;"
                  >{{ i * 10 }}</text>
                  <text x="2" y="10" font-size="10" fill="#666" style="writing-mode: vertical-lr;">0</text>
                </svg>
              </div>
            </template>

            <!-- 实际画布交互层 -->
            <div
              class="relative h-full w-full"
              @mousedown="onCanvasMouseDown"
              @mousemove="onCanvasMouseMove"
              @mouseleave="onCanvasMouseLeave"
            >
              <!-- 鼠标坐标提示 (跟随鼠标或固定角落) -->
              <div
                v-if="showMouseCoord"
                class="pointer-events-none absolute left-0 top-0 z-50 rounded bg-black/75 px-2 py-1 text-80px text-white backdrop-blur-sm transition-opacity"
                :style="{
                  transform: `translate(${mouseCoord.x * 10 + 15}px, ${mouseCoord.y * 10 + 15}px)`,
                }"
              >
                X: {{ mouseCoord.x }}mm, Y: {{ mouseCoord.y }}mm
              </div>

              <!-- 背景图片 -->
              <img
                v-if="imgSrc" :src="imgSrc"
                class="pointer-events-none absolute inset-0 h-full w-full select-none object-contain"
              >

              <!-- 网格辅助层 (10mm 格子) -->
              <svg
                v-if="showGrid && gridSizePx > 0"
                class="pointer-events-none absolute inset-0 z-1 h-full w-full"
                xmlns="http://www.w3.org/2000/svg"
              >
                <defs>
                  <pattern
                    id="gridPattern"
                    :width="gridSizePx"
                    :height="gridSizePx"
                    patternUnits="userSpaceOnUse"
                  >
                    <path
                      :d="`M ${gridSizePx} 0 L 0 0 0 ${gridSizePx}`"
                      fill="none"
                      stroke="rgba(255, 0, 0, 0.3)"
                      stroke-width="1"
                    />
                  </pattern>
                </defs>
                <rect width="100%" height="100%" fill="url(#gridPattern)" />
              </svg>

              <!-- 对齐参考线 -->
              <div
                v-if="guides.x !== null"
                class="pointer-events-none absolute bottom-0 top-0 z-50 border-l border-red-500 border-dashed"
                :style="{ left: `${guides.x}px` }"
              />
              <div
                v-if="guides.y !== null"
                class="pointer-events-none absolute left-0 right-0 z-50 border-t border-red-500 border-dashed"
                :style="{ top: `${guides.y}px` }"
              />

              <!-- 可拖拽区域 -->
              <!-- 注意: VueDraggableResizable 需要 w/h/x/y。
                  :parent="true" 限制在容器内。
             -->
              <VueDraggableResizable
                v-for="region in regions" :key="region.id" :x="region.x" :y="region.y"
                :w="region.w" :h="region.h" :parent="true" :active="selectedRegionIds.has(region.id)"
                :draggable="true" :resizable="true" class="region-box" class-active="active-region"
                @activated="onActivated(region.id)" @drag-start="onDragStart(region, $event)"
                @dragging="onDragging(region, $event)" @drag-end="onDragEnd(region, $event)"
                @resize-end="onResizeEnd(region, $event)"
              >
                <div
                  class="region-content group relative h-full w-full flex items-center justify-center transition-transform"
                  :style="{ transform: `rotate(${region.rotation || 0}deg)` }"
                  @mousedown="onRegionMouseDown(region, $event)"
                  @mouseup="onRegionMouseUp(region, $event)"
                >
                  <!-- 视觉边框 (旋转) -->
                  <div
                    class="pointer-events-none absolute inset-0 border-2 transition-colors"
                    :class="selectedRegionIds.has(region.id) ? 'border-orange-500 bg-orange-500/10' : 'border-transparent group-hover:border-orange-300'"
                  />

                  <!-- 标签 -->
                  <span class="relative z-10 select-none text-60px text-orange-600 font-bold">{{ region.label }}</span>

                  <!-- 旋转手柄 -->
                  <div
                    v-if="selectedRegionIds.has(region.id)"
                    class="absolute left-1/2 z-50 h-5 w-5 flex cursor-pointer items-center justify-center border border-gray-400 rounded-full bg-white shadow-sm -top-6 -translate-x-1/2 hover:bg-blue-50"
                    title="旋转" @mousedown.stop="onRotateStart(region, $event)"
                  >
                    <Icon icon="carbon:rotate-clockwise" class="text-xs text-gray-600" />
                  </div>
                </div>
              </VueDraggableResizable>

              <!-- 无图片时的上传占位符 (如果需要可以在这里添加插槽，或者由父组件控制) -->
              <!-- 这里我们移除内部上传，改为依赖父组件传入图片 -->
              <div
                v-if="!imgSrc"
                class="pointer-events-none absolute inset-0 z-10 flex flex-col cursor-pointer items-center justify-center bg-white/50 backdrop-blur-sm"
              >
                <div class="flex flex-col items-center gap-4 p-8 text-gray-400">
                  <SvgIcon icon="carbon:image" class="h-50 w-50" />
                  <div class="text-5xl text-gray-500">
                    请在上方点击上传答题卡底稿
                  </div>
                </div>
              </div>

              <!-- 加载遮罩 -->
              <div
                v-if="loading"
                class="absolute inset-0 z-50 flex items-center justify-center bg-white/80 backdrop-blur-sm"
              >
                <NSpin size="large" description="正在解析渲染高清底图..." />
              </div>
            </div>
          </div>
        </div>
      </div>
    </NScrollbar>

    <!-- 缩放控制 -->
    <div
      class="absolute bottom-4 left-4 z-10 flex items-center gap-2 rounded-full bg-white px-4 py-1 shadow ring-1 ring-black/5"
    >
      <NButton size="small" quaternary circle title="适应屏幕" @click="resetZoom">
        <Icon icon="carbon:fit-to-screen" />
      </NButton>
      <div class="mx-1 h-3 w-px bg-gray-300" />
      <NButton size="small" quaternary circle @click="scale = Math.max(scale - 0.05, 0.1)">
        -
      </NButton>
      <span class="font-variant-numeric w-12 text-center text-xs tabular-nums">{{ Math.round(scale * 100) }}%</span>
      <NButton size="small" quaternary circle @click="scale = Math.min(scale + 0.05, 3)">
        +
      </NButton>
      <div class="mx-1 h-3 w-px bg-gray-300" />
      <NButton size="small" quaternary circle title="删除选中" type="error" @click="handleDelete">
        <Icon icon="carbon:trash-can" />
      </NButton>
    </div>
  </div>
</template>

<style scoped>
.checker-bg {
  background-image: radial-gradient(#cbd5e1 1px, transparent 1px);
  background-size: 20px 20px;
}

/* Custom styles for the draggable component */
:deep(.vdr-container) {
  border: 1px dashed #4caf50;
  background-color: rgba(76, 175, 80, 0.1);
}

:deep(.active-region) {
  border: 1px dashed rgba(76, 175, 80, 0.5);
  z-index: 10;
}

/* Hide default handles until active? No, usually they show when active */
:deep(.vdr-handle) {
  /* Customize handles if needed */
  background-color: #ffffff;
  border: 1px solid #4caf50;
  border-radius: 50%;
  width: 8px;
  height: 8px;
}
</style>
