// ECO-PANNEAU.FR - __react/socle/_socle_pdf.jsx

const { useState, useEffect, useRef, memo } = React;

// 1. - VISIONNEUSES PDF (PIÈCES JOINTES ET ARRÊTÉS)

window.pano_PdfThumbnail = memo(({ url, id }) => {
    const { LoaderIcon, FileIcon } = window.pano_getIcons();
    
    const [error, setError] = useState(false);
    const previewUrl = id ? `${window.pano_CONFIG.apiBaseUrl}file/preview&type=pdf&id=${id}` : url?.replace('download', 'preview');
    
    if (error) {
        return (
            <div className="w-full h-32 bg-slate-100 flex items-center justify-center relative rounded-xl">
                <div className="text-slate-400 flex flex-col items-center">
                    <FileIcon size={24} />
                </div>
            </div>
        );
    }

    return (
        <div className="w-full h-32 bg-slate-100 flex items-center justify-center relative rounded-xl">
            <LoaderIcon className="animate-spin text-slate-300 absolute -z-10" size={24} />
            <img 
                src={previewUrl} 
                loading="lazy" 
                className="w-full h-full object-contain relative z-10 rounded-xl" 
                alt="Aperçu PDF" 
                onError={() => {
                    if (!error) {
                        if (window.pano_logFallback) window.pano_logFallback(`Échec du chargement de la miniature PDF (id: ${id}). Affichage de l'icône de secours.`);
                        setError(true);
                    }
                }} 
            />
        </div>
    );
});

const PdfPage = memo(({ pdf, pageNumber }) => {
    const canvasRef = useRef(null);
    const [rendered, setRendered] = useState(false);
    const { LoaderIcon } = window.pano_getIcons();

    useEffect(() => {
        let renderTask = null;
        let isSubscribed = true;

        pdf.getPage(pageNumber).then(page => {
            if (!isSubscribed) return;
            const canvas = canvasRef.current;
            if (!canvas) return;
            
            const ctx = canvas.getContext('2d');
            const viewport = page.getViewport({ scale: 1.5 });
            canvas.width = viewport.width;
            canvas.height = viewport.height;
            canvas.style.width = '100%';
            canvas.style.maxWidth = `${viewport.width}px`;
            canvas.style.height = 'auto';

            renderTask = page.render({ canvasContext: ctx, viewport });
            renderTask.promise.then(() => {
                if (isSubscribed) setRendered(true);
            }).catch(err => {
                if (err.name !== 'RenderingCancelledException') {
                    if (window.pano_logFallback) window.pano_logFallback(`Erreur de rendu PDF.js (page ${pageNumber}): ${err.message}`);
                }
            });
        });

        return () => {
            isSubscribed = false;
            if (renderTask) renderTask.cancel();
        };
    }, [pdf, pageNumber]);

    return (
        <div className="relative shadow-2xl rounded-xl bg-white w-full max-w-3xl shrink-0 flex items-center justify-center min-h-[300px] mb-6">
            {!rendered && <LoaderIcon className="animate-spin text-slate-300 absolute" size={32} />}
            <canvas ref={canvasRef} className="w-full h-auto relative z-10 block rounded-xl" />
        </div>
    );
});

