// ══════════════════════════════════════════════════════════════════════════════
// ndfPdfGenerator.js  — v5  (pdfkit pur, support proratisation repas)
// ══════════════════════════════════════════════════════════════════════════════

import PDFDocument from 'pdfkit';

const C = {
    blue: '#1B4F8A', header: '#2563EB',
    totalBg: '#DBEAFE', altRow: '#EFF6FF',
    amountBg: '#EEF2FF', greenBg: '#F0FDF4',
    greenText: '#15803D', headerRow: '#E2E8F0',
    border: '#CBD5E1', dark: '#0F172A',
    grey: '#64748B', light: '#94A3B8',
    white: '#FFFFFF',
    collabBg: '#F0FDF4', collabBorder: '#A7F3D0', collabText: '#059669',
    validBg: '#EEF2FF', validBorder: '#C7D2FE', validText: '#4F46E5',
    refusBg: '#FEF2F2', refusBorder: '#FCA5A5', refusText: '#DC2626',
    waitBg: '#F8FAFC', waitBorder: '#E2E8F0',
    kmBg: '#F5F3FF', kmBorder: '#DDD6FE', kmText: '#7C3AED', kmTotalBg: '#EDE9FE',
    // ✅ Nouveaux — lignes proratisées
    prorataBg: '#FFFBEB', prorataText: '#D97706', prorataBorder: '#FDE68A',
};

const COLS = [
    { key: 'num', label: 'N°pièce', w: 34, align: 'center' },
    { key: 'date', label: 'Date', w: 58, align: 'left' },
    { key: 'nature', label: 'Nature', w: 70, align: 'left' },
    { key: 'lib', label: 'Libellé', w: 140, align: 'left' },
    { key: 'km', label: 'Km', w: 36, align: 'right' },
    { key: 'tarifKm', label: 'Tarif €/km', w: 46, align: 'right' },
    { key: 'sousKm', label: 'S/Total Km', w: 50, align: 'right' },
    { key: 'ttc', label: 'TTC', w: 50, align: 'right' },
    { key: 'tva21', label: 'TVA 2,1%', w: 46, align: 'right' },
    { key: 'tva55', label: 'TVA 5,5%', w: 46, align: 'right' },
    { key: 'tva10', label: 'TVA 10%', w: 46, align: 'right' },
    { key: 'tva20', label: 'TVA 20%', w: 46, align: 'right' },
    { key: 'ht', label: 'HT', w: 50, align: 'right' },
];

const KM_COLS = ['km', 'tarifKm', 'sousKm'];

const MARGIN = 30;
const ROW_H = 16;
const HEAD_H = 20;
const PAGE_W = 841.89;
const PAGE_H = 595.28;

// ─────────────────────────────────────────────────────────────────────────────
// HELPERS
// ─────────────────────────────────────────────────────────────────────────────
const f2 = v => (parseFloat(v) || 0).toFixed(2);
const f3 = v => (parseFloat(v) || 0).toFixed(3);

function fmtDate(s) {
    if (!s) return '';
    try {
        const d = new Date(s);
        if (isNaN(d)) return String(s).slice(0, 10);
        return `${String(d.getDate()).padStart(2, '0')}/${String(d.getMonth() + 1).padStart(2, '0')}/${d.getFullYear()}`;
    } catch { return ''; }
}

function fmtDateTime(s) {
    if (!s) return '';
    try {
        const d = new Date(s);
        if (isNaN(d)) return String(s).slice(0, 16);
        return d.toLocaleString('fr-FR', {
            timeZone: 'Europe/Paris', day: '2-digit', month: '2-digit',
            year: 'numeric', hour: '2-digit', minute: '2-digit',
        });
    } catch { return ''; }
}

function drawRect(doc, x, y, w, h, fill, stroke = null, lw = 0.3) {
    doc.save();
    if (stroke) doc.lineWidth(lw).rect(x, y, w, h).fillAndStroke(fill, stroke);
    else doc.rect(x, y, w, h).fill(fill);
    doc.restore();
}

