<!-- Manga.vue -->
<script setup lang="ts">
import { ref, onMounted, onUnmounted, computed, watch } from 'vue'
import { useRoute } from 'vue-router'
import axios from 'axios'

const route = useRoute()

// 漫画专辑数据
interface AlbumData {
  album_id: string
  name: string
  image_urls: string[]
  nums: number[]
  authors?: string[]
  tags?: string[]
}

// 漫画图片列表（从 jm.vue 中获取）
const mangaImages = ref<string[]>([])
const mangaNums = ref<number[]>([])
const albumInfo = ref<Omit<AlbumData, 'image_urls' | 'nums'> | null>(null)

// 阅读器状态
const showMenu = ref(false)
const isFullscreen = ref(false)
const showDrawer = ref(false)
const currentImageIndex = ref(0) // 当前显示的图片索引
const imageStates = ref<Array<{ scale: number; translateX: number; translateY: number }>>([])
const loading = ref(true)
const canvasImages = ref<string[]>([]) // 解码后的图片
const abortLoading = ref(false) // 取消加载标志

// 计算是否应该隐藏头部（用于样式调整）
const shouldHideHeader = computed(() => {
  return route.meta?.hideHeader === true
})

// 计算当前页码信息
const currentPageInfo = computed(() => {
  return `第 ${currentImageIndex.value + 1} / ${mangaImages.value.length} 页`
})

// 获取专辑数据
const fetchAlbum = async (id: string) => {
  console.log('尝试获取专辑数据，ID:', id)
  if (!id) {
    console.log('ID为空，无法获取专辑数据')
    return
  }

  try {
    loading.value = true
    console.log('发送请求到:', `/api/manga/read?mangaId=${id}`)
    const response = await axios.get(`/api/manga/read?mangaId=${id}`, {
      maxRedirects: 5,
      validateStatus: (status) => status < 500,
    })
    console.log('收到响应:', response)

    let data: AlbumData

    if (response.status === 307 || response.status === 302) {
      const newUrl = new URL(response.headers.location, response.config.url).href
      const redirectResponse = await axios.get(newUrl)
      data = redirectResponse.data
    } else {
      data = response.data
    }

    // 设置专辑信息
    albumInfo.value = {
      album_id: data.album_id,
      name: data.name,
      authors: data.authors || [],
      tags: data.tags || []
    }

    // 设置图片 URL 和解码参数
    mangaImages.value = data.image_urls || []
    mangaNums.value = data.nums || []

    // 初始化图片状态
    imageStates.value = (data.image_urls || []).map(() => ({
      scale: 1,
      translateX: 0,
      translateY: 0
    }))

    // 初始化画布图片数组
    canvasImages.value = new Array((data.image_urls || []).length)

    // 开始加载图片
    if (data.image_urls && data.nums) {
      loadImagesInBatches(data.image_urls, data.nums)
    } else {
      loading.value = false
    }
  } catch (error) {
    console.error('加载专辑失败', error)
    loading.value = false
  }
}

// 分批加载图片（每次加载4张）
const loadImagesInBatches = async (urls: string[], nums: number[]) => {
  const batchSize = 4 // 每批加载4张图片
  let currentIndex = 0
  abortLoading.value = false // 开始新加载任务前重置标志

  while (currentIndex < urls.length && !abortLoading.value) {
    const batchUrls = urls.slice(currentIndex, currentIndex + batchSize)
    const batchNums = nums.slice(currentIndex, currentIndex + batchSize)

    const loadPromises = batchUrls.map((url, index) => {
      return new Promise<void>((resolve) => {
        if (abortLoading.value) return resolve()

        const img = new Image()
        img.crossOrigin = 'anonymous'
        img.src = url

        img.onload = () => {
          if (abortLoading.value) return resolve()

          if (batchNums[index] !== 0) {
            const decodedCanvas = decodeImage(img, batchNums[index])
            const base64 = decodedCanvas.toDataURL()
            canvasImages.value[currentIndex + index] = base64
          } else {
            canvasImages.value[currentIndex + index] = url
          }
          resolve()
        }

        img.onerror = () => {
          if (abortLoading.value) return resolve()
          console.error(`图片加载失败: ${url}`)
          // 加载失败时使用原始 URL
          canvasImages.value[currentIndex + index] = url
          resolve()
        }
      })
    })

    await Promise.all(loadPromises)
    currentIndex += batchSize
  }

  loading.value = false
}