window.pano_PdfFullViewer = memo(({ url, id, isPrivate = false }) => {
    const { LoaderIcon, FileIcon } = window.pano_getIcons();
    
    const [pdf, setPdf] = useState(null);
    const [error, setError] = useState(false);
    const [loading, setLoading] = useState(true);
    
    // CORRECTION OOM : Référence pour nettoyer la mémoire vive
    const pdfRef = useRef(null);

    const downloadUrl = id ? `${window.pano_CONFIG.apiBaseUrl}file/download&type=pdf&id=${id}${isPrivate ? '&private=1' : ''}` : url;

    useEffect(() => {
        let isMounted = true;

        if (!window.pano_pdfjsLib) {
            if (window.pano_logFallback) window.pano_logFallback("pano_PdfFullViewer: Bibliothèque PDF.js manquante. Affichage de l'erreur au client.");
            setError(true);
            setLoading(false);
            return;
        }
        
        const fetchAndRenderPdf = async () => {
            try {
                // CORRECTION OOM : Utilisation du streaming natif de PDF.js au lieu d'un fetch() en arrayBuffer complet
                const loadingTask = window.pano_pdfjsLib.getDocument({ 
                    url: downloadUrl, 
                    httpHeaders: { 'x-silent': '1' } 
                });
                
                const loadedPdf = await loadingTask.promise;
                
                if (isMounted) {
                    pdfRef.current = loadedPdf;
                    setPdf(loadedPdf);
                    setLoading(false);
                } else {
                    // Le composant a été fermé pendant le téléchargement
                    loadedPdf.destroy();
                }
            } catch (err) {
                if (window.pano_logFallback) window.pano_logFallback(`Échec de récupération ou lecture du PDF complet (${downloadUrl}): ${err.message}`);
                if (isMounted) {
                    setError(true);
                    setLoading(false);
                }
            }
        };

        fetchAndRenderPdf();

        return () => {
            isMounted = false;
            // CORRECTION OOM : Libération stricte de la mémoire du Web Worker pdf.js
            if (pdfRef.current) {
                pdfRef.current.destroy();
                pdfRef.current = null;
            }
        };
    }, [downloadUrl]);

    if (loading) {
        return (
            <div className="w-full h-full flex flex-col items-center justify-center">
                <LoaderIcon className="animate-spin text-emerald-600 mb-4" size={48} />
                <span className="text-white font-bold text-sm tracking-widest uppercase">Chargement du document...</span>
            </div>
        );
    }

    if (error || !pdf) {
        return (
            <div className="w-full h-full flex flex-col items-center justify-center text-slate-400 gap-4">
                <FileIcon size={48} />
                <span className="font-bold">Aperçu indisponible ou document corrompu.</span>
            </div>
        );
    }

    const pages = [];
    for (let i = 1; i <= pdf.numPages; i++) {
        pages.push(<PdfPage key={i} pdf={pdf} pageNumber={i} />);
    }

    return (
        <div className="w-full h-full overflow-y-auto overflow-x-hidden custom-scrollbar flex flex-col items-center pt-2 px-2 sm:px-4">
            {pages}
        </div>
    );
});


// 2. - GÉNÉRATEUR PDF NATIF A1 (IMPRESSION)

