<template>
  <div class="pdf-viewer-container">
    <!-- 控制面板 -->
    <div class="control-panel">
      <button @click="loadPDF" :disabled="loading">加载PDF</button>
      <button @click="downloadAndFixPDF" :disabled="loading">下载并修复PDF</button>
      <button @click="testSmallChunk" :disabled="loading">测试小文件下载</button>
      <button @click="resetViewer" :disabled="loading">重置</button>

      <span class="page-info" v-if="totalPages > 0">第 {{ currentPage }} 页 / 共 {{ totalPages }} 页</span>
    </div>

    <!-- 加载状态 -->
    <div v-if="loading" class="loading-container">
      <div class="progress-info">
        <div v-if="downloadProgress < 100">
          下载进度: {{ downloadProgress }}%
          <div class="progress-bar">
            <div class="progress-fill" :style="{ width: downloadProgress + '%' }"></div>
          </div>
          <div>已下载: {{ loadedProgressText }}</div>
        </div>
        <div v-else>
          PDF处理中...
        </div>
      </div>
    </div>

    <!-- 错误信息 -->
    <div v-if="error" class="error-message">
      {{ error }}
    </div>

    <!-- PDF 渲染区域 -->
    <div ref="pdfContainer" class="pdf-container" :class="{ hidden: loading }">
      <iframe
          v-if="pdfUrl"
          :src="pdfUrl"
          width="100%"
          height="600px"
          style="border: none;"
          @load="onIframeLoad"
          @error="onIframeError"
      ></iframe>

      <div v-else-if="!loading" class="no-pdf-message">
        暂无PDF显示
      </div>
    </div>

    <!-- 调试信息 -->
    <div v-if="debugInfo" class="debug-info">
      {{ debugInfo }}
    </div>

    <!-- 下载链接 -->
    <div v-if="pdfUrl" style="margin-top: 10px;">
      <a :href="pdfUrl" download="document.pdf" style="color: green; font-weight: bold;">
        ↓ 下载PDF文件
      </a>
    </div>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  name: 'PDFViewer',
  data() {
    return {
      fileKey: 'pdf/2025/10/11/company-intro.pdf',
      currentPage: 1,
      totalPages: 0,
      loading: false,
      error: '',
      debugInfo: '',
      totalSize: 0,
      loadedSize: 0,
      pdfUrl: '',
      downloadProgress: 0,
      // 配置项
      chunkSize: 2 * 1024 * 1024, // 2MB 每块
      maxConcurrentDownloads: 3, // 最大并发下载数
    };
  },
  computed: {
    loadedProgressText() {
      if (this.totalSize === 0) return '';
      const loadedMB = (this.loadedSize / 1024 / 1024).toFixed(1);
      const totalMB = (this.totalSize / 1024 / 1024).toFixed(1);
      return `${loadedMB}MB / ${totalMB}MB`;
    }
  },
  methods: {
    async loadPDF() {
      await this.downloadAndRenderPDF();
    },

    async downloadAndFixPDF() {
      await this.downloadAndRenderPDF(true);
    },

    async downloadAndRenderPDF(attemptFix = false) {
      this.loading = true;
      this.error = '';
      this.downloadProgress = 0;
      this.pdfUrl = '';

      try {
        this.debugInfo = '开始加载PDF...';

        // 获取文件大小
        const fileSize = await this.getFileSize();
        this.totalSize = fileSize;
        this.debugInfo = `文件大小: ${(fileSize / 1024 / 1024).toFixed(1)}MB`;

        // 分块下载完整文件
        const fullPdfData = await this.downloadFileByChunks(fileSize);

        // 检查并修复PDF
        let processedData = fullPdfData;
        if (attemptFix) {
          processedData = await this.attemptFixPDF(fullPdfData);
        }

        // 使用 iframe 渲染
        await this.renderWithIframe(processedData);

        this.debugInfo = `PDF 加载完成，大小: ${(processedData.byteLength / 1024 / 1024).toFixed(1)}MB`;

      } catch (error) {
        this.error = `PDF 加载失败: ${error.message}`;
        console.error('PDF 加载失败:', error);
      } finally {
        this.loading = false;
      }
    },

    // 尝试修复PDF文件
    async attemptFixPDF(pdfData) {
      this.debugInfo = '尝试修复PDF文件...';

      const dataView = new DataView(pdfData);
      const dataArray = new Uint8Array(pdfData);

      // 检查文件头
      const header = String.fromCharCode(...dataArray.slice(0, 8));
      console.log('PDF文件头:', header);

      if (header.substring(0, 4) !== '%PDF') {
        throw new Error('无效的PDF文件头');
      }

      // 查找文件尾的xref表和trailer
      const trailerInfo = this.findTrailerAndXref(dataArray);
      console.log('Trailer信息:', trailerInfo);

      if (!trailerInfo.foundTrailer) {
        console.warn('未找到完整的trailer，尝试手动添加EOF');
        // 手动添加EOF标记
        return this.addManualEOF(dataArray);
      }

      return pdfData;
    },

    // 查找trailer和xref表
    findTrailerAndXref(dataArray) {
      const decoder = new TextDecoder('ascii');
      const dataString = decoder.decode(dataArray);

      // 从文件末尾开始查找
      const chunkSize = 1024;
      let foundTrailer = false;
      let foundStartXref = false;
      let xrefOffset = -1;

      // 检查最后几个chunk
      for (let i = 0; i < 5; i++) {
        const start = Math.max(0, dataArray.length - chunkSize * (i + 1));
        const end = dataArray.length - chunkSize * i;
        const chunk = dataArray.slice(start, end);
        const chunkString = decoder.decode(chunk);

        if (chunkString.includes('trailer')) {
          foundTrailer = true;
        }

        if (chunkString.includes('startxref')) {
          foundStartXref = true;
          // 提取xref偏移量
          const startxrefMatch = chunkString.match(/startxref\s+(\d+)/);
          if (startxrefMatch) {
            xrefOffset = parseInt(startxrefMatch[1]);
          }
        }

        if (chunkString.includes('%%EOF')) {
          console.log('找到EOF标记');
        }
      }

      return {
        foundTrailer,
        foundStartXref,
        xrefOffset
      };
    },

    // 手动添加EOF标记
    addManualEOF(dataArray) {
      this.debugInfo = '手动添加PDF结束标记...';

      // 创建新的ArrayBuffer，额外空间用于添加EOF
      const newBuffer = new ArrayBuffer(dataArray.length + 50);
      const newArray = new Uint8Array(newBuffer);

      // 复制原始数据
      newArray.set(dataArray, 0);

      // 添加基本的PDF结束结构
      const eofString = '\n\n%%EOF\n';
      const encoder = new TextEncoder();
      const eofBytes = encoder.encode(eofString);

      newArray.set(eofBytes, dataArray.length);

      console.log('已添加手动EOF标记');
      return newArray.buffer;
    },

    // 测试小文件下载
    async testSmallChunk() {
      this.loading = true;
      this.error = '';

      try {
        this.debugInfo = '测试小文件下载...';

        // 只下载前5MB
        const testSize = 5 * 1024 * 1024;
        const testData = await this.downloadChunk(0, testSize - 1);

        // 检查下载的数据
        await this.analyzePDFChunk(testData);

        this.debugInfo = '小文件测试完成';

      } catch (error) {
        this.error = `测试失败: ${error.message}`;
      } finally {
        this.loading = false;
      }
    },

    // 分析PDF数据块
    async analyzePDFChunk(pdfData) {
      const dataArray = new Uint8Array(pdfData);
      const decoder = new TextDecoder('ascii');

      // 检查文件头
      const header = String.fromCharCode(...dataArray.slice(0, 8));
      console.log('测试文件头:', header);

      // 检查文件内容
      const sampleSize = Math.min(1000, dataArray.length);
      const sampleStart = decoder.decode(dataArray.slice(0, sampleSize));
      const sampleEnd = decoder.decode(dataArray.slice(-sampleSize));

      console.log('文件开始样本:', sampleStart.substring(0, 200));
      console.log('文件结束样本:', sampleEnd.substring(Math.max(0, sampleEnd.length - 200)));

      // 检查关键标记
      const hasObj = sampleStart.includes('obj');
      const hasEndObj = sampleStart.includes('endobj');
      const hasXref = sampleEnd.includes('xref');
      const hasTrailer = sampleEnd.includes('trailer');
      const hasEOF = sampleEnd.includes('%%EOF');

      console.log('PDF结构检查:', {
        hasObj,
        hasEndObj,
        hasXref,
        hasTrailer,
        hasEOF
      });

      this.debugInfo = `PDF结构: 对象${hasObj ? '✓' : '✗'} XREF${hasXref ? '✓' : '✗'} Trailer${hasTrailer ? '✓' : '✗'} EOF${hasEOF ? '✓' : '✗'}`;
    },

    // 分块下载文件
    async downloadFileByChunks(totalSize) {
      const chunks = [];
      const chunkCount = Math.ceil(totalSize / this.chunkSize);

      console.log(`开始分块下载，总大小: ${(totalSize / 1024 / 1024).toFixed(1)}MB, 块数: ${chunkCount}`);

      // 创建所有下载任务
      const chunkPromises = [];
      for (let i = 0; i < chunkCount; i++) {
        const start = i * this.chunkSize;
        const end = Math.min(start + this.chunkSize - 1, totalSize - 1);

        chunkPromises.push(() => this.downloadChunkWithProgress(start, end, i, chunkCount));
      }

      // 并发下载（限制并发数）
      for (let i = 0; i < chunkPromises.length; i += this.maxConcurrentDownloads) {
        const batch = chunkPromises.slice(i, i + this.maxConcurrentDownloads);
        const batchResults = await Promise.all(batch.map(fn => fn()));
        chunks.push(...batchResults);

        console.log(`已完成 ${Math.min(i + this.maxConcurrentDownloads, chunkCount)}/${chunkCount} 块下载`);
      }

      // 合并所有块
      return this.mergeChunks(chunks);
    },

    // 下载单个块（带进度）
    async downloadChunkWithProgress(start, end, chunkIndex, totalChunks) {
      try {
        const response = await axios.get('http://10.0.10.215:9106/oss/api/api/file/chunk', {
          params: {
            fileKey: this.fileKey,
            start: start,
            end: end
          },
          responseType: 'arraybuffer',
          onDownloadProgress: (progressEvent) => {
            // 计算整体下载进度
            const chunkProgress = progressEvent.loaded ? (progressEvent.loaded / (end - start + 1)) * 100 : 0;
            const overallProgress = (chunkIndex / totalChunks) * 100 + (chunkProgress / totalChunks);
            this.downloadProgress = Math.min(100, Math.round(overallProgress));
          }
        });

        this.loadedSize = Math.max(this.loadedSize, end + 1);
        return response.data;
      } catch (error) {
        console.error(`下载块 ${start}-${end} 失败:`, error);
        throw error;
      }
    },

    // 下载单个块（无进度）
    async downloadChunk(start, end) {
      try {
        const response = await axios.get('http://10.0.10.215:9106/oss/api/api/file/chunk', {
          params: {
            fileKey: this.fileKey,
            start: start,
            end: end
          },
          responseType: 'arraybuffer'
        });

        return response.data;
      } catch (error) {
        console.error(`下载块 ${start}-${end} 失败:`, error);
        throw error;
      }
    },

    // 合并所有块
    mergeChunks(chunks) {
      const totalLength = chunks.reduce((total, chunk) => total + chunk.byteLength, 0);
      const result = new Uint8Array(totalLength);
      let offset = 0;

      chunks.forEach(chunk => {
        const chunkArray = new Uint8Array(chunk);
        result.set(chunkArray, offset);
        offset += chunkArray.length;
      });

      console.log('合并完成，总大小:', totalLength);
      return result;
    },

    // 使用 iframe 渲染
    async renderWithIframe(pdfData) {
      try {
        this.debugInfo = '使用 iframe 渲染 PDF...';

        // 创建 Blob 并生成 URL
        const blob = new Blob([pdfData], { type: 'application/pdf' });
        this.pdfUrl = URL.createObjectURL(blob);

        this.debugInfo = 'iframe PDF 渲染完成';
        this.currentPage = 1;
        this.totalPages = 1; // iframe 模式下我们不知道总页数

      } catch (error) {
        console.error('iframe 渲染失败:', error);
        throw error;
      }
    },

    // iframe 加载成功
    onIframeLoad() {
      console.log('iframe PDF 加载成功');
      this.debugInfo += ' | iframe 加载成功';
    },

    // iframe 加载失败
    onIframeError() {
      console.error('iframe PDF 加载失败');
      this.error = 'iframe 无法加载 PDF 文档';
    },

    // 获取文件大小
    async getFileSize() {
      try {
        const response = await axios.get('http://10.0.10.215:9106/oss/api/api/file/chunk', {
          params: {
            fileKey: this.fileKey,
            start: 0,
            end: 1024
          },
          responseType: 'arraybuffer'
        });

        // 尝试从响应头获取文件大小
        const contentRange = response.headers['content-range'];
        if (contentRange) {
          const match = contentRange.match(/\/(\d+)$/);
          if (match) {
            return parseInt(match[1]);
          }
        }

        // 使用默认值
        return 85 * 1024 * 1024;
      } catch (error) {
        console.error('获取文件大小失败，使用默认值');
        return 85 * 1024 * 1024;
      }
    },

    // 重置查看器
    resetViewer() {
      if (this.pdfUrl) {
        URL.revokeObjectURL(this.pdfUrl);
      }
      this.currentPage = 1;
      this.totalPages = 0;
      this.error = '';
      this.debugInfo = '';
      this.loadedSize = 0;
      this.totalSize = 0;
      this.pdfUrl = '';
      this.downloadProgress = 0;
    }
  },

  beforeUnmount() {
    this.resetViewer();
  }
};
</script>

