<!-- 阅卷页面 -->
<route lang="jsonc">
{
  "style": {
    "navigationStyle": "custom"
  }
}
</route>

<script lang="ts" setup>
import type { MarkingDataProvider, MarkingHistoryProvider } from '@/composables/marking/MarkingContext'
import { useQueryClient } from '@tanstack/vue-query'
import { watchImmediate, whenever } from '@vueuse/core'
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import AnswerDialog from '@/components/marking/components/dialog/AnswerDialog.vue'
import AvgScoreDialog from '@/components/marking/components/dialog/AvgScoreDialog.vue'
import FullscreenImageDialog from '@/components/marking/components/dialog/FullscreenImageDialog.vue'
import ScoreSettingsDialog from '@/components/marking/components/dialog/ScoreSettingsDialog.vue'
import QuickScorePanel from '@/components/marking/components/QuickScorePanel.vue'
import MarkingImageViewerNew from '@/components/marking/components/renderer/MarkingImageViewerNew.vue'
import { provideMarkingData } from '@/components/marking/composables/useMarkingData'
import MarkingLayout from '@/components/marking/MarkingLayout.vue'
import { cachedImages, DefaultMarkingDataProvider, DefaultMarkingHistoryProvider, provideMarkingContext } from '@/composables/marking/MarkingContext'
import { ReviewMarkingDataProvider, ReviewMarkingHistoryProvider } from '@/composables/marking/ReviewMarkingContext'
import { provideMarkingHistory } from '@/composables/marking/useMarkingHistory'
import { provideMarkingNavigation } from '@/composables/marking/useMarkingNavigation'
import { useSafeArea } from '@/composables/useSafeArea'
import { svgToDataURL } from '@/utils/dom'

defineOptions({
  name: 'GradingPage',
})

const props = defineProps<{
  mode: string
}>()

// 获取屏幕边界到安全区域距离
const { safeAreaInsets } = useSafeArea()

// 获取路由参数
const examId = ref<number>()
const subjectId = ref<number>()
const questionId = ref<number>()
const taskId = ref<number>()
const evaluationType = ref<'single' | 'double'>('single')
const taskType = ref<'initial' | 'final' | 'arbitration'>('initial')

// 屏幕方向状态 - 默认横屏
const isLandscape = ref(true)

// 图片缩放比例
const imageScale = ref(1.0)

// MarkingImageViewerNew 组件引用
const imageViewerRef = ref<InstanceType<typeof MarkingImageViewerNew>>()

// 容器尺寸信息
const containerSize = ref({ width: 0, height: 0 })
const hasInitializedScale = ref(false)

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

/**
 * 获取容器尺寸
 */
async function getContainerSize() {
  return new Promise<{ width: number, height: number }>((resolve, reject) => {
    const query = uni.createSelectorQuery()
    query.select('.image-container').boundingClientRect((data) => {
      if (data && !Array.isArray(data)) {
        resolve({
          width: data.width,
          height: data.height,
        })
      }
      else {
        reject(new Error('Failed to get container size'))
      }
    }).exec()
  })
}

/**
 * 计算最佳初始缩放比例
 * 只基于图片宽度和容器宽度计算
 */
function calculateInitialScale(imageWidth: number, imageHeight: number): number {
  if (!containerSize.value.width || !containerSize.value.height) {
    return 1.0
  }

  // 预留一些边距（24px左右padding + 额外空间）
  const padding = 12
  const availableWidth = containerSize.value.width - padding

  // 只根据宽度计算缩放比例
  const scale = availableWidth / imageWidth

  // 限制在合理范围内
  return Math.max(0.15, Math.min(5.0, scale))
}

/**
 * 处理图片就绪事件
 */
function handleImageReady(imageInfo: { width: number, height: number }) {
  if (hasInitializedScale.value)
    return
  const initialScale = calculateInitialScale(imageInfo.width, imageInfo.height)
  imageScale.value = initialScale
  hasInitializedScale.value = true
  console.log('Initial scale calculated:', initialScale, 'for image:', imageInfo)
}

/**
 * 重新计算缩放比例
 * 用于横竖屏切换后重新适应
 */