function drawCellText(doc, text, x, y, w, h, font, size, color, align, padX = 3) {
    text = String(text ?? '');
    const maxW = w - padX * 2;
    doc.save().font(font).fontSize(size).fillColor(color);
    while (text.length > 1 && doc.widthOfString(text) > maxW) text = text.slice(0, -1);
    const ty = y + h * 0.28;
    if (align === 'right') doc.text(text, x + padX, ty, { width: maxW, align: 'right', lineBreak: false });
    else if (align === 'center') doc.text(text, x + padX, ty, { width: maxW, align: 'center', lineBreak: false });
    else doc.text(text, x + padX, ty, { width: maxW, align: 'left', lineBreak: false });
    doc.restore();
}

function drawVLine(doc, x, y1, y2) {
    doc.save().strokeColor(C.border).lineWidth(0.4).moveTo(x, y1).lineTo(x, y2).stroke().restore();
}
function drawHLine(doc, x1, x2, y) {
    doc.save().strokeColor(C.border).lineWidth(0.3).moveTo(x1, y).lineTo(x2, y).stroke().restore();
}

// ─────────────────────────────────────────────────────────────────────────────
// BARÈME KM fiscal (miroir de server.js)
// ─────────────────────────────────────────────────────────────────────────────
const BAREME_KM = {
    3: { t1: 0.529, t2_a: 0.316, t2_b: 1061, t3: 0.369 },
    4: { t1: 0.606, t2_a: 0.340, t2_b: 1330, t3: 0.408 },
    5: { t1: 0.636, t2_a: 0.356, t2_b: 1391, t3: 0.427 },
    6: { t1: 0.665, t2_a: 0.374, t2_b: 1457, t3: 0.448 },
    7: { t1: 0.697, t2_a: 0.394, t2_b: 1512, t3: 0.470 },
};

function getIndemniteKm(kmTotal, chevaux) {
    const cv = Math.min(Math.max(parseInt(chevaux) || 7, 3), 7);
    const b = BAREME_KM[cv];
    if (!b || kmTotal <= 0) return 0;
    if (kmTotal <= 5000) return parseFloat((kmTotal * b.t1).toFixed(2));
    if (kmTotal <= 20000) return parseFloat((kmTotal * b.t2_a + b.t2_b).toFixed(2));
    return parseFloat((kmTotal * b.t3).toFixed(2));
}