<style scoped>
.pdf-viewer-container {
  font-family: Arial, sans-serif;
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
}

.control-panel {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 20px;
  padding: 15px;
  background: #f5f5f5;
  border-radius: 8px;
  flex-wrap: wrap;
}

.control-panel button {
  padding: 8px 16px;
  border: 1px solid #ddd;
  background: white;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.2s;
}

.control-panel button:hover:not(:disabled) {
  background: #e9e9e9;
}

.control-panel button:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.page-info {
  margin-left: auto;
  font-weight: bold;
  color: #333;
}

.loading-container {
  text-align: center;
  padding: 40px;
}

.progress-info {
  max-width: 400px;
  margin: 0 auto;
}

.progress-bar {
  width: 100%;
  height: 20px;
  background: #e0e0e0;
  border-radius: 10px;
  margin-top: 10px;
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  background: #4CAF50;
  transition: width 0.3s ease;
}

.error-message {
  background: #ffebee;
  color: #c62828;
  padding: 15px;
  border-radius: 4px;
  margin: 20px 0;
  border-left: 4px solid #c62828;
}

.pdf-container {
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 20px;
  background: white;
  min-height: 600px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.pdf-container.hidden {
  display: none;
}

.no-pdf-message {
  color: #666;
  font-style: italic;
  text-align: center;
  margin-top: 50px;
}

.debug-info {
  margin-top: 20px;
  padding: 10px;
  background: #e3f2fd;
  border-radius: 4px;
  font-size: 12px;
  color: #1565c0;
}
</style>