async function recalculateScale() {
  try {
    // 重新获取容器尺寸
    containerSize.value = await getContainerSize()
    console.log('Container size updated:', containerSize.value)

    // 如果有图片信息，重新计算缩放
    if (imageViewerRef.value?.firstImageSize.width && imageViewerRef.value?.firstImageSize.height) {
      const newScale = calculateInitialScale(
        imageViewerRef.value.firstImageSize.width,
        imageViewerRef.value.firstImageSize.height,
      )
      imageScale.value = newScale
      console.log('Scale recalculated after orientation change:', newScale)
    }
  }
  catch (error) {
    console.warn('Failed to recalculate scale:', error)
  }
}

const markingDataProvider = props.mode === 'review' ? new ReviewMarkingDataProvider() : new DefaultMarkingDataProvider()
const markingHistoryProvider = props.mode === 'review' ? new ReviewMarkingHistoryProvider() : new DefaultMarkingHistoryProvider()

const context = provideMarkingContext({
  dataProvider: markingDataProvider,
  historyProvider: markingHistoryProvider,
  isHistory: false,
  defaultPosition: 'last',
})

// 提供历史记录管理
provideMarkingHistory({ taskId })

// 提供导航管理
const markingNavigation = provideMarkingNavigation({ taskId })
const {
  currentIndex: navCurrentIndex,
  totalCount: navTotalCount,
  isViewingHistory,
  canGoPrev,
  canGoNext,
  goToPrevQuestion,
  goToNextQuestion,
  initNavigation,
  createSwipeHandler,
} = markingNavigation

// 提供数据管理
const markingData = provideMarkingData({
  taskId,
  questionId,
  examId,
  subjectId,
  isLandscape,
  taskType,
  markingNavigation,
})
const { questionData: questions, questionsList, totalQuestions: totalQuestionsCount } = markingData

// 全屏弹窗状态
const showFullscreenImage = ref(false)

const currentQuestionIndex = ref(0)
const totalQuestions = computed(() => totalQuestionsCount.value)

// 分数数据
const myScore = computed(() => {
  const data = markingData.avgScoreData.value
  return data?.teacher_score.average_score?.toFixed(2) || 0
})
const avgScore = computed(() => {
  const data = markingData.avgScoreData.value
  return data?.all_teachers_score.average_score?.toFixed(2) || 0
})

// 页面加载时获取参数
onLoad((options) => {
  examId.value = Number(options.examId)
  subjectId.value = Number(options.subjectId)
  questionId.value = Number(options.questionId)
  taskId.value = Number(options.taskId) // 从路由参数获取taskId
  evaluationType.value = options.type as 'single' | 'double' || 'single'
  taskType.value = options.taskType
})

// 监听屏幕方向变化
function handleOrientationChange() {
  // #ifdef H5
  const orientation = window.screen.orientation?.angle || 0
  isLandscape.value = orientation === 90 || orientation === 270
  // #endif

  // #ifdef APP-PLUS
  // plus.screen.lockOrientation('portrait-primary')
  // #endif

  // 延迟一下以确保DOM更新完成
  nextTick(() => {
    setTimeout(() => {
      recalculateScale()
      // 根据横竖屏切换系统导航栏显示
      updateSystemUIVisibility()
    }, 300) // 给一些时间让布局稳定
  })
}

/**
 * 更新系统 UI 可见性（仅竖屏时隐藏导航栏）
 */
function updateSystemUIVisibility() {
  // #ifdef APP-PLUS
  plus.navigator.setFullscreen(true)
  // #endif

  // #ifdef H5
  // H5 端无法直接控制系统导航栏
  // #endif
}

// 监听 isLandscape 变化（手动切换横竖屏时）
watch(isLandscape, () => {
  nextTick(() => {
    setTimeout(() => {
      recalculateScale()
      // 根据横竖屏切换系统导航栏显示
      updateSystemUIVisibility()
    }, 300)
  })
})

// 监听阅卷数据加载完成，延迟 100ms 后重新初始化
let hasReinitialized = false
watch(questions, (newQuestions) => {
  if (newQuestions && newQuestions.length > 0 && !hasReinitialized) {
    hasReinitialized = true
    setTimeout(async () => {
      try {
        containerSize.value = await getContainerSize()
        console.log('Container size recalculated after data loaded:', containerSize.value)

        // 如果有图片信息，重新计算缩放
        if (imageViewerRef.value?.firstImageSize.width && imageViewerRef.value?.firstImageSize.height) {
          const newScale = calculateInitialScale(
            imageViewerRef.value.firstImageSize.width,
            imageViewerRef.value.firstImageSize.height,
          )
          imageScale.value = newScale
          console.log('Scale recalculated after data loaded:', newScale)
        }
      }
      catch (error) {
        console.warn('Failed to recalculate after data loaded:', error)
      }
    }, 100)
  }
})