window.pano_generateA1PDF = async (panneau) => {
    const jsPDF = window.jspdf ? window.jspdf.jsPDF : null;
    
    if (!jsPDF) {
        if (window.pano_logFallback) window.pano_logFallback("Générateur A1: Bibliothèque jsPDF introuvable. Échec de la génération.");
        throw new Error("La bibliothèque de génération PDF n'est pas encore chargée.");
    }
    
    // FORMAT IMPRIMEUR EXACT AVEC FOND PERDU : 845 x 598 mm (Paysage)
    const doc = new jsPDF({ 
        orientation: 'landscape', 
        unit: 'mm', 
        format: [845, 598] 
    });
    
    let fontLoaded = false;
    
    const hexToRgb = (hex) => {
        let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex || '#059669');
        if (result) {
            return { 
                r: parseInt(result[1], 16), 
                g: parseInt(result[2], 16), 
                b: parseInt(result[3], 16) 
            };
        }
        return { r: 5, g: 150, b: 105 };
    };

    // CORRECTION OPTIMISATION : Plafond à ~1200px (200 DPI), fond '#F8FAFC' et export JPEG 85%
    const loadImage = (url) => new Promise((resolve, reject) => {
        const img = new Image();
        img.crossOrigin = 'Anonymous';
        img.onload = () => {
            const MAX_WIDTH = 1200;
            let width = img.width;
            let height = img.height;

            if (width > MAX_WIDTH) {
                const ratio = MAX_WIDTH / width;
                width = MAX_WIDTH;
                height = height * ratio;
            }

            const canvas = document.createElement('canvas');
            canvas.width = width;
            canvas.height = height;
            const ctx = canvas.getContext('2d');
            
            // Fond plein gris clair (slate-50 de Tailwind : rgb(248, 250, 252))
            ctx.fillStyle = '#F8FAFC';
            ctx.fillRect(0, 0, width, height);
            
            ctx.drawImage(img, 0, 0, width, height);
            
            // Export en JPEG 0.85
            resolve({ dataUrl: canvas.toDataURL('image/jpeg', 0.85), width: width, height: height });
        };
        img.onerror = reject;
        img.src = url;
    });

    // CORRECTION OPTIMISATION : Fond plein foncé '#0F172A' et export JPEG 85%
    const loadFaviconAsHighResJpeg = async (url) => {
        try {
            const resp = await fetch(url);
            if (!resp.ok) return null;
            let svgText = await resp.text();
            
            if (!svgText.includes('width=')) {
                svgText = svgText.replace('<svg', '<svg width="2048" height="2048"');
            } else {
                svgText = svgText.replace(/width="[^"]+"/, 'width="2048"').replace(/height="[^"]+"/, 'height="2048"');
            }

            const svgBase64 = "data:image/svg+xml;base64," + window.btoa(unescape(encodeURIComponent(svgText)));

            return new Promise((resolve, reject) => {
                const img = new Image();
                img.crossOrigin = 'Anonymous';
                img.onload = () => {
                    const canvas = document.createElement('canvas');
                    canvas.width = 2048;
                    canvas.height = 2048;
                    const ctx = canvas.getContext('2d');
                    
                    // Fond plein bleu nuit (slate-900 de Tailwind : rgb(15, 23, 42))
                    ctx.fillStyle = '#0F172A';
                    ctx.fillRect(0, 0, 2048, 2048);
                    
                    ctx.drawImage(img, 0, 0, 2048, 2048);
                    
                    // Export en JPEG 0.85
                    resolve({ dataUrl: canvas.toDataURL('image/jpeg', 0.85), width: 2048, height: 2048 });
                };
                img.onerror = reject;
                img.src = svgBase64;
            });
        } catch (e) {
            return null;
        }
    };

    let moaLogo = null;
    let faviconLogo = null;
    
    try {
        const loadFont = async (fontName, fontStyle, url) => {
            const cacheKey = `${fontName}-${fontStyle}`;
            let base64 = window.pano_CONFIG?.pdfFontsCache?.[cacheKey];
            
            if (!base64) {
                const resp = await fetch(url);
                if (!resp.ok) {
                    throw new Error("Erreur réseau lors du chargement de la police");
                }
                const buffer = await resp.arrayBuffer();
                let binary = ''; 
                const bytes = new Uint8Array(buffer);
                
                for (let i = 0; i < bytes.byteLength; i++) { 
                    binary += String.fromCharCode(bytes[i]); 
                }
                
                base64 = window.btoa(binary);
                if (!window.pano_CONFIG) window.pano_CONFIG = {};
                if (!window.pano_CONFIG.pdfFontsCache) window.pano_CONFIG.pdfFontsCache = {};
                window.pano_CONFIG.pdfFontsCache[cacheKey] = base64;
            }
            
            const fileName = `${cacheKey}.ttf`;
            doc.addFileToVFS(fileName, base64);
            doc.addFont(fileName, fontName, fontStyle);
        };

        const assetsUrl = (window.pano_CONFIG && window.pano_CONFIG.assetsUrl) ? window.pano_CONFIG.assetsUrl : '_assets/';
        await Promise.all([
            loadFont("Roboto", "normal", window.pano_CONFIG?.fonts?.robotoRegular || (assetsUrl + "roboto/Roboto-Regular.ttf")),
            loadFont("Roboto", "bold", window.pano_CONFIG?.fonts?.robotoMedium || (assetsUrl + "roboto/Roboto-Medium.ttf"))
        ]);
        
        fontLoaded = true;

        const logoUrl = panneau.maitreOuvrageLogoUrl || (panneau.maitreOuvrageLogoId ? `${window.pano_CONFIG?.apiBaseUrl || '?api='}file/download&type=image&id=${panneau.maitreOuvrageLogoId}` : null);
        if (logoUrl) {
            moaLogo = await loadImage(logoUrl);
        }

        const faviconUrl = window.location.origin + '/favicon.svg';
        faviconLogo = await loadFaviconAsHighResJpeg(faviconUrl);

    } catch(e) {
        if (window.pano_logFallback) window.pano_logFallback(`Avertissement A1: Échec de chargement d'une ressource. Fallback système utilisé. Détail: ${e.message}`);
    }

    const sanitizeForPDF = (str) => {
        if (!str) {
            return '';
        }
        
        if (fontLoaded) {
            return str.toString().replace(/[\u1000-\uFFFF]/g, ''); 
        }
        
        let s = str.toString()
             .replace(/[’‘`]/g, "'")
             .replace(/[“”«»]/g, '"')
             .replace(/[–—]/g, '-')
             .replace(/œ/g, 'oe')
             .replace(/Œ/g, 'Oe')
             .replace(/€/g, 'EUR');
             
        return s.replace(/[^\x00-\xFF]/g, ""); 
    };

    const mainFont = fontLoaded ? "Roboto" : "helvetica";
    const themeRgb = hexToRgb(panneau.themeColor);
    
    doc.setFillColor(255, 255, 255); 
    doc.rect(0, 0, 845, 598, 'F');
    
    doc.setFillColor(themeRgb.r, themeRgb.g, themeRgb.b); 
    doc.rect(0, 0, 845, 45, 'F');

    if (!panneau.hasNoAds) {
        doc.setFillColor(15, 23, 42); 
        doc.rect(0, 598 - 45, 845, 45, 'F');
        
        doc.setFillColor(themeRgb.r, themeRgb.g, themeRgb.b); 
        doc.rect(0, 598 - 50, 845, 5, 'F');
        
        doc.setFont(mainFont, "bold"); 
        doc.setFontSize(55); 

        const textEco = "eco";
        const textPanneau = "-panneau";
        const textFr = ".fr";
        const textSep = "  |  ";
        const textDesc = "Professionnels du BTP : digitalisez vos obligations.";

        const wEco = doc.getTextWidth(textEco);
        const wPanneau = doc.getTextWidth(textPanneau);
        const wFr = doc.getTextWidth(textFr);
        const wSep = doc.getTextWidth(textSep);
        const wDesc = doc.getTextWidth(textDesc);

        const iconSize = 18;
        const iconMargin = 6;
        
        const totalWidth = iconSize + iconMargin + wEco + wPanneau + wFr + wSep + wDesc;
        
        let startX = 422.5 - (totalWidth / 2);
        
        const textY = 598 - 16; 
        const iconY = 598 - 45 + ((45 - iconSize) / 2); 
        
        if (faviconLogo) {
            // INTEGRATION jsPDF : Utilisation stricte de JPEG compressé
            doc.addImage(faviconLogo.dataUrl, 'JPEG', startX, iconY, iconSize, iconSize);
        } else {
            doc.setFillColor(30, 41, 59);
            doc.roundedRect(startX, iconY, iconSize, iconSize, 3.5, 3.5, 'F');
            
            doc.setDrawColor(255, 255, 255);
            doc.setLineWidth(1);
            doc.setFillColor(255, 255, 255);
            
            doc.roundedRect(startX + 2.5, iconY + 2.5, 5, 5, 1, 1, 'D');
            doc.rect(startX + 4, iconY + 4, 2, 2, 'F');
            doc.roundedRect(startX + 2.5, iconY + 10, 5, 5, 1, 1, 'D');
            doc.rect(startX + 4, iconY + 11.5, 2, 2, 'F');
            doc.roundedRect(startX + 10, iconY + 10, 5, 5, 1, 1, 'D');
            doc.rect(startX + 11.5, iconY + 11.5, 2, 2, 'F');
            
            doc.setFillColor(5, 150, 105);
            doc.triangle(startX + 10, iconY + 7.5, startX + 15.5, iconY + 2, startX + 15.5, iconY + 7.5, 'F');
        }
        
        startX += iconSize + iconMargin;
        
        doc.setTextColor(5, 150, 105); 
        doc.text(textEco, startX, textY);
        startX += wEco;
        
        doc.setTextColor(255, 255, 255);
        doc.text(textPanneau, startX, textY);
        startX += wPanneau;
        
        doc.setTextColor(148, 163, 184); 
        doc.text(textFr, startX, textY);
        startX += wFr;
        
        doc.setTextColor(71, 85, 105);
        doc.text(textSep, startX, textY);
        startX += wSep;
        
        doc.setTextColor(255, 255, 255);
        doc.text(textDesc, startX, textY);
    }

    const qrSize = 210; 
    const qrX = 55; 
    const qrY = 110;
    
    doc.setDrawColor(226, 232, 240); 
    doc.setLineWidth(3); 
    doc.setFillColor(255, 255, 255);
    doc.roundedRect(qrX - 15, qrY - 15, qrSize + 30, qrSize + 30, 5, 5, 'FD');

    if (!window.QRCode) {
        if (window.pano_logFallback) window.pano_logFallback("Générateur A1: QRCode.js manquant. Échec de la génération.");
        throw new Error("La bibliothèque de génération de QR Code n'est pas chargée.");
    }

    const qr = new window.QRCode({ 
        content: `https://eco-panneau.fr/?scan=${panneau.id}`, 
        padding: 0, 
        width: 256, 
        height: 256, 
        ecl: "H" 
    });
    
    const modules = qr.qrcode.modules; 
    const moduleCount = modules.length; 
    const moduleSize = qrSize / moduleCount;

    doc.setFillColor(15, 23, 42);
    
    for (let row = 0; row < moduleCount; row++) {
        for (let col = 0; col < moduleCount; col++) {
            if (modules[row][col]) { 
                doc.rect(qrX + col * moduleSize, qrY + row * moduleSize, moduleSize + 0.5, moduleSize + 0.5, 'F'); 
            }
        }
    }

    doc.setTextColor(15, 23, 42); 
    doc.setFontSize(40); 
    doc.setFont(mainFont, "bold"); 
    doc.text("Scannez pour les informations", qrX + qrSize / 2, qrY + qrSize + 50, { align: 'center' });
    doc.text("utiles et légales.", qrX + qrSize / 2, qrY + qrSize + 70, { align: 'center' });

    doc.setDrawColor(226, 232, 240); 
    doc.setLineWidth(2); 
    doc.line(345, 80, 345, panneau.hasNoAds ? 550 : 500);

    const drawAutoText = (text, x, y, maxW, maxH, startSize, minSize, fontName, fontStyle, color) => {
        const cleanText = sanitizeForPDF(text);
        if (!cleanText || cleanText.trim() === '') return { height: 0 };
        
        doc.setFont(fontName, fontStyle); 
        doc.setTextColor(color[0], color[1], color[2]);
        
        let fontSize = startSize; 
        doc.setFontSize(fontSize);
        
        let lines = doc.splitTextToSize(cleanText, maxW);
        let loopCount = 0;
        
        while (lines.length * (fontSize * 0.3528 * 1.15) > maxH && fontSize > minSize) {
            loopCount++; 
            if (loopCount > 30) break;
            fontSize -= 2; 
            doc.setFontSize(fontSize); 
            lines = doc.splitTextToSize(cleanText, maxW);
        }
        
        doc.text(lines, x, y);
        return { height: lines.length * (fontSize * 0.3528 * 1.15) };
    };

    const textX = 390; 
    const maxTextW = 410;
    
    doc.setTextColor(themeRgb.r, themeRgb.g, themeRgb.b); 
    doc.setFontSize(45); 
    doc.setFont(mainFont, "bold");
    doc.text("Panneau d'affichage légal", textX, 110);
    
    const nameMetrics = drawAutoText(panneau.name, textX, 150, maxTextW, 120, 100, 30, mainFont, "bold", [15, 23, 42]);
    
    const locY = Math.max(230, 150 + nameMetrics.height + 10);
    const locMetrics = drawAutoText(panneau.location, textX, locY, maxTextW, 60, 50, 20, mainFont, "normal", [71, 85, 105]);

    let boxY = Math.max(380, locY + locMetrics.height + 30);
    
    if (panneau.maitreOuvrage || moaLogo) {
        const moaText = panneau.maitreOuvrage || '';
        
        doc.setFontSize(50);
        const availableTextWidth = moaLogo ? 260 : 380;
        let moaLines = doc.splitTextToSize(sanitizeForPDF(moaText), availableTextWidth);
        let moaSize = 50;
        
        if (moaLines.length > 1) { moaSize = 40; doc.setFontSize(40); moaLines = doc.splitTextToSize(sanitizeForPDF(moaText), availableTextWidth); }
        if (moaLines.length > 2) { moaSize = 30; doc.setFontSize(30); moaLines = doc.splitTextToSize(sanitizeForPDF(moaText), availableTextWidth); }
        
        let textH = moaText ? (moaLines.length * (moaSize * 0.3528 * 1.15)) : 0;
        let contentH = Math.max(textH, moaLogo ? 60 : 0);
        let boxHeight = Math.max(70, 30 + contentH + 10);
        
        doc.setFillColor(248, 250, 252); 
        doc.setDrawColor(226, 232, 240); 
        doc.roundedRect(textX, boxY, 410, boxHeight, 5, 5, 'FD');
        
        doc.setTextColor(100, 116, 139); 
        doc.setFontSize(30); 
        doc.setFont(mainFont, "bold");
        doc.text("Maître d'ouvrage", textX + 15, boxY + 22); 
        
        if (moaText) {
            doc.setTextColor(15, 23, 42);
            doc.setFontSize(moaSize);
            doc.text(moaLines, textX + 15, boxY + 48);
        }
        
        if (moaLogo) {
            const maxLogoW = 110;
            const maxLogoH = boxHeight - 20; 
            const ratio = Math.min(maxLogoW / moaLogo.width, maxLogoH / moaLogo.height);
            const logoW = moaLogo.width * ratio;
            const logoH = moaLogo.height * ratio;
            
            const logoX = textX + 410 - 15 - logoW;
            const logoY = boxY + 10 + (maxLogoH - logoH) / 2;
            
            // INTEGRATION jsPDF : Utilisation stricte de JPEG compressé
            doc.addImage(moaLogo.dataUrl, 'JPEG', logoX, logoY, logoW, logoH);
        }
        
        boxY += boxHeight + 20;
    }

    if (panneau.permitNumber) {
        doc.setTextColor(148, 163, 184); 
        doc.setFontSize(35); 
        doc.setFont(mainFont, "bold");
        doc.text("Permis N°", textX, boxY + 25);
        
        drawAutoText(panneau.permitNumber.toString(), textX + 100, boxY + 25, 310, 60, 60, 20, mainFont, "bold", [15, 23, 42]);
    }
    
    return doc.output('blob');
};

