<script setup lang="ts">
import type { DomMarkingData } from '../../composables/renderer/useMarkingDom'
import type { ExamStudentMarkingQuestionResponse } from '@/api'
import { parseOSSImageSize } from '@/utils/image'
import { markingSettings } from '../../composables/useMarkingSettings'
import QuestionRenderer from './QuestionRenderer.vue'

interface Props {
  imageSize: number
  questionData: ExamStudentMarkingQuestionResponse[]
  nextQuestionImages?: string[]
}

const props = defineProps<Props>()

const emit = defineEmits<{
  'marking-change': [questionIndex: number, imageIndex: number, data: DomMarkingData]
  'ready': [imageInfo: { width: number, height: number }]
  'scroll-edge': [atLeftEdge: boolean, atRightEdge: boolean]
  'touch-start': [event: TouchEvent]
  'touch-move': [event: TouchEvent]
  'touch-end': [event: TouchEvent]
}>()

const scale = defineModel<number>('scale', { default: 1.0 })

// 滚动边缘状态
const atLeftEdge = ref(true)
const atRightEdge = ref(true)

// 第一张图片的尺寸信息
const firstImageSize = ref({ width: 0, height: 0 })

// 滚动容器ID（用于 uni.createSelectorQuery）
const scrollContainerId = `scroll-container-${Math.random().toString(36).slice(2)}`

/**
 * 手势事件透传
 */
function handleTouchStart(e: TouchEvent) {
  emit('touch-start', e)
}

function handleTouchMove(e: TouchEvent) {
  emit('touch-move', e)
}

function handleTouchEnd(e: TouchEvent) {
  emit('touch-end', e)
}

/**
 * 检查滚动边缘状态（使用 uni.createSelectorQuery）
 */
function checkScrollEdge() {
  const query = uni.createSelectorQuery()
  query.select(`#${scrollContainerId}`).scrollOffset()
  query.select(`#${scrollContainerId}`).boundingClientRect()
  query.exec((res) => {
    if (!res || res.length < 2)
      return

    const scrollInfo = res[0]
    const rectInfo = res[1]

    if (!scrollInfo || !rectInfo)
      return

    const scrollLeft = scrollInfo.scrollLeft || 0
    const scrollWidth = scrollInfo.scrollWidth || 0
    const clientWidth = rectInfo.width || 0

    // 允许1px的误差
    atLeftEdge.value = scrollLeft <= 1
    atRightEdge.value = scrollLeft + clientWidth >= scrollWidth - 1

    emit('scroll-edge', atLeftEdge.value, atRightEdge.value)
  })
}

/**
 * 监听滚动事件
 */
function handleScroll() {
  checkScrollEdge()
}

// 转换为渲染数据
const questionDataList = computed(() => {
  if (!props.questionData?.length)
    return []

  return props.questionData.map((item, index) => ({
    id: `question_${item.tpl_question_id || index}_${item.scan_info_id}_${index}`,
    title: `${item.question_major || ''}${item.question_minor || ''}`,
    fullScore: item.full_score || 0,
    finalScore: item.final_score || 0,
    imageUrls: item.image_urls || [],
  }))
})

/**
 * 处理标记变化
 */
function handleMarkingChange(questionIndex: number, imageIndex: number, data: DomMarkingData) {
  emit('marking-change', questionIndex, imageIndex, data)
}

/**
 * 加载第一张图片尺寸
 */
async function loadFirstImageSize() {
  if (!props.questionData?.length || !props.questionData[0]?.image_urls?.length) {
    return
  }

  const firstImageUrl = props.questionData[0].image_urls[0]

  // 优先从OSS URL参数中解析尺寸
  const ossInfo = parseOSSImageSize(firstImageUrl)
  if (ossInfo) {
    firstImageSize.value = { width: ossInfo.width, height: ossInfo.height }
    emit('ready', firstImageSize.value)
    return
  }

  // 使用 uni.getImageInfo 获取图片尺寸
  return new Promise<void>((resolve, reject) => {
    uni.getImageInfo({
      src: firstImageUrl,
      success: (res) => {
        firstImageSize.value = { width: res.width, height: res.height }
        emit('ready', firstImageSize.value)
        resolve()
      },
      fail: (err) => {
        console.error('Failed to load first image:', err)
        reject(new Error(`Failed to load image: ${firstImageUrl}`))
      },
    })
  })
}

// 监听questionData变化，加载第一张图片尺寸
watch(
  () => props.questionData,
  async () => {
    await loadFirstImageSize()
    // 数据变化后重新检查滚动边缘
    nextTick(() => {
      checkScrollEdge()
    })
  },
  { immediate: true },
)

// 监听scale变化，重新检查滚动边缘
watch(
  () => scale.value,
  () => {
    nextTick(() => {
      checkScrollEdge()
    })
  },
)

// 暴露方法和数据给父组件
defineExpose({
  firstImageSize,
  atLeftEdge,
  atRightEdge,
})
</script>

<template>
  <scroll-view
    :id="scrollContainerId"
    class="h-full w-full"
    scroll-y="true"
    scroll-x="true"
    @scroll="handleScroll"
    @touchstart="handleTouchStart"
    @touchmove="handleTouchMove"
    @touchend="handleTouchEnd"
  >
    <!-- 题目列表 -->
    <view
      class="flex flex-col"
      :class="{
        'items-start': markingSettings.imagePosition === 'left',
        'items-center': markingSettings.imagePosition === 'center',
        'items-end': markingSettings.imagePosition === 'right',
      }"
      :style="{ gap: '24px', padding: '12px' }"
    >
      <QuestionRenderer
        v-for="(question, questionIndex) in questionDataList"
        :key="question.id"
        :question="question"
        :question-index="questionIndex"
        :scale="scale"
        :image-layout="markingSettings.imageLayout"
        :show-toolbar="markingSettings.showTraceToolbar"
        :initial-marking-data="
          questionData[questionIndex].remark
            ? JSON.parse(questionData[questionIndex].remark)
            : undefined
        "
        @marking-change="(imageIndex, data) => handleMarkingChange(questionIndex, imageIndex, data)"
      />
    </view>

    <!-- 预加载下一题图片 -->
    <view v-if="nextQuestionImages?.length" class="hidden">
      <image
        v-for="(url, index) in nextQuestionImages"
        :key="`preload_${index}`"
        :src="url"
        class="h-0 w-0"
      />
    </view>
  </scroll-view>
</template>
