<template>
  <transition name="slide">
    <div v-if="visible" class="pdf-panel">
      <!-- 头部 -->
      <div class="panel-header">
        <h3 class="panel-title">{{ fileName || '文件预览' }}</h3>
        <div class="header-actions">
          <button class="action-btn" @click="zoomOut" :disabled="currentScale <= 1">−</button>
          <span class="zoom-text">{{ Math.round(currentScale * 50) }}%</span>
          <button class="action-btn" @click="zoomIn" :disabled="currentScale >= 4">+</button>
          <button class="close-btn" @click="handleClose">×</button>
        </div>
      </div>

      <!-- 内容区域 -->
      <div class="panel-body">
        <!-- 加载状态 -->
        <div v-if="loading && imageList.length === 0" class="loading-container">
          <div class="loading-spinner"></div>
          <p>正在加载文件...</p>
        </div>

        <!-- 错误状态 -->
        <div v-else-if="error" class="error-container">
          <div class="error-icon">⚠️</div>
          <p class="error-message">{{ error }}</p>
          <button class="retry-btn" @click="loadPdf">重试</button>
        </div>

        <!-- PDF预览区域 -->
        <div v-show="!error && imageList.length > 0" class="pdf-container" ref="pdfContainer" @scroll="handleScroll">
          <div class="pages-wrapper">
            <div v-for="(imgUrl, index) in imageList" :key="index" class="page-container">
              <img :src="imgUrl" class="pdf-page-img" :alt="`第${index + 1}页`" />
              <!-- 水印层 -->
              <div class="watermark-layer" v-if="watermarkConfig">
                <div class="watermark-grid">
                  <span v-for="n in 50" :key="n" class="watermark-text">
                    {{ watermarkFullText }}
                  </span>
                </div>
              </div>
            </div>
          </div>
          <!-- 加载更多提示 -->
          <div v-if="loading && imageList.length > 0 && imageList.length < totalPages" class="loading-more">
            <div class="loading-spinner-small"></div>
            <span>加载中 {{ imageList.length }}/{{ totalPages }}</span>
          </div>
        </div>
      </div>

      <!-- 底部工具栏 -->
      <div class="panel-footer">
        <div class="page-nav">
          <button class="nav-btn" @click="prevPage" :disabled="currentPage <= 1">‹</button>
          <span class="page-info">{{ currentPage }} / {{ totalPages || '-' }}</span>
          <button class="nav-btn" @click="nextPage" :disabled="currentPage >= totalPages">›</button>
        </div>
      </div>
    </div>
  </transition>
</template>

<script setup>
import { ref, watch, onBeforeUnmount, computed } from 'vue'
import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf.js'
import pdfjsWorker from 'pdfjs-dist/legacy/build/pdf.worker.js?url'

// 设置worker - 使用本地worker
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker

const props = defineProps({
  visible: { type: Boolean, default: false },
  fileUrl: { type: String, default: '' },
  fileName: { type: String, default: '' },
  watermarkConfig: { type: Object, default: null }
})

const emit = defineEmits(['close'])

const loading = ref(false)
const error = ref('')
const totalPages = ref(0)
const currentPage = ref(1)
const currentScale = ref(2) // 默认scale=2
const pdfContainer = ref(null)
const imageList = ref([])
let pdfDocument = null

// 计算完整水印文本
const watermarkFullText = computed(() => {
  if (!props.watermarkConfig) return ''
  const { username, account, date } = props.watermarkConfig
  return `${username || ''} ${account || ''} ${date || ''}`.trim()
})

// 加载PDF
const loadPdf = async () => {
  if (!props.fileUrl) {
    error.value = '文件地址为空'
    return
  }
  loading.value = true
  error.value = ''
  imageList.value = []
  totalPages.value = 0
  currentPage.value = 1

  try {
    // 先获取PDF文件的ArrayBuffer
    const response = await fetch(props.fileUrl)
    const arrayBuffer = await response.arrayBuffer()
    
    // 使用arrayBuffer加载PDF，配置CMap支持中文字体
    const loadingTask = pdfjsLib.getDocument({
      data: arrayBuffer,
      cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.11.174/cmaps/',
      cMapPacked: true,
      standardFontDataUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.11.174/standard_fonts/'
    })
    
    pdfDocument = await loadingTask.promise
    totalPages.value = pdfDocument.numPages
    
    // 逐页渲染
    await renderAllPages()
  } catch (err) {
    console.error('PDF加载失败:', err)
    error.value = '文件加载失败，请稍后重试'
    loading.value = false
  }
}