// 3. - PRÉVISUALISATION A1
window.pano_PrintA1View = ({ panneau }) => {
    const [isGenerating, setIsGenerating] = React.useState(true);
    const [error, setError] = React.useState(null);
    const canvasRef = React.useRef(null);

    const { LoaderIcon, AlertTriangleIcon } = window.pano_getIcons();

    const panelFingerprint = JSON.stringify({
        id: panneau?.id,
        name: panneau?.name,
        location: panneau?.location,
        themeColor: panneau?.themeColor,
        hasNoAds: panneau?.hasNoAds,
        maitreOuvrage: panneau?.maitreOuvrage,
        maitreOuvrageLogoId: panneau?.maitreOuvrageLogoId,
        permitNumber: panneau?.permitNumber
    });

    React.useEffect(() => {
        let isMounted = true;
        let currentPdf = null; // CORRECTION OOM : Référence locale

        const renderPDF = async () => {
            if (!panneau) return;
            try {
                setIsGenerating(true);
                setError(null);

                const blob = await window.pano_generateA1PDF(panneau);
                
                if (!isMounted) return;

                if (!window.pano_pdfjsLib) {
                    if (window.pano_logFallback) window.pano_logFallback("PrintA1View: La bibliothèque de lecture PDF.js n'est pas chargée. Échec de l'aperçu.");
                    throw new Error("La bibliothèque de lecture PDF n'est pas chargée.");
                }

                const arrayBuffer = await blob.arrayBuffer();
                currentPdf = await window.pano_pdfjsLib.getDocument({ data: arrayBuffer }).promise;
                const page = await currentPdf.getPage(1);
                
                if (!isMounted) return;

                const canvas = canvasRef.current;
                if (!canvas) return;
                const ctx = canvas.getContext('2d');
                
                // CORRECTION CRITIQUE (CRASH iOS CANVAS) : Calcul dynamique de la résolution maximale
                const baseVp = page.getViewport({ scale: 1 });
                const safeScale = Math.min(2, 2048 / baseVp.width); // Limite stricte de largeur de 2048px
                const viewport = page.getViewport({ scale: safeScale });
                
                canvas.width = viewport.width;
                canvas.height = viewport.height;
                
                await page.render({ canvasContext: ctx, viewport }).promise;
                
                if (isMounted) {
                    setIsGenerating(false);
                }

            } catch (err) {
                if (window.pano_logFallback) window.pano_logFallback(`Erreur de génération de l'aperçu PDF A1: ${err.message}`);
                if (isMounted) {
                    setError(err.message);
                    setIsGenerating(false);
                }
            } finally {
                // CORRECTION OOM : On nettoie l'objet lourd une fois rendu
                if (currentPdf) {
                    currentPdf.destroy();
                    currentPdf = null;
                }
            }
        };

        renderPDF();

        return () => {
            isMounted = false;
            // Filet de sécurité en cas de démontage avant la fin
            if (currentPdf) {
                currentPdf.destroy();
                currentPdf = null;
            }
        };
    }, [panelFingerprint]);

    return (
        <div className="w-full h-full flex items-center justify-center bg-slate-200 overflow-y-auto overflow-x-hidden relative shadow-inner">
            {isGenerating && (
                <div className="absolute inset-0 flex flex-col items-center justify-center bg-white/90 backdrop-blur-sm z-10">
                    <LoaderIcon size={32} className="animate-spin text-emerald-600 mb-3" />
                    <span className="text-[10px] font-black text-slate-500 uppercase tracking-widest">Rendu haute fidélité en cours...</span>
                </div>
            )}
            
            {error && (
                <div className="absolute inset-0 flex flex-col items-center justify-center bg-white z-20 p-6 text-center">
                    <AlertTriangleIcon size={32} className="text-red-500 mb-3" />
                    <span className="text-red-500 font-bold mb-2">Erreur d'aperçu</span>
                    <span className="text-xs text-slate-500">{error}</span>
                </div>
            )}
            
            <canvas 
                ref={canvasRef} 
                className="max-w-full max-h-full object-contain shadow-2xl bg-white transition-opacity duration-300"
                style={{ opacity: isGenerating ? 0 : 1 }}
            />
        </div>
    );
};

/* EOF ========== [__react/socle/_socle_pdf.jsx] */