// ─────────────────────────────────────────────────────────────────────────────
// preparerLignesPDF — v5 : gère montantAjuste + barème CV fiscal
// ─────────────────────────────────────────────────────────────────────────────
export function preparerLignesPDF(lignesParsed, tarifKm = 0.697) {
    console.log('🔍 preparerLignesPDF reçoit:', JSON.stringify(lignesParsed, null, 2));

    return (lignesParsed || []).map((l, idx) => {
        const isKm = (l.categorie || '').toLowerCase().includes('kilom');
        const km   = parseFloat(l.km) || 0;
        const cv   = parseInt(l.chevaux) || 7;

        const indemniteKm    = isKm ? getIndemniteKm(km, cv) : 0;
        const tarifKmAffiche = isKm ? (km > 0 ? parseFloat((indemniteKm / km).toFixed(3)) : tarifKm) : 0;

        const montantAjuste   = l.montantAjuste === true;
        const montantOriginal = montantAjuste
            ? (parseFloat(l.montantOriginal) || 0)
            : 0;

        // ✅ Toutes les variables avec let
        let ttc = 0, tva21 = 0, tva55 = 0, tva10 = 0, tva20 = 0, ht = 0;

        if (!isKm) {
            if (montantAjuste) {
                // ✅ Ligne proratisée — recalcul depuis montant retenu
                ttc = parseFloat(l.montant) || 0;
                const taux = parseFloat(l.tauxTVA) || 0;
                if (taux > 0 && ttc > 0) {
                    ht = parseFloat((ttc / (1 + taux / 100)).toFixed(2));
                    const tvaM = parseFloat((ttc - ht).toFixed(2));
                    if      (Math.abs(taux -  2.1) < 0.01) tva21 = tvaM;
                    else if (Math.abs(taux -  5.5) < 0.01) tva55 = tvaM;
                    else if (Math.abs(taux - 10  ) < 0.01) tva10 = tvaM;
                    else if (Math.abs(taux - 20  ) < 0.01) tva20 = tvaM;
                } else {
                    ht = ttc;
                }
            } else if (Array.isArray(l.tvaItems) && l.tvaItems.length > 0) {
                // ✅ Multi-TVA normal
                for (const item of l.tvaItems) {
                    const itemTTC = parseFloat(item.montantTTC) || 0;
                    const itemHT  = parseFloat(item.montantHT)  || 0;
                    const itemTau = parseFloat(item.taux)        || 0;
                    ttc += itemTTC;
                    ht  += itemHT;
                    const tvaM = parseFloat((itemTTC - itemHT).toFixed(2));
                    if      (Math.abs(itemTau -  2.1) < 0.01) tva21 += tvaM;
                    else if (Math.abs(itemTau -  5.5) < 0.01) tva55 += tvaM;
                    else if (Math.abs(itemTau - 10  ) < 0.01) tva10 += tvaM;
                    else if (Math.abs(itemTau - 20  ) < 0.01) tva20 += tvaM;
                }
                ttc = parseFloat(ttc.toFixed(2));
                ht  = parseFloat(ht.toFixed(2));
            } else {
                // ✅ Mono-TVA simple
                ttc = parseFloat(l.montant) || 0;
                const taux = parseFloat(l.tauxTVA) || 0;
                if (taux > 0 && ttc > 0) {
                    ht = parseFloat((ttc / (1 + taux / 100)).toFixed(2));
                    const tvaM = parseFloat((ttc - ht).toFixed(2));
                    if      (Math.abs(taux -  2.1) < 0.01) tva21 = tvaM;
                    else if (Math.abs(taux -  5.5) < 0.01) tva55 = tvaM;
                    else if (Math.abs(taux - 10  ) < 0.01) tva10 = tvaM;
                    else if (Math.abs(taux - 20  ) < 0.01) tva20 = tvaM;
                } else {
                    ht = ttc;
                }
            }
        }

        return {
            numPiece:    idx + 1,
            date:        l.date,
            nature:      l.categorie || '',
            libelle:     l.libelle   || '',
            km:          isKm ? km : 0,
            tarifKmVal:  isKm ? tarifKmAffiche : 0,
            montantTTC:  isKm ? 0 : ttc,
            tva21, tva55, tva10, tva20,
            montantHT:   isKm ? 0 : ht,
            indemniteKm,
            montantAjuste,
            montantOriginal,
        };
    });
}
// ─────────────────────────────────────────────────────────────────────────────
// generateFicheSignee
// ─────────────────────────────────────────────────────────────────────────────
export async function generateFicheSignee(note, signatures = []) {
    const tarifKm = parseFloat(note.tarifKm) || 0.697;

    let lignesPDF = [];
    if (note.lignesJson) {
        try {
            const parsed = typeof note.lignesJson === 'string'
                ? JSON.parse(note.lignesJson) : note.lignesJson;
            lignesPDF = preparerLignesPDF(parsed, tarifKm);
        } catch (e) { console.error('ndfPdfGenerator — Parse lignesJson:', e.message); }
    } else if (note.lignes && Array.isArray(note.lignes)) {
        lignesPDF = preparerLignesPDF(note.lignes, tarifKm);
    } else {
        // Fallback ligne unique (rétrocompat)
        const isKm = !!(note.km && parseFloat(note.km) > 0);
        const km = isKm ? parseFloat(note.km) : 0;
        const cv = parseInt(note.chevaux) || 7;
        const indem = isKm ? getIndemniteKm(km, cv) : 0;
        lignesPDF = [{
            numPiece: 1, date: note.date, nature: note.categorie || '', libelle: note.libelle || '',
            km: isKm ? km : 0,
            tarifKmVal: isKm && km > 0 ? parseFloat((indem / km).toFixed(3)) : tarifKm,
            montantTTC: isKm ? 0 : parseFloat(note.montant || 0),
            tva21: 0, tva55: 0, tva10: 0, tva20: 0,
            montantHT: isKm ? 0 : parseFloat(note.montantHT || note.montant || 0),
            indemniteKm: indem,
            montantAjuste: false, montantOriginal: 0,
        }];
    }

    let mois = note.mois || '';
    if (!mois && note.date) {
        const d = new Date(note.date);
        const m = d.toLocaleDateString('fr-FR', { month: 'long', year: 'numeric' });
        mois = m.charAt(0).toUpperCase() + m.slice(1);
    }

    return _buildPDF({
        reference: note.reference || '',
        nomPrenom: note.nomPrenom || note.collaborateur || '',
        mois,
        departement: note.departement || '',
        lignes: lignesPDF,
        tarifKm,
        signatures,
        statut: note.statut || 'enattente',
    });
}