// 渲染所有页面
const renderAllPages = async () => {
  const tempList = []
  for (let pageNum = 1; pageNum <= totalPages.value; pageNum++) {
    const imageUrl = await renderPageToImage(pageNum)
    if (imageUrl) {
      tempList.push(imageUrl)
      imageList.value = [...tempList]
    }
    if (pageNum === 1) loading.value = false
  }
  loading.value = false
}

// 渲染单页到图片
const renderPageToImage = async (pageNum) => {
  if (!pdfDocument) return null
  try {
    const page = await pdfDocument.getPage(pageNum)
    const viewport = page.getViewport({ scale: currentScale.value })
    
    const canvas = document.createElement('canvas')
    canvas.width = Math.floor(viewport.width)
    canvas.height = Math.floor(viewport.height)
    
    const context = canvas.getContext('2d', { willReadFrequently: true })
    if (!context) return null
    
    // 设置白色背景
    context.fillStyle = '#ffffff'
    context.fillRect(0, 0, canvas.width, canvas.height)
    
    await page.render({
      canvasContext: context,
      viewport: viewport
    }).promise
    
    return canvas.toDataURL('image/png')
  } catch (err) {
    console.error(`渲染第${pageNum}页失败:`, err)
    return null
  }
}

// 滚动监听
const handleScroll = () => {
  if (!pdfContainer.value || totalPages.value === 0) return
  const container = pdfContainer.value
  const containerRect = container.getBoundingClientRect()
  const images = container.querySelectorAll('.pdf-page-img')
  
  for (let i = 0; i < images.length; i++) {
    const rect = images[i].getBoundingClientRect()
    if (rect.top >= containerRect.top - rect.height / 2 && rect.top < containerRect.bottom) {
      currentPage.value = i + 1
      break
    }
  }
}

const prevPage = () => {
  if (currentPage.value > 1) {
    currentPage.value--
    scrollToPage(currentPage.value)
  }
}

const nextPage = () => {
  if (currentPage.value < totalPages.value) {
    currentPage.value++
    scrollToPage(currentPage.value)
  }
}

const scrollToPage = (pageNum) => {
  if (!pdfContainer.value) return
  const images = pdfContainer.value.querySelectorAll('.pdf-page-img')
  if (images[pageNum - 1]) {
    images[pageNum - 1].scrollIntoView({ behavior: 'smooth', block: 'start' })
  }
}

// 缩放
const zoomIn = async () => {
  if (currentScale.value < 4) {
    currentScale.value = Math.min(4, currentScale.value + 0.5)
    await reRenderAll()
  }
}

const zoomOut = async () => {
  if (currentScale.value > 1) {
    currentScale.value = Math.max(1, currentScale.value - 0.5)
    await reRenderAll()
  }
}

const reRenderAll = async () => {
  if (!pdfDocument) return
  loading.value = true
  const newList = []
  for (let pageNum = 1; pageNum <= totalPages.value; pageNum++) {
    const imageUrl = await renderPageToImage(pageNum)
    if (imageUrl) {
      newList.push(imageUrl)
    }
  }
  imageList.value = newList
  loading.value = false
}

const handleClose = () => emit('close')

watch([() => props.visible, () => props.fileUrl], ([newVisible, newUrl]) => {
  if (newVisible && newUrl) {
    currentScale.value = 2
    loadPdf()
  } else if (!newVisible) {
    pdfDocument = null
    totalPages.value = 0
    currentPage.value = 1
    imageList.value = []
    error.value = ''
  }
}, { immediate: true })

onBeforeUnmount(() => { pdfDocument = null })
</script>

<style scoped lang="less">
.slide-enter-active, .slide-leave-active { transition: transform 0.3s ease; }
.slide-enter-from, .slide-leave-to { transform: translateX(100%); }