onMounted(async () => {
  // #ifdef H5
  window.addEventListener('orientationchange', handleOrientationChange)
  // #endif

  // #ifdef APP-PLUS
  plus.screen.lockOrientation('landscape-primary')
  // 初始化时根据当前方向设置系统 UI 可见性
  updateSystemUIVisibility()
  // #endif

  // 初始化导航
  await initNavigation()

  // 等待DOM渲染完成后获取容器尺寸
  await nextTick()
  try {
    containerSize.value = await getContainerSize()
    console.log('Container size:', containerSize.value)

    // 延迟1秒再次计算比例，确保图片铺满
    setTimeout(() => {
      recalculateScale()
    }, 1000)
  }
  catch (error) {
    console.warn('Failed to get container size:', error)
  }
})

onUnmounted(() => {
  // #ifdef H5
  window.removeEventListener('orientationchange', handleOrientationChange)
  // #endif

  // #ifdef APP-PLUS
  plus.screen.lockOrientation('portrait-primary')
  // 恢复系统导航栏显示
  plus.navigator.setFullscreen(false)
  // #endif
})

// 切换屏幕方向
function toggleOrientation() {
  // #ifdef APP-PLUS
  if (isLandscape.value) {
    plus.screen.lockOrientation('portrait-primary')
  }
  else {
    plus.screen.lockOrientation('landscape-primary')
  }
  // #endif

  isLandscape.value = !isLandscape.value
}

// 打开全屏图片弹窗
function toggleFullscreen() {
  showFullscreenImage.value = true
}

// 返回上一页
function goBack() {
  uni.navigateBack()
}

// 题目选择
function selectQuestion(index: number) {
  currentQuestionIndex.value = index
  questions.value = []
}

// 弹窗状态
const showScoreSettings = ref(false)
const showAvgScore = ref(false)
const showAnswer = ref(false)

// 打分设置
function openScoreSettings() {
  showScoreSettings.value = true
}

// 打分设置确认
function handleScoreSettingsConfirm(data: { stepSize: number, commonScores: number[] }) {
  console.log('打分设置已确认:', data)
  uni.showToast({
    title: '设置已保存',
    icon: 'success',
  })
}

// 查看均分
function viewAvgScore() {
  showAvgScore.value = true
  markingData.refetchAvgScore()
}

// 查看答案
function viewAnswer() {
  showAnswer.value = true
}

// 当前题目信息
const currentQuestions = computed(() => questionsList.value[currentQuestionIndex.value])
// 如果在历史查看模式，使用历史记录数据，否则使用当前题目数据
const currentQuestion = computed(() => {
  if (isViewingHistory.value && markingNavigation.currentHistoryQuestion.value) {
    // 历史模式：返回历史记录
    return markingNavigation.currentHistoryQuestion.value
  }
  // 正常模式：返回当前题目
  return questions.value[0]
})
const currentTask = computed(() => currentQuestions.value?.tasks?.[taskType.value])
const fullScore = ref(0)
watchImmediate(currentQuestion, () => {
  fullScore.value = currentQuestion.value?.full_score || 0
})

// 当前答题卡图片列表
const currentImageUrls = computed(() => currentQuestion.value?.image_urls || [])

let isFirst = true
whenever(questionsList, () => {
  if (isFirst) {
    isFirst = false
    currentQuestionIndex.value = questionsList.value.findIndex(q => q.question_id === questionId.value)
  }
})

const queryClient = useQueryClient()
whenever(currentTask, (task, oldTask) => {
  taskId.value = task?.id
  questionId.value = task?.question_id

  queryClient.invalidateQueries({ queryKey: ['marking-question', oldTask?.id] })
  queryClient.invalidateQueries({ queryKey: ['marking-question', task.id] })
})

// 提交分数反馈状态
const showScoreFeedback = ref(false)
const feedbackScore = ref(0)
const doubleUnderlineSvg = `<svg width="100%" height="100%" viewBox="0 0 120 40" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none">
<path d="M5 12 Q 60 5 115 12" stroke="red" stroke-width="5" stroke-linecap="round" fill="none" />
<path d="M10 28 Q 60 22 110 30" stroke="red" stroke-width="5" stroke-linecap="round" fill="none" />
</svg>`

