// auto-split module


async function ensureJsPdf() {
    function loadScript(url) {
        return new Promise((resolve, reject) => {
            const s = document.createElement('script');
            s.src = url;
            s.onload = resolve;
            s.onerror = reject;
            document.head.appendChild(s);
        });
    }
    async function tryLoad(urls) {
        for (const u of urls) {
            try {
                await loadScript(u);
            } catch (_) {}
            if (window.jspdf && window.jspdf.jsPDF) return true;
        }
        return !!(window.jspdf && window.jspdf.jsPDF);
    }

    // 1) jsPDF laden (lokal bevorzugt, dann CDN/Unpkg)
    if (!(window.jspdf && window.jspdf.jsPDF)) {
        await tryLoad([
            '/vendor/jspdf/jspdf.umd.min.js',
            'https://cdn.jsdelivr.net/npm/jspdf@2.5.1/dist/jspdf.umd.min.js',
            'https://unpkg.com/jspdf@2.5.1/dist/jspdf.umd.min.js'
        ]);
    }
    if (!(window.jspdf && window.jspdf.jsPDF)) return false;

    // 2) autotable nachladen, falls nicht vorhanden
    try {
        const test = new window.jspdf.jsPDF();
        if (typeof test.autoTable !== 'function') {
            await tryLoad([
                '/vendor/jspdf-autotable/jspdf.plugin.autotable.min.js',
                'https://cdn.jsdelivr.net/npm/jspdf-autotable@3.8.2/dist/jspdf.plugin.autotable.min.js',
                'https://unpkg.com/jspdf-autotable@3.8.2/dist/jspdf.plugin.autotable.min.js'
            ]);
        }
    } catch (_) {
        /* egal – PDF geht auch ohne autotable-Funktion (Fallback) */
    }

    return true;
}


