// ==UserScript==
// @name         凭证自动合并下载
// @namespace    https://www.hujiuxi.top/
// @version      13.0
// @description  双重保障：首轮快速遍历，结束后自动回溯重试失败的行，最后统一合并
// @author       老九
// @match        http://10.65.248.23/*
// @require      https://unpkg.com/pdf-lib@1.17.1/dist/pdf-lib.min.js
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // ================= 配置区域 =================
    const CONFIG = {
        // 第一轮（正常）设置
        loadDelay: 4500,      // 基础等待时间
        retryMax: 3,          // 找不到PDF时的重试次数

        // 第二轮（重试/补录）设置
        retryLoadDelay: 6000, // 重试时多给点时间（6秒）
        retryMaxRound2: 6,    // 重试时的寻找次数增加

        // 通用
        processDelay: 1000,   // 行与行之间的缓冲
        leftMargin: '50px'
    };
    // ===========================================

    const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
    let lastBlobUrl = ""; // 全局变量，记录上一次的URL防止重复

    // --- 模拟真实鼠标点击 ---
    function simulateClick(element) {
        if (!element) return;
        ['mousedown', 'mouseup', 'click'].forEach(eventType => {
            element.dispatchEvent(new MouseEvent(eventType, {
                bubbles: true, cancelable: true, view: window
            }));
        });
    }

    // --- 寻找 PDF 阅读器窗口 ---
    function findPdfViewerWindow(win) {
        try {
            if (win.PDFViewerApplication && win.PDFViewerApplication.url) {
                return win;
            }
        } catch (e) {}
        try {
            const frames = win.frames;
            for (let i = 0; i < frames.length; i++) {
                const res = findPdfViewerWindow(frames[i]);
                if (res) return res;
            }
        } catch (e) {}
        return null;
    }

    // --- 核心：处理单行逻辑 ---
    // 返回值: true(成功), false(失败)
    async function processSingleRow(row, indexNum, mergedPdf, isRetryPhase = false) {
        const currentDelay = isRetryPhase ? CONFIG.retryLoadDelay : CONFIG.loadDelay;
        const currentMaxRetries = isRetryPhase ? CONFIG.retryMaxRound2 : CONFIG.retryMax;

        try {
            // 1. 点击
            const cell = row.querySelector('td[field="index"]');
            if(cell) {
                cell.scrollIntoView({block: "center", behavior: "auto"});
                simulateClick(cell.querySelector('div') || cell);
            }

            // 2. 等待加载
            await sleep(currentDelay);

            // 3. 寻找 PDF URL
            let viewerWindow = null;
            let foundUrl = null;

            // 循环寻找，确保 URL 变化了（即不是上一行的 URL）
            for(let k=0; k <= currentMaxRetries; k++){
                viewerWindow = findPdfViewerWindow(window.top);
                if(viewerWindow && viewerWindow.PDFViewerApplication.url) {
                    const tempUrl = viewerWindow.PDFViewerApplication.url;
                    // 如果 URL 有效且不等于上一次成功的 URL (防止卡在上一张)
                    if (tempUrl !== lastBlobUrl) {
                        foundUrl = tempUrl;
                        break;
                    }
                }
                if (k < currentMaxRetries) await sleep(1000);
            }

            if (foundUrl) {
                lastBlobUrl = foundUrl; // 更新全局记录

                // Fetch & Merge
                const res = await fetch(foundUrl);
                const arrayBuffer = await res.arrayBuffer();
                const { PDFDocument } = PDFLib;
                const srcDoc = await PDFDocument.load(arrayBuffer);
                const copiedPages = await mergedPdf.copyPages(srcDoc, srcDoc.getPageIndices());
                copiedPages.forEach((page) => mergedPdf.addPage(page));

                // 视觉反馈：成功变绿
                row.style.backgroundColor = '#dff0d8';
                console.log(`序号 ${indexNum}: ✅ 成功 (重试模式: ${isRetryPhase})`);
                return true;
            } else {
                throw new Error("超时未获取到新URL");
            }

        } catch (e) {
            console.warn(`序号 ${indexNum}: ❌ 失败 - ${e.message}`);
            // 视觉反馈：失败变红
            row.style.backgroundColor = '#f2dede';
            return false;
        }
    }

    // --- 寻找数据行 ---
    function findRowsRecursively(win) {
        try {
            const doc = win.document;
            const rows = doc.querySelectorAll('tr.datagrid-row');
            const validRows = Array.from(rows).filter(tr => {
                const indexCell = tr.querySelector('td[field="index"]');
                return indexCell && indexCell.innerText.trim() !== '';
            });
            if (validRows.length > 0) return validRows;
            const frames = win.frames;
            for (let i = 0; i < frames.length; i++) {
                const result = findRowsRecursively(frames[i]);
                if (result) return result;
            }
        } catch (e) {}
        return null;
    }

    // --- 主流程 ---
    async function startBatchProcess() {
        if (typeof PDFLib === 'undefined') { alert('❌ PDF库加载失败，请刷新。'); return; }

        const targetRows = findRowsRecursively(window.top);
        if (!targetRows || targetRows.length === 0) { alert('❌ 未找到数据。'); return; }

        if (!confirm(`🚀 V13.0 准备就绪\n共 ${targetRows.length} 条数据。\n\n策略说明：\n1. 第一轮快速遍历，失败则跳过。\n2. 第二轮会自动“回头”重试失败的项目。\n3. 注意：重试成功的凭证会排在文件末尾。\n\n是否开始？`)) return;

        // 初始化
        const { PDFDocument } = PDFLib;
        const mergedPdf = await PDFDocument.create();

        // 状态条
        const statusDiv = document.createElement('div');
        statusDiv.style.cssText = 'position:fixed; top:60px; left:50%; transform:translateX(-50%); background:rgba(0,0,0,0.85); color:#fff; padding:15px 30px; border-radius:30px; font-size:15px; z-index:9999999; text-align:center; box-shadow: 0 4px 15px rgba(0,0,0,0.3);';
        document.body.appendChild(statusDiv);

        let successCount = 0;
        let failedRows = []; // 存储第一轮失败的行对象

        // === 第一轮：正常遍历 ===
        for (let i = 0; i < targetRows.length; i++) {
            const row = targetRows[i];
            const indexNum = row.querySelector('td[field="index"]').innerText.trim();

            statusDiv.innerHTML = `🌟 <b>第 1 轮</b>: ${i + 1}/${targetRows.length} (序号: ${indexNum})<br><span style="font-size:12px;color:#ccc">成功: ${successCount} | 暂败: ${failedRows.length}</span>`;

            const success = await processSingleRow(row, indexNum, mergedPdf, false);

            if (success) {
                successCount++;
            } else {
                failedRows.push({ row: row, index: indexNum });
            }

            await sleep(CONFIG.processDelay);
        }

        // === 第二轮：重试失败项 ===
        if (failedRows.length > 0) {
            statusDiv.style.backgroundColor = "rgba(200, 100, 0, 0.9)"; // 变橙色提示

            for (let j = 0; j < failedRows.length; j++) {
                const item = failedRows[j];
                statusDiv.innerHTML = `🔥 <b>第 2 轮补录</b>: ${j + 1}/${failedRows.length}<br>正在重试序号: <b>${item.index}</b>`;

                // 这里调用时，传入 isRetryPhase = true
                const success = await processSingleRow(item.row, item.index, mergedPdf, true);

                if (success) {
                    successCount++;
                    // 从失败名单里仅仅是为了计数，不需要实际移除，因为循环已经定好了
                }
            }
        }

        // === 最终保存 ===
        statusDiv.innerHTML = `正在生成最终 PDF...`;
        statusDiv.style.backgroundColor = "rgba(0, 150, 0, 0.9)";

        try {
            const finalPdfBytes = await mergedPdf.save();
            const blob = new Blob([finalPdfBytes], { type: 'application/pdf' });
            const link = document.createElement('a');
            link.href = URL.createObjectURL(blob);
            const dateStr = new Date().toISOString().slice(0,10).replace(/-/g,"");
            link.download = `财政凭证合并版_${dateStr}_(总${successCount}张).pdf`;
            link.click();

            // 最终报告
            const finalFailedCount = failedRows.length - (successCount - (targetRows.length - failedRows.length));
            // 上面那个公式太绕了，其实就是 总数 - 成功数
            const realFailed = targetRows.length - successCount;

            if (realFailed > 0) {
                alert(`⚠️ 处理完成，但仍有 ${realFailed} 条彻底失败。\n请检查红色标记的行。`);
            } else {
                statusDiv.innerHTML = "🎉 完美！全部下载合并成功！";
                setTimeout(() => document.body.removeChild(statusDiv), 3000);
            }

        } catch (e) {
            alert("保存 PDF 出错: " + e.message);
        }
    }

    function injectButton() {
        const topNav = document.getElementById('topnav');
        if (!topNav || document.getElementById('my-merge-btn')) return;
        const spans = topNav.querySelectorAll('span');
        let targetSpan = null;
        for (let i = 0; i < spans.length; i++) {
            if (spans[i].innerText && spans[i].innerText.includes('已登记')) {
                targetSpan = spans[i]; break;
            }
        }
        if (!targetSpan) return;

        const btn = document.createElement('span');
        btn.id = 'my-merge-btn';
        btn.innerText = '自动合并';
        btn.style.cssText = `display: inline-block; margin-left: ${CONFIG.leftMargin}; padding: 5px 15px; background-color: #6610f2; color: white; border-radius: 4px; cursor: pointer; font-size: 14px; font-weight: bold; vertical-align: middle; line-height: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);`;
        btn.onclick = function(e) { e.stopPropagation(); startBatchProcess(); };
        if (targetSpan.parentNode) targetSpan.parentNode.insertBefore(btn, targetSpan.nextSibling);
    }

    window.addEventListener('load', injectButton);
    setInterval(injectButton, 1000);
})();