// 快捷打分选择
async function handleQuickScoreSelect(score: number) {
  console.log('选择分数:', score)

  // 设置当前分数
  markingData.currentScore.value = score

  // 显示反馈动画
  feedbackScore.value = score
  showScoreFeedback.value = true

  try {
    await markingData.submitSingleRecord()
  }
  catch (error) {
    console.error('提交失败:', error)
    uni.showToast({
      title: error.message || '提交失败',
      icon: 'none',
    })
  }
  finally {
    // 延迟隐藏反馈
    setTimeout(() => {
      showScoreFeedback.value = false
    }, 400)
  }
}

// 历史查看模式提示
const historyModeText = computed(() => {
  if (isViewingHistory.value) {
    return `${navCurrentIndex.value}/${totalQuestionsCount.value}`
  }
  return ''
})

// 上一题
async function handlePrevQuestion() {
  if (props.mode === 'review')
    return
  await goToPrevQuestion()
}

// 下一题
async function handleNextQuestion() {
  if (props.mode === 'review')
    return
  await goToNextQuestion()
}

/**
 * 处理滚动边缘变化
 */
function handleScrollEdge(left: boolean, right: boolean) {
  atLeftEdge.value = left
  atRightEdge.value = right
}

// 创建手势处理器
const swipeHandler = createSwipeHandler()

// 全局双指缩放手势状态
const isGesturing = ref(false)
const initialDistance = ref(0)
const initialScale = ref(1.0)
const lastUpdateTime = ref(0)

/**
 * 计算两点之间的距离
 */
function getDistance(touch1: Touch, touch2: Touch): number {
  const dx = touch2.clientX - touch1.clientX
  const dy = touch2.clientY - touch1.clientY
  return Math.sqrt(dx * dx + dy * dy)
}

/**
 * 全局触摸开始处理 - 捕获阶段优先处理双指缩放
 */
function handleGlobalTouchStart(e: TouchEvent) {
  if (e.touches.length === 2) {
    isGesturing.value = true
    initialDistance.value = getDistance(e.touches[0], e.touches[1])
    initialScale.value = imageScale.value
    lastUpdateTime.value = Date.now()
  }
  else if (atLeftEdge.value || atRightEdge.value) {
    // 只有在边缘时才允许手势切换
    swipeHandler.onTouchStart(e)
  }
}

/**
 * 全局触摸移动处理 - 捕获阶段优先处理双指缩放
 * 使用节流优化性能，避免缩放卡死
 */
function handleGlobalTouchMove(e: TouchEvent) {
  if (e.touches.length === 2 && isGesturing.value) {
    // 节流：每 16ms (约 60fps) 更新一次
    const now = Date.now()
    if (now - lastUpdateTime.value < 16) {
      return
    }
    lastUpdateTime.value = now

    const currentDistance = getDistance(e.touches[0], e.touches[1])
    const scaleChange = currentDistance / initialDistance.value
    const newScale = Math.max(0.15, Math.min(5.0, initialScale.value * scaleChange))

    // 只有当变化超过一定阈值时才更新（减少不必要的更新）
    if (Math.abs(newScale - imageScale.value) > 0.01) {
      imageScale.value = newScale
    }

    e.preventDefault()
  }
}

/**
 * 全局触摸结束处理
 */
function handleGlobalTouchEnd(e: TouchEvent) {
  if (e.touches.length < 2) {
    if (atLeftEdge.value || atRightEdge.value) {
      swipeHandler.onTouchEnd(e)
    }
    isGesturing.value = false
  }
}

// 下一题的图片列表（用于预加载）
const nextQuestionImages = computed(() => {
  return cachedImages.value
})
</script>