async function generatePdfBlob(run) {
    // Lade jsPDF + AutoTable falls nötig (lokal → CDN/Unpkg). Fällt ansonsten sauber auf Text-Blob zurück.
    const pdfReady = await ensureJsPdf();
    if (!pdfReady) {
        const txt = 'QA Report\n' + JSON.stringify(run, null, 2);
        return new Blob([txt], {
            type: 'application/pdf'
        });
    }
    const {
        jsPDF
    } = window.jspdf;
    const doc = new jsPDF({
        orientation: 'landscape',
        unit: 'mm',
        format: 'a4',
        compress: true
    });
    // dynamic layout metrics for landscape A4
    const pageW = doc.internal.pageSize.getWidth();
    const pageH = doc.internal.pageSize.getHeight();
    const marginL = 14,
        marginR = 14;
    const xRight = pageW - marginR;
    const footerY = pageH - 13;

    // Farben (RGB, NICHT Hex!): "muted" war zuvor unsichtbar – jetzt korrekt
    const muted = [102, 102, 102];
    const headFill = [242, 242, 242];
    const ok = [0, 140, 0],
        fail = [200, 0, 0],
        skip = [160, 160, 0];

    // Optionales Logo oben rechts – proportional in 26×12 mm Box, rechtsbündig
    let logo = null;
    try {
        logo = await imgToDataURL('logo_light.png');
    } catch {}

    if (logo) {
        // 1) Bildabmessungen ermitteln (erst jsPDF, dann Fallback über <img>)
        let iw = 0,
            ih = 0;
        try {
            const props = doc.getImageProperties ? doc.getImageProperties(logo) : null;
            if (props) {
                iw = props.width || 0;
                ih = props.height || 0;
            }
        } catch {}
        if (!(iw && ih)) {
            await new Promise((resolve) => {
                const img = new Image();
                img.onload = () => {
                    iw = img.naturalWidth;
                    ih = img.naturalHeight;
                    resolve();
                };
                img.onerror = () => resolve();
                img.src = logo;
            });
        }

        // 2) Proportional in die Box einpassen
        const maxW = 26,
            maxH = 12;
        const ratio = (ih && iw) ? (ih / iw) : (10 / 26);
        let w = maxW,
            h = w * ratio;
        if (h > maxH) {
            h = maxH;
            w = h / ratio;
        }

        // 3) Rechtsbündig relativ zur Nutzkante (xRight)
        const x = xRight - w;
        const y = 7.8;

        try {
            doc.addImage(logo, 'PNG', x, y, w, h, undefined, 'FAST');
        } catch {}
    }


    // Titelzeile
    doc.setFont('helvetica', 'bold');
    doc.setFontSize(18);
    doc.setTextColor(0, 0, 0);
    doc.text('QA Report', 14, 16);
    if (logo) {
        try {
            // Optionales Logo oben rechts – proportional in 26×12 mm Box, rechtsbündig
            let logo = null;
            try {
                logo = await imgToDataURL('logo_light.png');
            } catch {}

            if (logo) {
                // Bildabmessungen: zuerst aus jsPDF, sonst via <img>-Fallback
                let iw = 0,
                    ih = 0;
                try {
                    const props = doc.getImageProperties ? doc.getImageProperties(logo) : null;
                    if (props) {
                        iw = props.width || 0;
                        ih = props.height || 0;
                    }
                } catch {}
                if (!(iw && ih)) {
                    await new Promise((resolve) => {
                        const img = new Image();
                        img.onload = () => {
                            iw = img.naturalWidth;
                            ih = img.naturalHeight;
                            resolve();
                        };
                        img.onerror = () => resolve();
                        img.src = logo;
                    });
                }

                // proportional in die Box einpassen
                const maxW = 26,
                    maxH = 12;
                const ratio = (ih && iw) ? (ih / iw) : (10 / 26);
                let w = maxW,
                    h = w * ratio;
                if (h > maxH) {
                    h = maxH;
                    w = h / ratio;
                }

                // rechtsbündig zur Nutzkante
                const x = xRight - w;
                const y = 7.8;

                try {
                    doc.addImage(logo, 'PNG', x, y, w, h, undefined, 'FAST');
                } catch {}
            }

        } catch {}
    }
    doc.setDrawColor(0, 0, 0);
    doc.setLineWidth(0.2);
    doc.line(marginL, 18, xRight, 18);

    // Metadaten mit Labels (sichtbar!)
    const meta = [
        ['Modul', sanitizeText(run.module)],
        ['Modul-Version', sanitizeText(run.module_version)],
        ['PBX-Version', sanitizeText(run.pbx_version)],
        ['OLM-Nummer', sanitizeText(run.olm_nummer)],
        ['Tester', sanitizeText(run.tester)],
        ['DocBee', sanitizeText(run.docbee_url || '-')],
    ];
    let y = 24;
    doc.setFontSize(10);
    meta.forEach(([k, v]) => {
        doc.setFont('helvetica', 'bold');
        doc.setTextColor(...muted);
        doc.text(k + ':', 14, y);
        doc.setFont('helvetica', 'normal');
        doc.setTextColor(0, 0, 0);
        doc.text(v || '—', 50, y);
        y += 6;
    });

    // Zeilen aus Steps bauen
    const rows = [];
    let i = 0,
        group = null;
    (run.steps || []).forEach(s => {
        if ((s.kind || 'step') === 'group') {
            group = sanitizeText(s.title);
            return;
        }
        i++;
        rows.push({
            nr: i,
            group: sanitizeText(group || '–'),
            id: sanitizeText(s.id),
            title: sanitizeText(s.title),
            expected: sanitizeText(s.expected),
            status: sanitizeText((s.status || '').toLowerCase()),
            comment: sanitizeText(s.comment),
        });
    });

    const body = rows.map(r => [r.nr, r.group, r.id, r.title, r.expected, r.status, r.comment]);
    const startY = Math.max(y + 4, 24);

    // Tabelle (autoTable)
    // @ts-ignore
    doc.autoTable({
        startY,
        tableWidth: pageW - (marginL + marginR),
        tableWidth: pageW - (marginL + marginR),
        head: [
            ['#', 'Gruppe', 'Step-ID', 'Titel', 'Erwartet', 'Status', 'Kommentar']
        ],
        body,
        styles: {
            font: 'helvetica',
            fontSize: 9,
            cellPadding: 2,
            overflow: 'linebreak',
            valign: 'top'
        },
        headStyles: {
            fillColor: headFill,
            textColor: [0, 0, 0],
            halign: 'left'
        },
        columnStyles: {
            0: {
                halign: 'right',
                cellWidth: 8
            },
            1: {
                cellWidth: 36
            },
            2: {
                cellWidth: 24
            },
            3: {
                cellWidth: 62
            },
            4: {
                cellWidth: 76
            },
            5: {
                cellWidth: 20,
                halign: 'left'
            },
            6: {
                cellWidth: 36
            }
        },
        didParseCell: (d) => {
            // Normalize every cell fragment to PDF-safe ASCII/Latin-1 and map arrows
            if (d && d.cell) {
                const arr = Array.isArray(d.cell.text) ? d.cell.text : [String(d.cell.text ?? '')];
                d.cell.text = arr.map(t => toPdfSafe(replaceSymbols(String(t))));
            }
            if (d.section === 'body') {
                // Status einfärben
                if (d.column.index === 5) {
                    const val = String(d.cell.raw || '').toLowerCase();
                    if (val === 'pass') d.cell.styles.textColor = ok;
                    else if (val === 'fail') d.cell.styles.textColor = fail;
                    else if (val === 'skip' || val === 'na') d.cell.styles.textColor = skip;
                }
                // "Erwartet" als Monospace + leicht grauer Hintergrund
                if (d.column.index === 4) {
                    d.cell.styles.font = 'courier';
                    d.cell.styles.fillColor = [250, 250, 250];
                }
            }
        },
        margin: {
            left: marginL,
            right: marginR
        },
        pageBreak: 'auto'
    });

    // Footer: Seitenzahlen & Zeitstempel
    const pageCount = doc.getNumberOfPages();
    const ts = new Date().toLocaleString();
    for (let p = 1; p <= pageCount; p++) {
        doc.setPage(p);
        doc.setFont('helvetica', 'normal');
        doc.setFontSize(8);
        doc.setTextColor(...muted);
        doc.text(`Seite ${p} / ${pageCount}`, xRight, footerY, {
            align: 'right'
        });
        doc.text(ts, marginL, footerY);
    }

    return doc.output('blob');
}