// JS 版 decodeImage（等效 Java 方法）
const decodeImage = (imgSrc: HTMLImageElement, num: number): HTMLCanvasElement => {
  if (num === 0) {
    const canvas = document.createElement('canvas')
    canvas.width = imgSrc.width
    canvas.height = imgSrc.height
    const ctx = canvas.getContext('2d')
    ctx?.drawImage(imgSrc, 0, 0)
    return canvas
  }

  const w = imgSrc.width
  const h = imgSrc.height
  const canvas = document.createElement('canvas')
  canvas.width = w
  canvas.height = h
  const ctx = canvas.getContext('2d')!

  const over = h % num

  for (let i = 0; i < num; i++) {
    let move = Math.floor(h / num)
    let ySrc = h - move * (i + 1) - over
    let yDst = move * i

    if (i === 0) {
      move += over
    } else {
      yDst += over
    }

    const srcRect = { x: 0, y: ySrc, width: w, height: move }
    const dstRect = { x: 0, y: yDst, width: w, height: move }

    const tempCanvas = document.createElement('canvas')
    tempCanvas.width = w
    tempCanvas.height = move
    const tempCtx = tempCanvas.getContext('2d')!
    tempCtx.drawImage(
      imgSrc,
      srcRect.x,
      srcRect.y,
      srcRect.width,
      srcRect.height,
      0,
      0,
      srcRect.width,
      srcRect.height
    )

    ctx.drawImage(
      tempCanvas,
      0,
      0,
      tempCanvas.width,
      tempCanvas.height,
      dstRect.x,
      dstRect.y,
      dstRect.width,
      dstRect.height
    )
  }

  return canvas
}

// 切换抽屉菜单显示
const toggleDrawer = () => {
  showDrawer.value = !showDrawer.value
}

// 切换顶部菜单显示
const toggleMenu = () => {
  showMenu.value = !showMenu.value
}

// 进入全屏模式
const enterFullscreen = () => {
  const element = document.documentElement
  if (element.requestFullscreen) {
    element.requestFullscreen()
    isFullscreen.value = true
  }
}

// 退出全屏模式
const exitFullscreen = () => {
  if (document.exitFullscreen) {
    document.exitFullscreen()
    isFullscreen.value = false
  }
}

// 重置所有图片的缩放
const resetAllImages = () => {
  imageStates.value = imageStates.value.map(() => ({
    scale: 1,
    translateX: 0,
    translateY: 0
  }))
}

// 处理双指缩放（只响应真正的触摸事件）
let initialDistance = 0
let initialScale = 1

const getDistance = (touch1: Touch, touch2: Touch) => {
  const dx = touch1.clientX - touch2.clientX
  const dy = touch1.clientY - touch2.clientY
  return Math.sqrt(dx * dx + dy * dy)
}

const handleTouchStart = (index: number, event: TouchEvent) => {
  if (event.touches.length === 2) {
    // 双指触摸开始
    initialDistance = getDistance(event.touches[0], event.touches[1])
    initialScale = imageStates.value[index].scale
  } else if (event.touches.length === 1) {
    // 单指触摸，可能是滚动，不阻止默认行为
    return
  }
}

const handleTouchMove = (index: number, event: TouchEvent) => {
  if (event.touches.length === 2) {
    // 双指缩放
    event.preventDefault() // 只在双指操作时阻止默认行为
    const currentDistance = getDistance(event.touches[0], event.touches[1])
    const scale = initialScale * (currentDistance / initialDistance)

    // 限制缩放范围
    const clampedScale = Math.min(Math.max(scale, 1), 3)
    imageStates.value[index].scale = clampedScale
  }
}

// 处理滚轮缩放（仅鼠标滚轮）
const handleWheel = (index: number, event: WheelEvent) => {
  // 确保是鼠标滚轮事件而不是触摸板手势
  if (Math.abs(event.deltaX) > Math.abs(event.deltaY) * 2) {
    // 可能是水平滚动，不处理缩放
    return
  }

  event.preventDefault()
  const currentState = imageStates.value[index]

  if (event.deltaY < 0) {
    // 向上滚动放大
    if (currentState.scale < 3) {
      currentState.scale *= 1.1
    }
  } else {
    // 向下滚动缩小
    if (currentState.scale > 1) {
      currentState.scale /= 1.1
      if (currentState.scale <= 1) {
        currentState.scale = 1
        currentState.translateX = 0
        currentState.translateY = 0
      }
    }
  }
}