<template>
  <div
    class="relative h-screen w-100vw flex flex-col touch-pan-x touch-pan-y overflow-hidden overscroll-none"
    :style="{ paddingTop: `${(isLandscape ? 0 : safeAreaInsets?.top || 0)}px` }"
    @touchstart="handleGlobalTouchStart"
    @touchmove="handleGlobalTouchMove"
    @touchend="handleGlobalTouchEnd"
  >
    <!-- 缩放提示 -->
    <view
      v-if="isGesturing"
      class="pointer-events-none fixed left-1/2 top-1/2 z-50 rounded-lg px-4 py-2 text-white"
      :style="{
        backgroundColor: 'rgba(0, 0, 0, 0.7)',
        transform: 'translate(-50%, -50%)',
      }"
    >
      {{ Math.round(imageScale * 100) }}%
    </view>

    <MarkingLayout
      :mode
      :is-landscape="isLandscape"
      :is-fullscreen="false"
      :current-question-index="currentQuestionIndex"
      :current-task-submit="navCurrentIndex || 0"
      :total-questions="totalQuestions"
      :questions="questionsList"
      :my-score="Number(myScore)"
      :avg-score="Number(avgScore)"
      :is-viewing-history="isViewingHistory"
      :can-go-prev="canGoPrev"
      :can-go-next="canGoNext"
      :history-mode-text="historyModeText"
      :task-id="taskId"
      :current-question-full-score="fullScore"
      :current-question-final-score="currentQuestion?.final_score || 0"
      @go-back="goBack"
      @select-question="selectQuestion"
      @open-score-settings="openScoreSettings"
      @view-avg-score="viewAvgScore"
      @view-answer="viewAnswer"
      @toggle-orientation="toggleOrientation"
      @toggle-fullscreen="toggleFullscreen"
      @prev-question="handlePrevQuestion"
      @next-question="handleNextQuestion"
    >
      <template #content>
        <div class="image-container h-full w-full">
          <MarkingImageViewerNew
            v-if="questions[0]?.image_urls?.length"
            ref="imageViewerRef"
            v-model:scale="imageScale"
            :question-data="[currentQuestion]"
            :image-size="100"
            :next-question-images="nextQuestionImages"
            @ready="handleImageReady"
            @scroll-edge="handleScrollEdge"
            @touch-start="handleGlobalTouchStart"
            @touch-move="handleGlobalTouchMove"
            @touch-end="handleGlobalTouchEnd"
          />
        </div>
      </template>

      <!-- 打分区域（横屏和竖屏共用） -->
      <template #scoring>
        <QuickScorePanel
          :is-landscape="isLandscape"
          :full-score="fullScore"
          @score-selected="handleQuickScoreSelect"
          @toggle-collapse="recalculateScale"
        />
      </template>
    </MarkingLayout>

    <!-- 打分设置弹窗 -->
    <ScoreSettingsDialog
      v-model="showScoreSettings"
      :full-score="currentQuestions?.full_score"
      @confirm="handleScoreSettingsConfirm"
    />

    <!-- 查看均分弹窗 -->
    <AvgScoreDialog
      v-model="showAvgScore"
      :my-score="myScore"
      :avg-score="avgScore"
      :question-title="`${currentQuestions?.question_major}.${currentQuestions?.question_minor}`"
      :full-score="currentQuestions?.full_score"
      :avg-score-data="markingData.avgScoreData.value"
    />

    <!-- 查看答案弹窗 -->
    <AnswerDialog
      v-if="currentQuestion"
      v-model="showAnswer"
      :question-title="`${currentQuestion?.question_major}.${currentQuestion?.question_minor}`"
      :full-score="fullScore"
      :standard-answer="currentQuestion?.standard_answer || ''"
    />

    <!-- 全屏图片弹窗 -->
    <FullscreenImageDialog
      v-model="showFullscreenImage"
      :image-urls="currentImageUrls"
    />

    <!-- 提交分数反馈动画 -->
    <view
      v-if="showScoreFeedback"
      class="pointer-events-none fixed left-1/2 top-1/2 z-999 flex flex-col items-center justify-center text-red-500"
      style="transform: translate(-50%, -50%) rotate(-10deg)"
    >
      <text class="text-96px font-bold leading-none" style="font-family: 'KaiTi', 'STKaiti', serif">
        {{ feedbackScore }}
      </text>
      <view class="h-7 w-20" :style="{ backgroundImage: `url('${svgToDataURL(doubleUnderlineSvg)}')`, backgroundSize: 'contain', backgroundRepeat: 'no-repeat', backgroundPosition: 'center' }" />
    </view>
  </div>
</template>

<style scoped>
/* 禁用橡皮筋效果 */
.h-screen {
  position: fixed;
  overscroll-behavior: none;
  -webkit-overflow-scrolling: touch;
}

/* H5端额外的橡皮筋禁用 */
/* #ifdef H5 */
body,
html {
  overscroll-behavior: none;
  overflow: hidden;
  position: fixed;
  width: 100%;
  height: 100%;
}
/* #endif */

/* 微信小程序端橡皮筋禁用 */
/* #ifdef MP-WEIXIN */
page {
  overflow: hidden;
  overscroll-behavior: none;
}
/* #endif */

/* APP端橡皮筋禁用 */
/* #ifdef APP-PLUS */
page {
  overflow: hidden;
}
/* #endif */
</style>