async function printPDF() {
    const run = collectRun();
    if (!run) return;
    if (!checkRequired(run)) return;
    renumberSteps();

    const logoDataUrl = await imgToDataURL('logo_light.png').catch(() => null);
    const esc = (s) => String(s ?? '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
    // ===== Funktion: badge (Arrow) =====
    // Zweck: siehe Inline-Kommentare im Funktionskörper.
    const badge = (status) => {
        const map = {
            pass: {
                txt: '✅ PASS',
                bg: '#DCFCE7',
                bd: '#22c55e'
            },
            fail: {
                txt: '❌ FAIL',
                bg: '#FEE2E2',
                bd: '#ef4444'
            },
            skip: {
                txt: '⏭️ SKIP',
                bg: '#E5E7EB',
                bd: '#6b7280'
            },
            blocked: {
                txt: '⛔ BLOCK',
                bg: '#FEF3C7',
                bd: '#f59e0b'
            },
            '': {
                txt: '—',
                bg: '#F3F4F6',
                bd: '#9ca3af'
            }
        };
        const m = map[status || ''] || map[''];
        return `<span style="display:inline-block;padding:2px 8px;border:1px solid ${m.bd};border-radius:999px;background:${m.bg};font-weight:600;font-size:12px">${m.txt}</span>`;
    };
    const counts = {
        pass: 0,
        fail: 0,
        skip: 0,
        blocked: 0
    };
    run.steps.forEach(s => {
        if ((s.kind || 'step') !== 'step') return;
        if (counts[s.status] !== undefined) counts[s.status]++;
    });
    const summary = `✅ ${counts.pass}  ❌ ${counts.fail}  ⏭️ ${counts.skip}  ⛔ ${counts.blocked}`;
    let rows = '';
    let seenGroup = false;
    for (const s of run.steps) {
        if ((s.kind || 'step') === 'group') {
            const t = esc(s.title || '');
            const cls = `group${seenGroup ? ' pagebreak' : ''}`;
            rows += `<tr class="${cls}"><td colspan="5"><strong>${t}</strong></td></tr>`;
            seenGroup = true;
            continue;
        }
        rows += `
      <tr>
        <td><strong>${esc(s.id)}</strong><div class="stitle">${esc(s.title)}${s.required?' 📌':''}</div></td>
        <td>${esc(s.expected)}</td>
        <td class="status">${badge(s.status||'')}</td>
        <td>${esc(s.comment)}</td>
        <td>${linkify(s.evidence)}</td>
      </tr>`;
    }

    const html = `<!doctype html>
<html><head><meta charset="utf-8"><title>QA Report</title>
<style>
  :root{ --text:#111827; --muted:#4b5563; --line:#d1d5db; --brandLight:#f3f4f6; }
  *{box-sizing:border-box}
  body{font-family:system-ui,Segoe UI,Roboto,Arial,sans-serif;margin:24px;color:var(--text); background:#fff}
  header{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}
  .brand{display:flex;gap:10px;align-items:center}
  .brand img{height:28px;width:auto;object-fit:contain}
  h1{margin:0;font-size:20px}
  .summary{margin:6px 0 0 0;font-weight:600}
  .meta{border:1px solid var(--line);border-radius:10px;padding:10px;background:#fff;margin:8px 0 14px 0}
  .meta ul{margin:0;padding-left:16px;color:var(--muted)}
  table{width:100%;border-collapse:collapse;margin-top:4px}
  thead th{background:var(--brandLight);text-align:left;border-bottom:1px solid var(--line);padding:8px}
  td{border-bottom:1px solid var(--line);padding:8px;vertical-align:top}
  td.status{white-space:nowrap}
  .stitle{color:var(--muted);font-size:12px;margin-top:2px}
  .legend{font-size:12px;color:var(--muted);margin-top:4px}
  tr.group td{ background:#e8f6fd; border-top:2px solid #bfe7fb; font-weight:700 }
  /* Seitenumbruch vor jeder Gruppe (außer der ersten) */
  @media print{
    tr.pagebreak{ break-before: page; page-break-before: always; }
  }

  a{color:#1d4ed8;text-decoration:underline}
  @media print{ body{margin:10mm} thead th, td{border-color:#000} }
</style>
</head>
<body>
  <header>
    <div class="brand">
      ${logoDataUrl ? `<img src="${logoDataUrl}" alt="Logo">` : ``}
      <h1>Testprotokoll</h1>
    </div>
    <div class="summary">${summary}</div>
  </header>

  <section class="meta">
    <ul>
      <li><strong>Modul:</strong> ${esc(run.module||'')}</li>
      <li><strong>Modul-Version:</strong> ${esc(run.module_version||'')}</li>
      <li><strong>PBX-Version:</strong> ${esc(run.pbx_version||'')}</li>
      <li><strong>DocBee:</strong> ${esc(run.docbee_url||'')}</li>
      <li><strong>Tester:</strong> ${esc(run.tester||'')}</li>
      <li><strong>Datum:</strong> ${new Date(run.ts).toLocaleString('de-DE')}</li>
    </ul>
    <div class="legend">Legende: ✅ Pass, ❌ Fail, ⏭️ Skip, ⛔ Blocked, 📌 Pflicht</div>
  </section>

  <table>
    <thead><tr><th>Schritt</th><th>Erwartung</th><th>Status</th><th>Kommentar</th><th>Evidenz</th></tr></thead>
    <tbody>${rows}</tbody>
  </table>

  <script>
    (function(){
      function go(){
        try{ window.focus(); }catch(e){}
        setTimeout(function(){ window.print(); }, 120);
      }
      if (document.readyState === 'complete') go();
      else window.addEventListener('load', go);
      window.onafterprint = function(){
        setTimeout(function(){ try{ window.close(); }catch(e){} }, 50);
      };
      setTimeout(function(){ try{ window.close(); }catch(e){} }, 3000);
    })();
  </script>
</body></html>`;

    const blob = new Blob([html], {
        type: 'text/html'
    });
    const url = URL.createObjectURL(blob);
    const w = window.open(url, '_blank', 'noopener');
    if (!w) {
        alert('Pop-up blockiert. Bitte Pop-ups erlauben.');
        URL.revokeObjectURL(url);
        return;
    }
    setTimeout(() => URL.revokeObjectURL(url), 10000);
}


function toPdfSafe(s) {
    return String(s).replace(/[^\x09\x0A\x0D\x20-\x7E\u00A0-\u00FF]/g, '?');
}


async function imgToDataURL(src) {
    return new Promise((resolve, reject) => {
        const img = new Image();
        img.crossOrigin = 'anonymous';
        img.onload = () => {
            const c = document.createElement('canvas');
            c.width = img.naturalWidth;
            c.height = img.naturalHeight;
            const ctx = c.getContext('2d');
            ctx.drawImage(img, 0, 0);
            resolve(c.toDataURL('image/png'));
        };
        img.onerror = reject;
        img.src = src;
    });
}