// 跳转到指定图片
const scrollToImage = (index: number) => {
  if (index < 0 || index >= mangaImages.value.length) return

  const element = document.getElementById(`image-${index}`)
  if (element) {
    element.scrollIntoView({ behavior: 'smooth', block: 'center' })
    currentImageIndex.value = index
    // 关闭抽屉菜单
    showDrawer.value = false
  }
}

// 跳转到下一张图片
const nextImage = () => {
  if (currentImageIndex.value < mangaImages.value.length - 1) {
    scrollToImage(currentImageIndex.value + 1)
  }
}

// 跳转到上一张图片
const prevImage = () => {
  if (currentImageIndex.value > 0) {
    scrollToImage(currentImageIndex.value - 1)
  }
}

// 节流函数
const throttle = (func: Function, limit: number) => {
  let inThrottle: boolean
  return function() {
    const args = arguments
    const context = this
    if (!inThrottle) {
      func.apply(context, args)
      inThrottle = true
      setTimeout(() => inThrottle = false, limit)
    }
  }
}

// 监听滚动事件，更新当前图片索引
const handleScroll = () => {
  const containers = document.querySelectorAll('.image-container')
  let currentIndex = 0

  // 使用更精确的计算方式确定当前视口中的图片
  for (let i = 0; i < containers.length; i++) {
    const rect = containers[i].getBoundingClientRect()
    // 当图片的任意部分在视口中时就认为是当前图片
    if (rect.bottom > 0 && rect.top < window.innerHeight) {
      // 优先选择图片中心点在视口中央的图片
      if (Math.abs(rect.top + rect.height/2 - window.innerHeight/2) <
        Math.abs(containers[currentIndex].getBoundingClientRect().top +
          containers[currentIndex].getBoundingClientRect().height/2 - window.innerHeight/2)) {
        currentIndex = i
      }
    }
  }

  // 只有当索引真正改变时才更新
  if (currentImageIndex.value !== currentIndex) {
    currentImageIndex.value = currentIndex
  }
}

// 使用节流优化滚动处理
const throttledHandleScroll = throttle(handleScroll, 100)

// 键盘事件处理
const handleKeydown = (event: KeyboardEvent) => {
  switch (event.key) {
    case 'ArrowLeft':
      prevImage()
      event.preventDefault()
      break
    case 'ArrowRight':
      nextImage()
      event.preventDefault()
      break
    case 'Escape':
      if (isFullscreen.value) {
        exitFullscreen()
      }
      showDrawer.value = false
      break
  }
}

// 监听路由参数变化
watch(
  () => route.params.id,
  (newId) => {
    console.log('路由参数变化:', newId)
    if (newId) {
      abortLoading.value = true // 取消之前的加载
      fetchAlbum(newId as string)
    }
  },
  { immediate: true }
)

// 组件挂载时添加事件监听器
onMounted(() => {
  window.addEventListener('keydown', handleKeydown)
  // 直接监听 manga-reader 元素的滚动事件，而不是 manga-content
  const mangaReader = document.querySelector('.manga-reader')
  if (mangaReader) {
    mangaReader.addEventListener('scroll', throttledHandleScroll)
  }

  // 初始化当前图片索引
  handleScroll()
})

// 组件卸载时移除事件监听器
onUnmounted(() => {
  window.removeEventListener('keydown', handleKeydown)
  const mangaReader = document.querySelector('.manga-content')
  if (mangaReader) {
    mangaReader.removeEventListener('scroll', throttledHandleScroll)
  }
  abortLoading.value = true // 取消加载
})
</script>

<template>
  <div class="manga-reader"
       @click="toggleMenu"
       :class="{ 'no-header': shouldHideHeader }">