// ─────────────────────────────────────────────────────────────────────────────
// _buildPDF
// ─────────────────────────────────────────────────────────────────────────────
function _buildPDF({ reference, nomPrenom, mois, departement, lignes, tarifKm, signatures }) {
    return new Promise((resolve, reject) => {
        const doc = new PDFDocument({
            size: 'A4', layout: 'landscape', margin: 0,
            info: {
                Title: `Note de Frais ${reference}`,
                Author: `ENSUP — ${nomPrenom}`,
                Subject: `NDF ${reference}`,
                Creator: 'NDF ENSUP v5',
            },
        });

        const chunks = [];
        doc.on('data', c => chunks.push(c));
        doc.on('end', () => resolve(Buffer.concat(chunks)));
        doc.on('error', e => reject(e));

        // Positions X colonnes
        const colX = {};
        let cx = MARGIN;
        for (const col of COLS) { colX[col.key] = cx; cx += col.w; }
        const tableW = cx - MARGIN;

        // ── Bandeau titre ────────────────────────────────────────────
        const bandY = 44;
        drawRect(doc, MARGIN, bandY, tableW, 18, C.header);
        doc.font('Helvetica-Bold').fontSize(11).fillColor(C.white)
            .text('NOTE DE FRAIS', MARGIN, bandY + 3.5, { width: tableW, align: 'center', lineBreak: false });

        // ── Infos collaborateur ──────────────────────────────────────
        const infoY = bandY + 23;
        doc.font('Helvetica-Bold').fontSize(9).fillColor(C.dark)
            .text(`NOM : ${nomPrenom}`, MARGIN, infoY, { lineBreak: false });
        if (departement)
            doc.font('Helvetica').fontSize(8).fillColor(C.grey)
                .text(`Service : ${departement}`, MARGIN + 200, infoY, { lineBreak: false });
        doc.font('Helvetica').fontSize(8).fillColor(C.grey)
            .text('Repas, déplacement, autres', MARGIN + 380, infoY, { lineBreak: false });
        doc.font('Helvetica-Bold').fontSize(9).fillColor(C.dark)
            .text(`Mois : ${mois}`, MARGIN, infoY + 13, { lineBreak: false });

        // ── En-tête colonnes ─────────────────────────────────────────
        const tableTop = infoY + 27;
        drawRect(doc, MARGIN, tableTop, tableW, HEAD_H, C.headerRow, C.border, 0.5);
        for (const key of KM_COLS)
            drawRect(doc, colX[key], tableTop, COLS.find(c => c.key === key).w, HEAD_H, C.kmBg);

        for (const col of COLS) {
            const isKmCol = KM_COLS.includes(col.key);
            drawCellText(doc, col.label, colX[col.key], tableTop, col.w, HEAD_H,
                'Helvetica-Bold', isKmCol ? 6.5 : 7,
                isKmCol ? C.kmText : C.dark, col.align);
            drawVLine(doc, colX[col.key], tableTop, tableTop + HEAD_H);
        }
        drawVLine(doc, MARGIN + tableW, tableTop, tableTop + HEAD_H);
        drawHLine(doc, MARGIN, MARGIN + tableW, tableTop);
        drawHLine(doc, MARGIN, MARGIN + tableW, tableTop + HEAD_H);

        // ── Lignes données ───────────────────────────────────────────
        const MIN_ROWS = 18;
        const totalRows = Math.max(MIN_ROWS, lignes.length);
        let y = tableTop + HEAD_H;
        let totKm = 0, totTTC = 0, totT21 = 0, totT55 = 0, totT10 = 0, totT20 = 0, totHT = 0, totSousKm = 0;

        for (let i = 0; i < totalRows; i++) {
            const lig = lignes[i] || null;
            const isProrata = lig?.montantAjuste === true;

            // Fond : prorata = amber pâle, sinon alternance
            const rowBg = isProrata
                ? C.prorataBg
                : (i % 2 === 1 ? C.altRow : C.white);
            drawRect(doc, MARGIN, y, tableW, ROW_H, rowBg);

            // Fond violet km
            for (const key of KM_COLS) {
                const col = COLS.find(c => c.key === key);
                drawRect(doc, colX[key], y, col.w, ROW_H,
                    i % 2 === 1 ? '#F3F0FF' : '#FAF8FF');
            }

            if (lig) {
                const km = parseFloat(lig.km) || 0;
                const tarif = parseFloat(lig.tarifKmVal) || 0;
                const sousKm = parseFloat(lig.indemniteKm) || 0;
                const ttc = parseFloat(lig.montantTTC) || 0;
                const t21 = parseFloat(lig.tva21) || 0;
                const t55 = parseFloat(lig.tva55) || 0;
                const t10 = parseFloat(lig.tva10) || 0;
                const t20 = parseFloat(lig.tva20) || 0;
                const ht = parseFloat(lig.montantHT) || 0;

                totKm += km;
                totTTC += ttc;
                totT21 += t21; totT55 += t55; totT10 += t10; totT20 += t20;
                totHT += ht;
                totSousKm += sousKm;

                // ✅ Libellé enrichi si proratisé : afficher montant original barré
             let libelleAffiche = lig.libelle || '';

                const r = {
                    num: String(lig.numPiece || i + 1),
                    date: fmtDate(lig.date),
                    nature: lig.nature || '',
                    lib: libelleAffiche,
                    km: km > 0 ? f2(km) : '',
                    tarifKm: tarif > 0 ? f3(tarif) : '',
                    sousKm: sousKm > 0 ? f2(sousKm) : '',
                    ttc: f2(ttc),
                    tva21: f2(t21), tva55: f2(t55),
                    tva10: f2(t10), tva20: f2(t20),
                    ht: f2(ht),
                };

                for (const col of COLS) {
                    const isKmCol = KM_COLS.includes(col.key);
                    // ✅ Couleur ambre pour montants proratisés
                    const textColor = isProrata && ['ttc', 'ht'].includes(col.key)
                        ? C.prorataText
                        : isKmCol ? C.kmText : C.dark;

                    drawCellText(doc, r[col.key],
                        colX[col.key], y, col.w, ROW_H,
                        'Helvetica', 7, textColor, col.align);
                }

                // ✅ Indicateur proratisation — petit triangle orange en coin haut-gauche
                if (isProrata) {
                    doc.save()
                        .fillColor(C.prorataText)
                        .moveTo(MARGIN, y)
                        .lineTo(MARGIN + 6, y)
                        .lineTo(MARGIN, y + 6)
                        .fill()
                        .restore();
                }

            } else {
                // Ligne vide — zéros en gris
                for (const col of COLS) {
                    if (['ttc', 'tva21', 'tva55', 'tva10', 'tva20', 'ht'].includes(col.key))
                        drawCellText(doc, '0.00', colX[col.key], y, col.w, ROW_H,
                            'Helvetica', 7, C.border, 'right');
                }
            }

            drawHLine(doc, MARGIN, MARGIN + tableW, y + ROW_H);
            for (const col of COLS) drawVLine(doc, colX[col.key], y, y + ROW_H);
            drawVLine(doc, MARGIN + tableW, y, y + ROW_H);
            y += ROW_H;
        }

        // ── Ligne Total ──────────────────────────────────────────────
        const totalY = y;
        drawRect(doc, MARGIN, totalY, tableW, ROW_H + 2, C.totalBg, C.border, 0.5);
        for (const key of KM_COLS) {
            const col = COLS.find(c => c.key === key);
            drawRect(doc, colX[key], totalY, col.w, ROW_H + 2, C.kmTotalBg);
        }

        doc.font('Helvetica-Bold').fontSize(8).fillColor(C.dark)
            .text('Total', MARGIN + 3, totalY + 4, { lineBreak: false });

        const totMap = {
            km: totKm > 0 ? f2(totKm) : '',
            tarifKm: '',
            sousKm: totSousKm > 0 ? f2(totSousKm) : '',
            ttc: f2(totTTC),
            tva21: f2(totT21), tva55: f2(totT55),
            tva10: f2(totT10), tva20: f2(totT20),
            ht: f2(totHT),
        };

        for (const col of COLS) {
            if (!totMap[col.key] && totMap[col.key] !== '0.00') continue;
            if (totMap[col.key] === '') continue;
            const isKmCol = KM_COLS.includes(col.key);
            drawCellText(doc, totMap[col.key],
                colX[col.key], totalY, col.w, ROW_H + 2,
                'Helvetica-Bold', 8, isKmCol ? C.kmText : C.dark, 'right');
        }

        // ── Zone bas ─────────────────────────────────────────────────
        const footY = totalY + ROW_H + 12;
        const montantR = parseFloat((totTTC + totSousKm).toFixed(2));
        const bw = 64;

        // ✅ Légende proratisation si au moins une ligne ajustée
        const hasProrata = lignes.some(l => l?.montantAjuste === true);
        if (hasProrata) {
            const nbProrata = lignes.filter(l => l?.montantAjuste === true).length;
            const montantOriginalTotal = lignes
                .filter(l => l?.montantAjuste === true)
                .reduce((s, l) => s + (parseFloat(l.montantOriginal) || 0), 0);
            const economie = parseFloat((montantOriginalTotal - lignes
                .filter(l => l?.montantAjuste === true)
                .reduce((s, l) => s + (parseFloat(l.montantTTC) || 0), 0)).toFixed(2));

            drawRect(doc, MARGIN, footY - 1, tableW * 0.6, 14, C.prorataBg, C.prorataBorder, 0.5);
            doc.font('Helvetica').fontSize(6.5).fillColor(C.prorataText)
                        .text(
                            `⚠ ${nbProrata} ligne${nbProrata > 1 ? 's' : ''} de repas plafonnée${nbProrata > 1 ? 's' : ''} à 25 €/pers. par la Finance — ` +
                            `Montant soumis : ${f2(montantOriginalTotal)} € → Retenu : ${f2(montantOriginalTotal - economie)} €`,
                            MARGIN + 3, footY + 1.5, { lineBreak: false }
                        );
        }

        const labelOffsetY = hasProrata ? 16 : 0;

        doc.font('Helvetica-Bold').fontSize(9).fillColor(C.dark)
            .text('Montant total à rembourser', MARGIN, footY + 4 + labelOffsetY, { lineBreak: false });
        drawRect(doc, MARGIN + 180, footY + labelOffsetY, bw + 10, 18, C.amountBg, C.border, 0.5);
        doc.font('Helvetica-Bold').fontSize(11).fillColor(C.blue)
            .text(f2(montantR) + ' €',
                MARGIN + 182, footY + 3.5 + labelOffsetY,
                { width: bw + 6, align: 'right', lineBreak: false });

        doc.font('Helvetica').fontSize(6.5).fillColor(C.grey)
            .text(
                `Tarif km appliqué : ${tarifKm.toFixed(3)} €/km  —  Sous-total km : ${f2(totSousKm)} €  —  TTC hors km : ${f2(totTTC)} €`,
                MARGIN, footY + 24 + labelOffsetY, { lineBreak: false }
            );

        // ── Signatures ────────────────────────────────────────────────
        const sigStartX = MARGIN + 310;
        const sigW = (tableW - 313) / 2 - 4;
        const sigH = 52;
        const sigY = footY - 2 + labelOffsetY;

        const sigCollab = signatures.find(s => s.niveau === 'COLLAB');
        const sigManager = signatures.find(s => ['N1', 'N2', 'VERIF'].includes(s.niveau));

        // ✅ Afficher toutes les signatures (jusqu'à 3 : COLLAB, N1/N2, VERIF)
        const sigsAffichees = ['COLLAB', 'N1', 'N2', 'VERIF']
            .map(niv => signatures.find(s => s.niveau === niv))
            .filter(Boolean)
            .slice(0, 3);

        const nbSigs = sigsAffichees.length;
        const sigWAdj = nbSigs > 2 ? (tableW - 313) / 3 - 4 : sigW;

        sigsAffichees.forEach((sig, idx) => {
            const label = sig.niveau === 'COLLAB' ? 'Date et signature Collaborateur'
                : sig.niveau === 'VERIF' ? 'Vérification Finance'
                    : `Date et signature Validateur ${sig.niveau}`;
            _drawSigBox(doc, sig,
                sigStartX + idx * (sigWAdj + 4),
                sigY, sigWAdj, sigH,
                label,
                sig.niveau !== 'COLLAB');
        });

        // ── Pied de page ──────────────────────────────────────────────
        doc.font('Helvetica').fontSize(6).fillColor(C.light)
            .text(
                `Réf. ${reference}  —  Généré le ${new Date().toLocaleDateString('fr-FR')}  —  NDF ENSUP Groupe  —  Document électronique`,
                MARGIN, PAGE_H - 13, { width: tableW, align: 'center', lineBreak: false }
            );

        doc.end();
    });
}