.pdf-panel {
  position: fixed;
  top: 0;
  right: 0;
  width: 40%;
  height: 100vh;
  background: rgba(255, 255, 255, 0.98);
  backdrop-filter: blur(12px);
  display: flex;
  flex-direction: column;
  box-shadow: -4px 0 20px rgba(0, 0, 0, 0.08);
  border-left: 1px solid #e5e7eb;
  z-index: 1000;
}

.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  border-bottom: 1px solid #e5e7eb;
  background: rgba(255, 255, 255, 0.9);

  .panel-title {
    margin: 0;
    font-size: 14px;
    font-weight: 500;
    color: #1f2937;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 50%;
  }

  .header-actions {
    display: flex;
    align-items: center;
    gap: 4px;

    .action-btn {
      width: 28px;
      height: 28px;
      display: flex;
      align-items: center;
      justify-content: center;
      background: #f3f4f6;
      border: none;
      border-radius: 6px;
      cursor: pointer;
      font-size: 14px;
      color: #6b7280;
      transition: all 0.2s;
      &:hover:not(:disabled) { background: #e5e7eb; color: #3b82f6; }
      &:disabled { opacity: 0.4; cursor: not-allowed; }
    }

    .zoom-text {
      min-width: 40px;
      text-align: center;
      font-size: 12px;
      color: #6b7280;
    }

    .close-btn {
      width: 28px;
      height: 28px;
      display: flex;
      align-items: center;
      justify-content: center;
      background: transparent;
      border: none;
      cursor: pointer;
      font-size: 18px;
      color: #9ca3af;
      margin-left: 8px;
      &:hover { color: #ef4444; }
    }
  }
}

.panel-body {
  flex: 1;
  overflow: hidden;
  background: #f8fafc;
  position: relative;
}

.loading-container, .error-container {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 20px;
  color: #6b7280;
}

.loading-spinner {
  width: 32px;
  height: 32px;
  border: 3px solid #e5e7eb;
  border-top-color: #60a5fa;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin-bottom: 12px;
}

.loading-spinner-small {
  width: 16px;
  height: 16px;
  border: 2px solid #e5e7eb;
  border-top-color: #60a5fa;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

.error-icon { font-size: 32px; margin-bottom: 8px; }
.error-message { color: #f87171; font-size: 13px; margin-bottom: 12px; }
.retry-btn {
  padding: 6px 16px;
  background: #fff;
  color: #3b82f6;
  border: 1px solid #bfdbfe;
  border-radius: 16px;
  cursor: pointer;
  font-size: 13px;
  &:hover { background: #eff6ff; }
}

.pdf-container {
  height: 100%;
  overflow: auto;
  padding: 12px;
}

.pages-wrapper {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}

.page-container {
  position: relative;
  background: #fff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
  border-radius: 4px;
}

.pdf-page-img {
  display: block;
  max-width: 100%;
  height: auto;
}

.watermark-layer {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  pointer-events: none;
  overflow: hidden;
}

.watermark-grid {
  position: absolute;
  top: -100%;
  left: -100%;
  width: 300%;
  height: 300%;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  transform: rotate(-45deg);
  transform-origin: center center;
}

.watermark-text {
  color: rgba(100, 100, 100, 0.15);
  font-size: 14px;
  white-space: nowrap;
  user-select: none;
  padding: 30px 50px;
  flex-shrink: 0;
}

.loading-more {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px;
  color: #6b7280;
  font-size: 12px;
}

.panel-footer {
  padding: 8px 16px;
  border-top: 1px solid #e5e7eb;
  background: rgba(255, 255, 255, 0.9);
  display: flex;
  justify-content: center;
}

.page-nav {
  display: flex;
  align-items: center;
  gap: 8px;

  .nav-btn {
    width: 28px;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f3f4f6;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-size: 14px;
    color: #374151;
    &:hover:not(:disabled) { background: #e5e7eb; color: #3b82f6; }
    &:disabled { opacity: 0.4; cursor: not-allowed; }
  }

  .page-info {
    font-size: 12px;
    color: #6b7280;
    min-width: 50px;
    text-align: center;
  }
}
</style>