<!--    &lt;!&ndash; 始终可见的页码显示 &ndash;&gt;-->
<!--    <div class="page-indicator">-->
<!--      {{ currentPageInfo }}-->
<!--    </div>-->

    <!-- 顶部菜单栏 -->
    <div
      class="menu-bar"
      :class="{ visible: showMenu }"
      @click.stop
    >
      <div class="menu-content">
        <span class="page-info">{{ currentPageInfo }}</span>
        <button @click="prevImage" :disabled="currentImageIndex === 0 || loading">上一张</button>
        <button @click="nextImage" :disabled="currentImageIndex === mangaImages.length - 1 || loading">下一张</button>
        <button @click="isFullscreen ? exitFullscreen() : enterFullscreen()">
          {{ isFullscreen ? '退出全屏' : '全屏' }}
        </button>
        <button @click="toggleDrawer">菜单</button>
      </div>
    </div>

    <!-- 左侧抽屉菜单 -->
    <div
      class="drawer-overlay"
      :class="{ 'drawer-open': showDrawer }"
      @click="toggleDrawer"
    >
      <div
        class="drawer"
        :class="{ 'drawer-open': showDrawer }"
        @click.stop
      >
        <div class="drawer-content">
          <div class="drawer-header">
            <h3>ReiJM</h3>
            <button @click="toggleDrawer" class="close-btn">×</button>
          </div>
          <div class="drawer-body">
            <button @click="isFullscreen ? exitFullscreen() : enterFullscreen()" class="drawer-item">
              {{ isFullscreen ? '退出全屏' : '进入全屏' }}
            </button>
            <div class="page-list">
              <h4>页面列表</h4>
              <div
                v-for="(image, index) in mangaImages"
                :key="index"
                class="page-item"
                :class="{ 'active': index === currentImageIndex }"
                @click="scrollToImage(index)"
              >
                第 {{ index + 1 }} 页
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 漫画内容 -->
    <div class="manga-content">
      <!-- 专辑信息 -->
      <div v-if="albumInfo" class="comic-header">
        <h1 class="comic-title">{{ albumInfo.name }}</h1>
        <div class="comic-meta">
          <div v-if="albumInfo.authors && albumInfo.authors.length" class="meta-item">
            <span class="label">作者：</span>
            <span class="value">{{ albumInfo.authors.join(' / ') }}</span>
          </div>
          <div v-if="albumInfo.tags && albumInfo.tags.length" class="meta-item">
            <span class="label">标签：</span>
            <span class="value tags">
              <span v-for="(tag, idx) in albumInfo.tags" :key="idx" class="tag">{{ tag }}</span>
            </span>
          </div>
        </div>
      </div>

      <!-- 加载状态 -->
      <div v-if="loading" class="loading">加载中...</div>

      <!-- 漫画图片 -->
      <div
        v-for="(image, index) in canvasImages"
        :key="index"
        class="image-container"
        :id="`image-${index}`"
      >
        <img
          v-if="image"
          :src="image"
          :alt="`漫画第 ${index + 1} 页`"
          class="manga-image"
          :style="{
            transform: `scale(${imageStates[index].scale}) translate(${imageStates[index].translateX}px, ${imageStates[index].translateY}px)`
          }"
          @wheel="handleWheel(index, $event)"
          @touchstart="handleTouchStart(index, $event)"
          @touchmove="handleTouchMove(index, $event)"
        />
        <div v-else class="image-placeholder">图片加载中...</div>
      </div>
    </div>

    <!-- 点击屏幕显示菜单的提示区域 -->
    <div
      class="screen-click-area"
      @click="toggleMenu"
    ></div>
  </div>
</template>

<style scoped>
.manga-reader {
  position: relative;
  width: 100vw;
  height: 100vh;
  background-color: #000;
  overflow-y: auto;
  overflow-x: hidden;
  user-select: none;
  padding-top: 0; /* 移除顶部内边距 */
  padding-bottom: 60px; /* 添加底部内边距 */
}

.manga-reader.no-header {
  padding-bottom: 0; /* 无头部时也无底部内边距 */
}

/* 添加页码指示器样式 */
.page-indicator {
  position: fixed;
  top: 10px;
  left: 50%;
  transform: translateX(-50%);
  background-color: rgba(0, 0, 0, 0.7);
  color: white;
  padding: 5px 15px;
  border-radius: 20px;
  font-size: 14px;
  z-index: 90;
  pointer-events: none; /* 不拦截点击事件 */
}

.menu-bar {
  position: fixed;
  bottom: 0; /* 改为底部定位 */
  left: 0;
  right: 0;
  background-color: rgba(0, 0, 0, 0.8);
  color: white;
  padding: 10px 20px;
  z-index: 100;
  transform: translateY(100%); /* 改为向上偏移 */
  transition: transform 0.3s ease;
}

.menu-bar.visible {
  transform: translateY(0); /* 回到正常位置 */
}

.menu-content {
  display: flex;
  justify-content: space-between;
  align-items: center;
  max-width: 800px;
  margin: 0 auto;
}