// ─────────────────────────────────────────────────────────────────────────────
// _drawSigBox
// ─────────────────────────────────────────────────────────────────────────────
function _drawSigBox(doc, sig, x, y, w, h, label, isManager) {
    let bg, border, accent, icon;

    if (sig) {
        const a = sig.action || '';
        if (a === 'refuser' || a === 'refuse') {
            bg = C.refusBg; border = C.refusBorder; accent = C.refusText; icon = '✗ REFUSÉ';
        } else if (sig.niveau === 'VERIF') {
            bg = '#FEFCE8'; border = '#FDE047'; accent = '#CA8A04'; icon = '✓ VÉRIFIÉ Finance';
        } else if (isManager) {
            bg = C.validBg; border = C.validBorder; accent = C.validText; icon = '✓ VALIDÉ';
        } else {
            bg = C.collabBg; border = C.collabBorder; accent = C.collabText; icon = '✓ SOUMIS';
        }
    } else {
        bg = C.waitBg; border = C.waitBorder; accent = C.grey; icon = null;
    }

    drawRect(doc, x, y, w, h, bg, border, 1);

    doc.font('Helvetica-Bold').fontSize(6.5).fillColor(C.grey)
        .text(label, x + 4, y + 4, { width: w - 8, lineBreak: false });

    if (sig) {
        let nom = String(sig.nomPrenom || '');
        const ds = fmtDateTime(sig.date);
        const comment = String(sig.commentaire || '');

        doc.font('Helvetica-Bold').fontSize(8).fillColor(accent)
            .text(icon, x + 4, y + 14, { lineBreak: false });

        doc.font('Helvetica-Bold').fontSize(9).fillColor(C.dark);
        while (nom.length > 1 && doc.widthOfString(nom) > w - 10) nom = nom.slice(0, -1);
        doc.text(nom, x + 4, y + 25, { width: w - 8, lineBreak: false });

        doc.font('Helvetica').fontSize(7).fillColor(C.grey)
            .text(`Le ${ds}`, x + 4, y + 36, { width: w - 8, lineBreak: false });

        if (comment)
            doc.font('Helvetica-Oblique').fontSize(6.5).fillColor(C.grey)
                .text(comment, x + 4, y + 45, { width: w - 8, lineBreak: false });

        doc.save().strokeColor(border).lineWidth(0.5)
            .moveTo(x + 3, y + h - 9).lineTo(x + w - 3, y + h - 9).stroke().restore();
        doc.font('Helvetica').fontSize(6).fillColor(C.grey)
            .text('Signature — NDF ENSUP', x + 4, y + h - 7,
                { width: w - 8, align: 'center', lineBreak: false });
    } else {
        doc.font('Helvetica').fontSize(8).fillColor(C.grey)
            .text('En attente de signature', x + 4, y + h / 2 - 5,
                { width: w - 8, align: 'center', lineBreak: false });
    }
} 