<!-- eslint-disable ts/no-use-before-define -->
<script setup lang="ts">
import type { DomMarkingData, MarkingTool } from '../../composables/renderer/useMarkingDom'
import { useMessage } from 'wot-design-uni'
import { parseOSSImageSize } from '@/utils/image'
import { useSimpleDomLayer } from '../../composables/renderer/useMarkingDom'

interface Props {
  imageUrl: string
  scale?: number
  markingData?: DomMarkingData
  currentTool: MarkingTool
  readOnly?: boolean
  onQuickScore?: (value: number) => boolean
  onTextInput?: (pos: { x: number, y: number }) => Promise<string | null>
  onScoreDelete?: (value: number) => void
}

const props = withDefaults(defineProps<Props>(), {
  scale: 1,
  readOnly: false,
})

const emit = defineEmits<{
  'layer-ready': [layerManager: ReturnType<typeof useSimpleDomLayer>]
}>()

// 图片的自然尺寸
const naturalWidth = ref(0)
const naturalHeight = ref(0)

// 计算显示尺寸（应用缩放）
const displayWidth = computed(() => naturalWidth.value * props.scale)
const displayHeight = computed(() => naturalHeight.value * props.scale)
function encodeSvg(svg: string) {
  return svg.replace('<svg', (~svg.indexOf('xmlns') ? '<svg' : '<svg xmlns="http://www.w3.org/2000/svg"'))
    .replace(/"/g, '\'')
    .replace(/%/g, '%25')
    .replace(/#/g, '%23')
    .replace(/\{/g, '%7B')
    .replace(/\}/g, '%7D')
    .replace(/</g, '%3C')
    .replace(/>/g, '%3E')
}

/**
 * 将 SVG 转换为 base64 data URL
 */
function svgToDataURL(svg: string): string {
  // 将被设置到 dataset 中的属性还原出来
  svg = svg.replace(/data-(.*?=(['"]).*?\2)/g, '$1')

  // 将被设置到 data-xlink-href 的属性还原出来
  svg = svg.replace(/xlink-href=/g, 'xlink:href=')

  // 将 dataset 中被变成 kebab-case 写法的 viewBox 还原出来
  svg = svg.replace(/view-box=/g, 'viewBox=')

  // 清除 SVG 中不应该显示的 title、desc、defs 元素
  svg = svg.replace(/<(title|desc|defs)>[\s\S]*?<\/\1>/g, '')

  // 为非标准 XML 的 SVG 添加 xmlns，防止视图层解析出错
  if (!/xmlns=/.test(svg))
    svg = svg.replace(/<svg/, '<svg xmlns=\'http://www.w3.org/2000/svg\'')

  // 对 SVG 中出现的浮点数统一取最多两位小数，缓解数据量过大问题
  svg = svg.replace(/\d+\.\d+/g, match => Number.parseFloat(Number.parseFloat(match).toFixed(2)) as any)

  // 清除注释，缓解数据量过大的问题
  svg = svg.replace(/<!--[\s\S]*?-->/g, '')

  // 模拟 HTML 的 white-space 行为，将多个空格或换行符换成一个空格，减少数据量
  svg = svg.replace(/\s+/g, ' ')

  // 对特殊符号进行转义，这里参考了 https://github.com/bhovhannes/svg-url-loader/blob/master/src/loader.js
  svg = svg.replace(/[{}|\\^~[\]`"<>#%]/g, (match) => {
    return `%${match[0].charCodeAt(0).toString(16).toUpperCase()}`
  })

  // 单引号替换为 \'，由于 kbone 的 bug，节点属性中的双引号在生成 outerHTML 时不会被转义导致出错
  // 因此 background-image: url( 后面只能跟单引号，所以生成的 URI 内部也就只能用斜杠转义单引号了
  svg = svg.replace(/'/g, '\\\'')

  // 最后添加 mime 头部，变成 Webview 可以识别的 Data URI
  return `data:image/svg+xml,${svg.trim()}`
}

/**
 * 生成线条的 SVG data URL
 */
function generateLineSvg(points: string, stroke: string, strokeWidth: number, width: number, height: number): string {
  const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">
    <polyline points="${points}" stroke="${stroke}" stroke-width="${strokeWidth}" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
  </svg>`
  return svgToDataURL(svg)
}

/**
 * 生成特殊标记的 SVG data URL
 */
function generateMarkSvg(type: 'correct' | 'wrong' | 'half'): string {
  let svg = '<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64">'

  if (type === 'correct') {
    // 对勾：短的向下斜线 + 长的向上斜线
    svg += '<line x1="16" y1="32" x2="28" y2="44" stroke="#ff4d4f" stroke-width="3" stroke-linecap="round" fill="none"/>'
    svg += '<line x1="28" y1="44" x2="48" y2="20" stroke="#ff4d4f" stroke-width="3" stroke-linecap="round" fill="none"/>'
  }
  else if (type === 'wrong') {
    // 叉号：两条对角线
    svg += '<line x1="20" y1="20" x2="44" y2="44" stroke="#ff4d4f" stroke-width="3" stroke-linecap="round"/>'
    svg += '<line x1="44" y1="20" x2="20" y2="44" stroke="#ff4d4f" stroke-width="3" stroke-linecap="round"/>'
  }
  else if (type === 'half') {
    // 半对：对勾 + 右侧斜线
    svg += '<line x1="16" y1="32" x2="28" y2="44" stroke="#ff4d4f" stroke-width="3" stroke-linecap="round" fill="none"/>'
    svg += '<line x1="28" y1="44" x2="48" y2="20" stroke="#ff4d4f" stroke-width="3" stroke-linecap="round" fill="none"/>'
    svg += '<line x1="30" y1="25" x2="46" y2="40" stroke="#ff4d4f" stroke-width="3" stroke-linecap="round" fill="none"/>'
  }

  svg += '</svg>'
  return svgToDataURL(svg)
}

// Layer管理器
const message = useMessage()
const layerManager = useSimpleDomLayer({
  scale: computed(() => props.scale),
  currentTool: computed(() => props.currentTool),
  initialData: props.markingData,
  onQuickScore: (value: number) => props.onQuickScore?.(value),
  onTextInput: props.onTextInput,
  readOnly: props.readOnly,
  message,
})

/**
 * 加载图片获取尺寸
 */
async function loadImage(): Promise<void> {
  // 优先从OSS URL参数中解析尺寸
  const ossInfo = parseOSSImageSize(props.imageUrl)
  console.log('ossInfo', ossInfo)
  if (ossInfo) {
    naturalWidth.value = ossInfo.width
    naturalHeight.value = ossInfo.height
    return
  }

  // 使用 uni.getImageInfo 获取图片尺寸
  return new Promise((resolve, reject) => {
    uni.getImageInfo({
      src: props.imageUrl,
      success: (res) => {
        naturalWidth.value = res.width
        naturalHeight.value = res.height
        resolve()
      },
      fail: (err) => {
        console.error('Failed to load image:', err)
        reject(new Error(`Failed to load image: ${props.imageUrl}`))
      },
    })
  })
}

// 缓存rect，避免频繁查询
let cachedRect: DOMRect | null = null
const instance = getCurrentInstance()

/**
 * 获取canvas元素的位置信息（使用uni-app API）
 */
async function getCanvasRect(): Promise<DOMRect> {
  return new Promise((resolve, reject) => {
    const query = uni.createSelectorQuery().in(instance.proxy)
    query.select('.canvas-container').boundingClientRect((data) => {
      if (data && !Array.isArray(data)) {
        resolve({
          left: data.left,
          top: data.top,
          right: data.right,
          bottom: data.bottom,
          width: data.width,
          height: data.height,
          x: data.left,
          y: data.top,
          toJSON: () => ({}),
        } as DOMRect)
      }
      else {
        reject(new Error('Failed to get canvas rect'))
      }
    }).exec()
  })
}

// 事件处理
async function handleTouchStart(e: TouchEvent) {
  if (!layerManager)
    return

  // 双指手势不处理，让全局缩放接管
  if (e.touches.length >= 2) {
    return
  }

  try {
    const rect = cachedRect || await getCanvasRect()
    if (!cachedRect) {
      cachedRect = rect
    }
    layerManager.handleMouseDown(e, rect)
  }
  catch (error) {
    console.error('Failed to get canvas rect:', error)
  }
}

async function handleTouchMove(e: TouchEvent) {
  if (!layerManager)
    return

  // 双指手势不处理，让全局缩放接管
  if (e.touches.length >= 2) {
    return
  }

  try {
    const rect = cachedRect || await getCanvasRect()
    if (!cachedRect) {
      cachedRect = rect
    }
    layerManager.handleMouseMove(e, rect)
  }
  catch (error) {
    console.error('Failed to get canvas rect:', error)
  }
}

function handleTouchEnd(e: TouchEvent) {
  if (!layerManager)
    return

  // 如果还有触点（从双指变单指），不结束绘制
  if (e.touches.length > 0) {
    return
  }

  layerManager.handleMouseUp()
}

/**
 * 处理删除注释
 */
function handleDeleteAnnotation(annotationId: string, scoreValue?: number) {
  if (!layerManager)
    return

  // 删除注释
  layerManager.deleteAnnotation(annotationId)

  // 如果有分数值，通知父组件减去对应分数
  if (scoreValue !== undefined && props.onScoreDelete) {
    props.onScoreDelete(-scoreValue)
  }
}

// 监听图片URL变化
watch(
  () => props.imageUrl,
  async () => {
    await loadImage()
    // 图片变化时清除缓存的rect
    cachedRect = null
  },
)

// 暴露方法给父组件
defineExpose({
  getLayerManager: () => layerManager,
})

// 组件挂载时初始化
onMounted(async () => {
  await loadImage()
  await nextTick()

  // 初始化时缓存rect
  try {
    cachedRect = await getCanvasRect()
  }
  catch (error) {
    console.warn('Failed to cache canvas rect on init:', error)
  }

  emit('layer-ready', layerManager)
})
</script>

<template>
  <view
    v-if="naturalWidth && naturalHeight"
    class="canvas-container relative"
    :style="{
      width: `${displayWidth}px`,
      height: `${displayHeight}px`,
      backgroundColor: '#ffffff',
    }"
    @touchstart="handleTouchStart"
    @touchmove="handleTouchMove"
    @touchend="handleTouchEnd"
  >
    <!-- 背景图片 -->
    <image
      :src="imageUrl"
      mode="aspectFit"
      :style="{
        width: `${displayWidth}px`,
        height: `${displayHeight}px`,
        pointerEvents: 'none',
      }"
    />

    <!-- 标记层容器 -->
    <view
      class="absolute left-0 top-0"
      :style="{
        width: `${naturalWidth}px`,
        height: `${naturalHeight}px`,
        transform: `scale(${scale})`,
        transformOrigin: 'top left',
        pointerEvents: 'none',
      }"
    >
      <!-- 当前绘制中的形状 -->
      <template v-if="layerManager.currentDrawingShape.value">
        <!-- 矩形 -->
        <view
          v-if="layerManager.currentDrawingShape.value.type === 'rect'"
          class="absolute"
          :style="{
            left: `${layerManager.currentDrawingShape.value.x}px`,
            top: `${layerManager.currentDrawingShape.value.y}px`,
            width: `${layerManager.currentDrawingShape.value.width}px`,
            height: `${layerManager.currentDrawingShape.value.height}px`,
            border: `${layerManager.currentDrawingShape.value.strokeWidth}px solid ${layerManager.currentDrawingShape.value.stroke}`,
          }"
        />

        <!-- 线条 -->
        <view
          v-else-if="layerManager.currentDrawingShape.value.type === 'line'"
          class="absolute left-0 top-0"
          :style="{
            width: `${naturalWidth}px`,
            height: `${naturalHeight}px`,
            backgroundImage: `url('${generateLineSvg(
              layerManager.currentDrawingShape.value.points?.join(' ') || '',
              layerManager.currentDrawingShape.value.stroke,
              layerManager.currentDrawingShape.value.strokeWidth,
              naturalWidth,
              naturalHeight,
            )}')`,
            backgroundSize: 'contain',
            backgroundRepeat: 'no-repeat',
            pointerEvents: 'none',
          }"
        />
      </template>

      <!-- 已保存的形状 -->
      <!-- 矩形 -->
      <view
        v-for="shape in layerManager.markingData.value.shapes.filter(s => s.type === 'rect')"
        :key="shape.id"
        class="absolute"
        :style="{
          left: `${shape.x}px`,
          top: `${shape.y}px`,
          width: `${shape.width}px`,
          height: `${shape.height}px`,
          border: `${shape.strokeWidth}px solid ${shape.stroke}`,
        }"
      />

      <!-- 线条 -->
      <view
        v-for="shape in layerManager.markingData.value.shapes.filter(s => s.type === 'line')"
        :key="shape.id"
        class="absolute left-0 top-0"
        :style="{
          width: `${naturalWidth}px`,
          height: `${naturalHeight}px`,
          backgroundImage: `url('${generateLineSvg(
            shape.points?.join(' ') || '',
            shape.stroke,
            shape.strokeWidth,
            naturalWidth,
            naturalHeight,
          )}')`,
          backgroundSize: 'contain',
          backgroundRepeat: 'no-repeat',
          pointerEvents: 'none',
        }"
      />

      <!-- 特殊标记 -->
      <view
        v-for="mark in layerManager.markingData.value.specialMarks"
        :key="mark.id"
        class="absolute"
        :style="{
          left: `${mark.x - 32}px`,
          top: `${mark.y - 32}px`,
          width: '64px',
          height: '64px',
          backgroundImage: `url('${generateMarkSvg(mark.type)}')`,
          backgroundSize: 'contain',
          backgroundRepeat: 'no-repeat',
          pointerEvents: 'none',
        }"
      />

      <!-- 文本注释 -->
      <view
        v-for="annotation in layerManager.markingData.value.annotations"
        :key="annotation.id"
        class="absolute font-bold flex items-center"
        :style="{
          left: `${annotation.x}px`,
          top: `${annotation.y}px`,
          fontSize: `${annotation.fontSize}px`,
          color: annotation.color,
          whiteSpace: 'nowrap',
          gap: '4px',
          pointerEvents: annotation.scoreValue !== undefined && !readOnly ? 'auto' : 'none',
        }"
      >
        <text>{{ annotation.text }}</text>
        <view
          v-if="annotation.scoreValue !== undefined && !readOnly"
          class="flex items-center justify-center bg-red-500 text-white rounded-full"
          :style="{
            width: `${annotation.fontSize * 0.8}px`,
            height: `${annotation.fontSize * 0.8}px`,
            fontSize: `${annotation.fontSize * 0.4}px`,
            cursor: 'pointer',
            pointerEvents: 'auto',
          }"
          @touchstart.stop="handleDeleteAnnotation(annotation.id, annotation.scoreValue)"
        >
          ×
        </view>
      </view>
    </view>
  </view>
</template>