.menu-content button {
  background-color: rgba(255, 255, 255, 0.2);
  color: white;
  border: none;
  padding: 8px 16px;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.2s;
  margin-left: 10px;
}

.menu-content button:hover:not(:disabled) {
  background-color: rgba(255, 255, 255, 0.3);
}

.menu-content button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.page-info {
  font-size: 16px;
  white-space: nowrap;
}

/* 左侧抽屉菜单样式 */
.drawer-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  z-index: 199;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0.3s ease;
}

.drawer-overlay.drawer-open {
  opacity: 1;
  visibility: visible;
}

.drawer {
  position: fixed;
  top: 0;
  left: 0;
  width: 300px;
  height: 100vh;
  background-color: rgba(0, 0, 0, 0.9);
  color: white;
  z-index: 200;
  transform: translateX(-100%);
  transition: transform 0.3s ease;
  overflow-y: auto;
}

.drawer.drawer-open {
  transform: translateX(0);
}

.drawer-content {
  padding: 20px;
  height: 100%;
  display: flex;
  flex-direction: column;
}

.drawer-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  padding-bottom: 10px;
  border-bottom: 1px solid #333;
  flex-shrink: 0;
}

.drawer-header h3 {
  margin: 0;
}

.close-btn {
  background: none;
  border: none;
  color: white;
  font-size: 24px;
  cursor: pointer;
}

.drawer-body {
  flex: 1;
  overflow-y: auto;
}

.drawer-item {
  display: block;
  width: 100%;
  padding: 12px;
  margin-bottom: 10px;
  background-color: rgba(255, 255, 255, 0.1);
  color: white;
  border: none;
  border-radius: 4px;
  text-align: left;
  cursor: pointer;
}

.drawer-item:hover {
  background-color: rgba(255, 255, 255, 0.2);
}

.page-list h4 {
  margin: 20px 0 10px 0;
  color: #ccc;
}

.page-item {
  padding: 8px;
  margin: 5px 0;
  background-color: rgba(255, 255, 255, 0.05);
  border-radius: 4px;
  cursor: pointer;
}

.page-item:hover {
  background-color: rgba(255, 255, 255, 0.1);
}

.page-item.active {
  background-color: rgba(255, 255, 255, 0.2);
  font-weight: bold;
}

.manga-content {
  padding: 20px 0 0 0; /* 只保留顶部内边距 */
}

.image-container {
  width: 100%;
  display: flex;
  justify-content: center;
  margin-bottom: 0; /* 移除图片间的间距 */
  padding: 0; /* 移除内边距 */
}

.manga-image {
  max-width: 100%;
  height: auto;
  cursor: zoom-in;
  transform-origin: center center;
  transition: transform 0.2s ease;
  user-select: none;
  -webkit-user-drag: none;
  display: block; /* 避免 inline 元素带来的空白间隙 */
}

.manga-image:active {
  cursor: grabbing;
}

.image-placeholder {
  color: #999;
  font-size: 16px;
  padding: 20px;
}

/* 顶部信息 */
.comic-header {
  margin-bottom: 24px;
  z-index: 2;
  position: relative;
  padding: 0 20px;
}

.comic-title {
  font-size: 28px;
  font-weight: bold;
  margin-bottom: 16px;
  line-height: 1.2;
  color: white;
}

.comic-meta {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.meta-item {
  display: flex;
  align-items: center;
}

.label {
  font-weight: bold;
  color: #aaa;
  width: 50px;
  flex-shrink: 0;
}

.value {
  color: #ddd;
}

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.tag {
  background: rgba(255, 255, 255, 0.1);
  padding: 4px 10px;
  border-radius: 12px;
  font-size: 12px;
  color: #ccc;
}

.loading {
  text-align: center;
  padding: 40px;
  color: #999;
  font-size: 18px;
}

/* 屏幕点击区域 */
.screen-click-area {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 10;
  pointer-events: none;
}

/* 移动端适配 */
@media (max-width: 768px) {
  .menu-content {
    flex-direction: column;
    gap: 10px;
  }

  .menu-content > * {
    width: 100%;
    text-align: center;
  }

  .manga-image {
    max-width: 100%;
  }

  .drawer {
    width: 280px;
  }

  .page-info {
    font-size: 14px;
  }

  .comic-header {
    padding: 0 10px;
  }

  .comic-title {
    font-size: 24px;
  }

  .page-indicator {
    top: 5px;
    font-size: 12px;
    padding: 3px 10px;
  }
}
</style>
