/**
 * =========================================================================
 * PLATEFORME ECO-PANNEAU.FR - VERSION 1.0.0
 * Composants UI Globaux, Icônes, Utilitaires et Moteur PDF jsPDF
 * =========================================================================
 */

const { useState, useEffect, useRef } = React;

// =========================================================================
// 1. CONFIGURATION GLOBALE ET MÉTHODES D'API
// =========================================================================

window.ECO_CONFIG = window.ECO_CONFIG || {};
window.ECO_CONFIG.pdfFontsCache = window.ECO_CONFIG.pdfFontsCache || {};

window.uploadFile = async (file, type, delegateToken = window.CURRENT_DELEGATE_TOKEN, isPrivate = false) => {
    const formData = new FormData(); formData.append('file', file); formData.append('type', type);
    if (isPrivate) formData.append('is_private', 'true'); if (delegateToken) formData.append('delegate_token', delegateToken);
    try {
        const res = await fetch('?api=upload/file', { method: 'POST', body: formData });
        if (!res.ok) throw new Error('Erreur HTTP serveur : ' + res.status);
        const data = await res.json(); if (data.status === 'success') return data.data.fileId;
        throw new Error(data.message || 'Erreur inconnue lors du téléchargement');
    } catch (err) { throw new Error("Échec de l'envoi : " + err.message); }
};

window.deleteFile = async (id, type, delegateToken = window.CURRENT_DELEGATE_TOKEN) => {
    try { await fetch('?api=file/delete', { method: 'POST', body: JSON.stringify({ id, type, delegate_token: delegateToken }), headers: { 'Content-Type': 'application/json' } }); } catch (err) {}
};

// =========================================================================
// 2. BIBLIOTHÈQUE D'ICÔNES SVG (Depuis _constantes.jsx)
// =========================================================================

const predefinedThemes = window.predefinedThemes || [];

const Icons = {};
if (window.svgPaths) {
  Object.keys(window.svgPaths).forEach(key => {
    Icons[key] = ({ size = 24, className = "", style = {}, title }) => React.createElement("svg", {
      xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 24 24",
      fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round",
      className, style, dangerouslySetInnerHTML: title ? { __html: `<title>${title}</title>${window.svgPaths[key]}` } : { __html: window.svgPaths[key] }
    });
  });
}

const { 
  Leaf, QrCode, Home, Building, Users, AlertTriangle, CheckCircle, Search, Menu, X, Plus, MessageSquare, 
  Download, MapPin, Shield, LifeBuoy, ArrowRight, ArrowLeft, ArrowUp, ArrowDown, UserCheck, Smartphone, Check, Settings, FileSignature, HardHat, FileDigit, Info, Edit,
  Activity, Server, HardDrive, Wifi, Terminal, RefreshCw, CreditCard, Percent, Tag, Lock, ShoppingCart, FileText, Loader, Copy,
  LogIn, LogOut, Calendar, Clock, ExternalLink, Palette, Globe, Phone, Mail, GripVertical, Trash2, Save, Eye, Power, AlertOctagon, Database, KeyRound, History, ShieldAlert, Scale, Zap, UserCircle, ShieldCheck, FileCheck, Image, Package, Archive, BarChart, Newspaper, LinkIcon, Bell, BellRing, HardDriveDownload, Share2
} = Icons;

// =========================================================================
// 3. UTILITAIRES ET COMPOSANTS GLOBAUX
// =========================================================================

class ErrorBoundary extends React.Component {
  constructor(props) { super(props); this.state = { hasError: false, error: null }; }
  static getDerivedStateFromError(error) { return { hasError: true, error }; }
  render() { 
      if (this.state.hasError) return (<div className="h-screen flex items-center justify-center p-8 bg-red-50 text-red-600"><pre className="text-xs bg-white p-4 rounded border">{this.state.error.toString()}</pre></div>); 
      return this.props.children; 
  }
}

const NativeQRCode = ({ value, size = 120, padding = 0, className = "", ecc = "H", onRendered }) => {
    const containerRef = useRef(null);
    useEffect(() => {
        if (containerRef.current && window.QRCode) {
            containerRef.current.innerHTML = '';
            const text = value || "https://eco-panneau.fr";
            const qr = new window.QRCode({ content: text, padding: padding, width: 256, height: 256, color: "#0f172a", background: "transparent", ecl: ecc });
            const svg = qr.svg();
            containerRef.current.innerHTML = svg;
            const svgElement = containerRef.current.querySelector('svg');
            if (svgElement) {
                // Suppression stricte des dimensions fixes pour un vrai comportement vectoriel adaptatif
                svgElement.removeAttribute('width');
                svgElement.removeAttribute('height');
                svgElement.style.width = '100%'; 
                svgElement.style.height = '100%';
                svgElement.setAttribute('preserveAspectRatio', 'xMidYMid meet');
                svgElement.style.display = 'block';
                if(onRendered) onRendered(svg);
            }
        }
    }, [value, ecc, padding, onRendered]);

    return (<div ref={containerRef} style={{ width: size, height: size }} className={`shrink-0 flex items-center justify-center ${className}`}></div>);
};

const SimpleBarChart = ({ data }) => {
    if (!data || data.length === 0) return <div className="text-slate-400 text-sm text-center py-10">Pas encore assez de données de scan.</div>;
    const max = Math.max(...data.map(d => d.count), 1);
    return (
        <div className="w-full overflow-x-auto overflow-y-hidden custom-scrollbar pb-6">
            <div className="flex items-end gap-2 h-40 pt-6 min-w-[500px] px-2">
                {data.map((d, i) => (
                    <div key={i} className="flex-1 flex flex-col items-center gap-2 group" title={`${d.count} scans`}>
                        <div className="w-full bg-emerald-100 rounded-t-sm relative flex items-end justify-center hover:bg-emerald-300 transition-colors" style={{ height: `${(d.count / max) * 100}%`, minHeight: '4px' }}>
                            <span className="absolute -top-6 text-[10px] font-bold text-emerald-700 opacity-0 group-hover:opacity-100 transition-opacity bg-white px-2 py-1 rounded shadow-sm z-10 pointer-events-none">{d.count}</span>
                        </div>
                        <span className="text-[8px] text-slate-400 -rotate-45 origin-top-left truncate w-full mt-2 leading-none">{new Date(d.date).toLocaleDateString('fr-FR', {day:'2-digit', month:'2-digit'})}</span>
                    </div>
                ))}
            </div>
        </div>
    );
};

// =========================================================================
// 4. MOTEUR DE GÉNÉRATION PDF NATIF (jsPDF) ET APERÇU A1 FLUIDE
// =========================================================================

window.generateA1PDF = async (chantier) => {
    const { jsPDF } = window.jspdf;
    // Format A1 paysage : 841 x 594 mm
    const doc = new jsPDF({ orientation: 'landscape', unit: 'mm', format: [841, 594] });
    
    let fontLoaded = false;
    try {
        const loadFont = async (fontName, fontStyle, url) => {
            const cacheKey = `${fontName}-${fontStyle}`;
            let base64 = window.ECO_CONFIG.pdfFontsCache[cacheKey];
            
            if (!base64) {
                const resp = await fetch(url);
                if (!resp.ok) throw new Error("Network");
                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);
                window.ECO_CONFIG.pdfFontsCache[cacheKey] = base64;
            }
            const fileName = `${cacheKey}.ttf`;
            doc.addFileToVFS(fileName, base64);
            doc.addFont(fileName, fontName, fontStyle);
        };

        await Promise.all([
            loadFont("Roboto", "normal", "https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/fonts/Roboto/Roboto-Regular.ttf"),
            loadFont("Roboto", "bold", "https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.2.7/fonts/Roboto/Roboto-Medium.ttf")
        ]);
        fontLoaded = true;
    } catch(e) {
        console.warn("Échec du chargement des polices UTF-8. Bascule sur Helvetica.");
    }

    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";
    
    doc.setFillColor(255, 255, 255); doc.rect(0, 0, 841, 594, 'F');

    const hexToRgb = (hex) => {
        let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex || '#059669');
        return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : { r:5, g:150, b:105 };
    };
    const themeRgb = hexToRgb(chantier.themeColor);
    
    // Bandeau supérieur couleur
    doc.setFillColor(themeRgb.r, themeRgb.g, themeRgb.b); doc.rect(0, 0, 841, 45, 'F');

    // Bandeau inférieur pub
    if (!chantier.hasNoAds) {
        doc.setFillColor(15, 23, 42); doc.rect(0, 594 - 45, 841, 45, 'F');
        doc.setFillColor(16, 185, 129); doc.rect(0, 594 - 50, 841, 5, 'F');
        doc.setTextColor(255, 255, 255); doc.setFont(mainFont, "bold"); doc.setFontSize(35);
        doc.text("eco-panneau.fr  |  Professionnels du BTP : digitalisez vos obligations.", 420.5, 594 - 18, { align: 'center' });
    }

    // Colonne de gauche (QR Code)
    const qrSize = 210; const qrX = 50; 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');

    // Retrait du padding=4 natif pour un dessin précis et centré dans notre box jsPDF
    const qr = new window.QRCode({ content: `https://eco-panneau.fr/?scan=${chantier.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, moduleSize, '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("légales et utiles", qrX + qrSize/2, qrY + qrSize + 70, { align: 'center' });

    // Séparateur vertical
    doc.setDrawColor(226, 232, 240); doc.setLineWidth(2); doc.line(340, 80, 340, chantier.hasNoAds ? 550 : 500);

    const drawAutoText = (text, x, y, maxW, maxH, startSize, fontName, fontStyle, color) => {
        const cleanText = sanitizeForPDF(text);
        if (!cleanText || cleanText.trim() === '') return;
        
        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;
        
        // Multiplicateur 0.352 pour convertir les points en mm
        while (lines.length * (fontSize * 0.352) > maxH && fontSize > 20) {
            loopCount++; if (loopCount > 20) break;
            fontSize -= 2; doc.setFontSize(fontSize); lines = doc.splitTextToSize(cleanText, maxW);
        }
        if (lines.length * (fontSize * 0.352) > maxH) {
            const maxAllowedLines = Math.floor(maxH / (fontSize * 0.352));
            lines = lines.slice(0, maxAllowedLines);
            if (lines.length > 0) lines[lines.length - 1] += "...";
        }
        doc.text(lines, x, y);
    };

    // Colonne de droite (Textes)
    const textX = 380; const maxTextW = 420;
    doc.setTextColor(themeRgb.r, themeRgb.g, themeRgb.b); doc.setFontSize(45); doc.setFont(mainFont, "bold");
    doc.text("Panneau d'affichage légal", textX, 110);
    
    drawAutoText(chantier.name, textX, 140, maxTextW, 120, 120, mainFont, "bold", [15, 23, 42]);
    drawAutoText(chantier.location, textX, 280, maxTextW, 60, 60, mainFont, "normal", [71, 85, 105]);

    let boxY = 380;
    if (chantier.maitreOuvrage || chantier.clientName) {
        doc.setFillColor(248, 250, 252); doc.setDrawColor(226, 232, 240); doc.roundedRect(textX, boxY, 420, 70, 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); 
        drawAutoText((chantier.maitreOuvrage || chantier.clientName), textX + 15, boxY + 48, 390, 30, 60, mainFont, "bold", [15, 23, 42]);
        boxY += 90;
    }

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

/**
 * Aperçu visuel en CSS pur (Fluid) du panneau A1.
 * Utilise des dimensions relatives (cqw) pour s'adapter à n'importe quel conteneur de façon réaliste.
 */
const PrintA1View = ({ chantier }) => {
    if (!chantier) return <div className="p-10 font-bold text-center text-slate-500">Panneau introuvable...</div>;

    const displayMoaLogoUrl = chantier.maitreOuvrageLogoId ? `?api=file/download&type=image&id=${chantier.maitreOuvrageLogoId}` : chantier.maitreOuvrageLogoUrl;
    const textThemeColor = chantier.themeColor || '#059669';

    return (
        <div style={{ containerType: 'inline-size', aspectRatio: '841/594', width: '100%', backgroundColor: 'white', position: 'relative', overflow: 'hidden', fontFamily: 'Inter, sans-serif' }}>
            {/* Bandeau supérieur couleur */}
            <div style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '7.5cqw', backgroundColor: textThemeColor }}></div>

            {/* Zone de contenu principale */}
            <div style={{ position: 'absolute', top: '7.5cqw', bottom: chantier.hasNoAds ? 0 : '7.5cqw', left: 0, right: 0, display: 'flex' }}>
                
                {/* Colonne Gauche (QR Code) */}
                <div style={{ width: '40%', padding: '6cqw', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', borderRight: '2px solid #e2e8f0' }}>
                    <div style={{ width: '100%', aspectRatio: '1/1', padding: '3cqw', backgroundColor: 'white', border: '0.5cqw solid #e2e8f0', borderRadius: '1.5cqw', boxShadow: '0 1cqw 3cqw rgba(0,0,0,0.05)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                        <NativeQRCode value={`https://eco-panneau.fr/?scan=${chantier.id}`} size="100%" padding={0} />
                    </div>
                    <p style={{ marginTop: '4cqw', textAlign: 'center', fontSize: '2.5cqw', fontWeight: 900, textTransform: 'uppercase', color: '#1e293b', lineHeight: 1.4 }}>
                        Scannez pour les informations légales et utiles
                    </p>
                </div>

                {/* Colonne Droite (Textes) */}
                <div style={{ width: '60%', padding: '6cqw', display: 'flex', flexDirection: 'column' }}>
                    <div style={{ fontSize: '2.5cqw', fontWeight: 900, color: textThemeColor, textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: '1cqw' }}>
                        Panneau d'affichage légal
                    </div>
                    <h2 style={{ fontSize: '6cqw', fontWeight: 900, color: '#0f172a', lineHeight: 1.1, display: '-webkit-box', WebkitLineClamp: 3, WebkitBoxOrient: 'vertical', overflow: 'hidden' }}>
                        {chantier.name}
                    </h2>
                    <p style={{ fontSize: '3cqw', fontWeight: 600, color: '#475569', marginTop: '2cqw', lineHeight: 1.3, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' }}>
                        {chantier.location}
                    </p>

                    <div style={{ flex: 1 }}></div>

                    {/* Bloc Maître d'ouvrage & Permis */}
                    <div style={{ display: 'flex', flexDirection: 'column', gap: '3cqw' }}>
                        {(chantier.maitreOuvrage || chantier.clientName) && (
                            <div style={{ backgroundColor: '#f8fafc', border: '0.3cqw solid #e2e8f0', borderRadius: '1cqw', padding: '2.5cqw' }}>
                                <p style={{ fontSize: '1.5cqw', fontWeight: 900, color: '#64748b', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: '1cqw' }}>Maître d'ouvrage</p>
                                <div style={{ display: 'flex', alignItems: 'center', gap: '2cqw' }}>
                                    {displayMoaLogoUrl && <img src={displayMoaLogoUrl} alt="MOA" style={{ height: '6cqw', objectFit: 'contain', mixBlendMode: 'multiply' }} />}
                                    <p style={{ fontSize: '3.5cqw', fontWeight: 900, color: '#1e293b', lineHeight: 1.1, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' }}>
                                        {chantier.maitreOuvrage || chantier.clientName}
                                    </p>
                                </div>
                            </div>
                        )}

                        {chantier.permitNumber && (
                            <div style={{ display: 'flex', alignItems: 'center', gap: '2cqw', marginTop: '1cqw' }}>
                                <p style={{ fontSize: '2cqw', fontWeight: 800, color: '#94a3b8', textTransform: 'uppercase', letterSpacing: '0.05em' }}>Permis N°</p>
                                <p style={{ fontSize: '4.5cqw', fontWeight: 900, color: '#1e293b', fontFamily: 'monospace' }}>{chantier.permitNumber}</p>
                            </div>
                        )}
                    </div>
                </div>
            </div>

            {/* Bandeau inférieur (Sponsor) */}
            {!chantier.hasNoAds && (
                <div style={{ position: 'absolute', bottom: 0, left: 0, width: '100%', height: '7.5cqw', backgroundColor: '#0f172a', borderTop: '0.8cqw solid #10b981', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '0 4cqw', gap: '1.5cqw' }}>
                    <div style={{ fontSize: '2cqw', fontWeight: 900, letterSpacing: '-0.05em', display: 'flex', gap: '0.5cqw' }}>
                        <span style={{ color: '#34d399' }}>eco</span><span style={{ color: 'white' }}>-panneau</span><span style={{ color: '#94a3b8' }}>.fr</span>
                    </div>
                    <span style={{ color: '#475569', fontSize: '2cqw' }}>|</span>
                    <p style={{ fontSize: '1.6cqw', color: '#cbd5e1', fontWeight: 500, whiteSpace: 'nowrap' }}>
                        Professionnels du BTP : digitalisez vos obligations sur <strong style={{ color: 'white' }}>eco-panneau.fr</strong>
                    </p>
                </div>
            )}
        </div>
    );
};

// =========================================================================
// 5. COMPOSANTS DE L'INTERFACE UTILISATEUR
// =========================================================================

const SiteLogo = ({ className = "text-xl", qrSize = 24, onClick, theme = "light" }) => (
  <a href="?" onClick={(e) => { if(onClick) { e.preventDefault(); onClick(); } }} className={`flex items-center gap-2 font-black tracking-tight ${className}`} title="Retour à l'accueil">
    <svg width={qrSize} height={qrSize} viewBox="0 0 100 100" className={`shrink-0 ${theme === 'dark' ? 'opacity-90' : ''}`}>
        <rect width="100" height="100" rx="20" fill={theme === 'dark' ? "#ffffff" : "#1e293b"} />
        <rect x="12" y="12" width="30" height="30" rx="8" stroke={theme === 'dark' ? "#1e293b" : "#ffffff"} strokeWidth="6" fill="none"/>
        <rect x="21" y="21" width="12" height="12" rx="3" fill={theme === 'dark' ? "#1e293b" : "#ffffff"}/>
        <rect x="12" y="58" width="30" height="30" rx="8" stroke={theme === 'dark' ? "#1e293b" : "#ffffff"} strokeWidth="6" fill="none"/>
        <rect x="21" y="67" width="12" height="12" rx="3" fill={theme === 'dark' ? "#1e293b" : "#ffffff"}/>
        <rect x="58" y="58" width="30" height="30" rx="8" stroke={theme === 'dark' ? "#1e293b" : "#ffffff"} strokeWidth="6" fill="none"/>
        <rect x="67" y="67" width="12" height="12" rx="3" fill={theme === 'dark' ? "#1e293b" : "#ffffff"}/>
        <path d="M 88 12 C 58 12 58 42 58 42 C 88 42 88 12 88 12 Z" fill="#a7f3d0" stroke="none"/>
        <path d="M 88 12 C 58 12 58 42 58 42 C 88 42 88 12 88 12 Z" fill="none" stroke="#059669" strokeWidth="6" strokeLinejoin="round" strokeLinecap="round"/>
        <line x1="48" y1="52" x2="60" y2="40" stroke="#059669" strokeWidth="6" strokeLinecap="round" />
        <path d="M 60 40 L 85 15 M 66 34 L 66 23 M 74 26 L 83 26" stroke="#059669" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" />
    </svg>
    <span className="flex">
        <span className={theme === 'dark' ? 'text-emerald-400' : 'text-emerald-600'}>eco</span>
        <span className={theme === 'dark' ? 'text-white' : 'text-slate-800'}>-panneau</span>
        <span className="text-slate-400">.fr</span>
    </span>
  </a>
);

// Modale floutée globale avec fermeture au clic externe
const Modal = ({ title, onClose, children, preventClose }) => (
    <div className="fixed inset-0 bg-slate-900/80 z-[200] flex items-center justify-center p-3 backdrop-blur-md animate-in fade-in duration-300" onMouseDown={!preventClose ? onClose : undefined}>
        <div className="bg-white rounded-[2rem] shadow-2xl w-full max-w-xl flex flex-col max-h-[90vh] overflow-hidden" onMouseDown={e => e.stopPropagation()}>
            <div className="px-8 py-6 border-b border-slate-50 flex justify-between items-center bg-slate-50/50 shrink-0">
                <h3 className="font-black text-slate-800 text-lg uppercase tracking-widest">{title}</h3>
                {!preventClose && <button onClick={onClose} title="Fermer la fenêtre" className="text-slate-400 hover:text-slate-600 bg-white shadow-sm border border-slate-100 rounded-xl p-2 transition"><X size={20} /></button>}
            </div>
            <div className="p-4 sm:p-8 overflow-y-auto custom-scrollbar flex-1 pb-8">
                {children}
            </div>
        </div>
    </div>
);

const DashboardLayout = ({ children, role, user, theme, navItems, activeTab, setActiveTab, onLogout, customLogout, sidebarFooter }) => {
  const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
  const themeColors = { emerald: 'bg-emerald-600', purple: 'bg-slate-900' };
  const colorClass = themeColors[theme] || 'bg-slate-800';

  useEffect(() => {
      const url = new URL(window.location);
      if (url.searchParams.get('tab') !== activeTab) {
          url.searchParams.set('tab', activeTab);
          window.history.pushState({}, '', url);
      }
  }, [activeTab]);

  useEffect(() => {
      const handlePopState = () => {
          const url = new URL(window.location);
          const tab = url.searchParams.get('tab');
          if (tab && tab !== activeTab) { setActiveTab(tab); }
      };
      window.addEventListener('popstate', handlePopState);
      handlePopState(); 
      return () => window.removeEventListener('popstate', handlePopState);
  }, []);

  return (
    <div className="flex h-full bg-slate-50 relative">
      <div className="md:hidden absolute top-0 left-0 right-0 h-14 bg-white border-b border-slate-200 flex items-center px-4 justify-between z-[40] shadow-sm"><SiteLogo className="text-lg" qrSize={20} onClick={() => { setActiveTab('dashboard'); setIsMobileMenuOpen(false); }} /><button title="Ouvrir le menu" className="text-slate-600 p-1" onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}><Menu size={24}/></button></div>
      {isMobileMenuOpen && (<div className="md:hidden fixed inset-0 bg-slate-900/50 z-[45] backdrop-blur-sm" onClick={() => setIsMobileMenuOpen(false)}></div>)}
      <aside className={`fixed md:static inset-y-0 left-0 w-64 bg-white border-r border-slate-200 flex flex-col z-[50] transform transition-transform duration-300 ease-in-out ${isMobileMenuOpen ? 'translate-x-0' : '-translate-x-full md:translate-x-0'}`}>
        <div className="h-14 md:h-16 flex items-center justify-between px-6 border-b border-slate-100 shrink-0 bg-white"><SiteLogo className="text-lg" qrSize={20} onClick={() => setActiveTab('dashboard')} /><button title="Fermer le menu" className="md:hidden text-slate-400" onClick={() => setIsMobileMenuOpen(false)}><X size={20}/></button></div>
        <div className="p-4 flex-1 overflow-y-auto">
            <div className={`${colorClass} rounded-2xl p-5 text-white shadow-xl mb-6`}><p className="text-[10px] font-black opacity-80 uppercase tracking-widest mb-1">{role}</p><p className="font-bold text-base truncate" title={user}>{user}</p></div>
            <nav className="space-y-1.5">
              {navItems.map(item => (
                <button key={item.id} title={item.label} onClick={() => { setActiveTab(item.id); setIsMobileMenuOpen(false); }} className={`w-full flex items-center justify-between px-4 py-3 rounded-xl font-black text-xs uppercase tracking-wider transition ${activeTab === item.id ? 'bg-slate-100 text-slate-900' : 'text-slate-500 hover:bg-slate-50 hover:text-slate-700'}`}>
                  <div className="flex items-center gap-3">
                      <div className="shrink-0">{item.icon}</div>
                      <div className="text-left leading-snug break-words">{item.label}</div>
                  </div>
                  {item.badge > 0 && <span className="bg-red-500 text-white text-[10px] px-2 py-0.5 rounded-full shrink-0">{item.badge}</span>}
                </button>
              ))}
            </nav>
        </div>
        <div className="p-6 border-t border-slate-100 shrink-0 flex flex-col gap-3 bg-slate-50/50">
            {sidebarFooter}
            {customLogout ? (
                <button onClick={customLogout.action} title={customLogout.label} className="w-full bg-slate-900 text-white font-bold text-sm py-3 rounded-xl flex items-center justify-center gap-2 transition shadow-xl hover:-translate-y-1">{customLogout.icon} {customLogout.label}</button>
            ) : (
                <button onClick={onLogout} title="Déconnexion" className="w-full bg-red-50 text-red-600 border border-red-200 hover:bg-red-100 hover:text-red-700 font-bold text-sm py-3 rounded-xl flex items-center justify-center gap-2 transition shadow-sm"><LogOut size={18}/> Déconnexion</button>
            )}
        </div>
      </aside>
      <main className="flex-1 min-w-0 overflow-y-auto p-4 pt-20 md:p-10 md:pt-10 w-full"><div className="max-w-6xl mx-auto pb-20">{children}</div></main>
    </div>
  );
};

const StatCard = ({ title, value, icon, color, bg, onClick }) => (
    <div onClick={onClick} title={title} className={`p-6 rounded-3xl border border-slate-200 flex items-center gap-4 bg-white shadow-sm transition ${onClick ? 'cursor-pointer hover:shadow-md hover:border-slate-300' : ''}`}>
        <div className={`w-14 h-14 rounded-2xl flex items-center justify-center shrink-0 ${bg} ${color}`}>{icon}</div>
        <div><p className="text-xs font-bold text-slate-500 uppercase tracking-widest">{title}</p><p className={`text-2xl font-black mt-1 ${color}`}>{value}</p></div>
    </div>
);

const PriceInput = ({ label, value, onChange }) => (
    <div className="space-y-1"><label className="text-[10px] font-bold text-slate-500 uppercase tracking-wider">{label}</label><div className="relative"><input type="number" min="0" value={value} onChange={e=>onChange(Number(e.target.value))} className="w-full border border-slate-200 rounded-lg p-2 text-sm pr-8 focus:border-slate-400 outline-none" /><span className="absolute right-3 top-2 text-slate-400 text-sm">€</span></div></div>
);

// =========================================================================
// 6. COMPOSANTS MÉTIER : MESSAGERIE ET FORMULAIRES
// =========================================================================

const ChatBox = ({ messages, currentUserRole, chantierId, refreshData, onSend }) => {
    const endRef = useRef(null);
    const [draft, setDraft] = useState('');
    const [sending, setSending] = useState(false);

    useEffect(() => { 
        endRef.current?.scrollIntoView({ behavior: 'smooth' }); 
        const authorRole = currentUserRole === 'admin' ? 'Admin' : 'Client';
        const checkAuthor = (a) => a === authorRole;
        const unread = messages.filter(m => !m.resolved && !checkAuthor(m.author));
        
        if (unread.length > 0) { 
            fetch(window.ECO_CONFIG.apiBaseUrl + 'interactions/read', { method: 'POST', body: JSON.stringify({ chantierId, author: authorRole }) }).then(() => { if(refreshData) refreshData(); }); 
            
            if (window.Notification && Notification.permission === 'granted' && localStorage.getItem('eco_push_enabled') === 'true') {
                const latestMsgId = unread[0].id || unread[0].created_at; 
                const lastNotified = sessionStorage.getItem('last_notified_msg_' + chantierId);
                
                if (lastNotified !== latestMsgId) {
                    new Notification("eco-panneau.fr", { 
                        body: "Nouveau message reçu.",
                        icon: "/favicon.svg"
                    });
                    sessionStorage.setItem('last_notified_msg_' + chantierId, latestMsgId);
                }
            }
        }
    }, [messages, chantierId, currentUserRole]);

    const handleSend = async (e) => {
        e.preventDefault(); if(!draft.trim()) return;
        setSending(true);
        if (onSend) await onSend(draft.trim());
        setDraft(''); setSending(false);
    };

    return (
        <div className="flex flex-col h-full bg-slate-50">
            <div className="flex-1 overflow-y-auto p-4 space-y-4 custom-scrollbar">
                {[...messages].reverse().map((msg, idx) => {
                    const isMe = (currentUserRole === 'admin' && msg.author === 'Admin') || (currentUserRole === 'client' && msg.author === 'Client') || (currentUserRole === 'public' && msg.author === 'Riverain');
                    return (
                        <div key={idx} className={`flex flex-col ${isMe ? 'items-end' : 'items-start'}`}>
                            <div className={`max-w-[85%] sm:max-w-[70%] p-3 rounded-2xl ${isMe ? 'bg-emerald-600 text-white rounded-br-sm' : 'bg-white border border-slate-200 text-slate-700 rounded-bl-sm shadow-sm'}`}>
                                <p className="text-sm leading-relaxed whitespace-pre-wrap">{msg.detail}</p>
                            </div>
                            <span className="text-[10px] font-bold text-slate-400 mt-1 px-1">{msg.author} • {new Date(msg.created_at).toLocaleString('fr-FR')}</span>
                        </div>
                    );
                })}
                {messages.length === 0 && <div className="text-center text-slate-400 text-sm mt-10 font-medium italic">Aucun message.</div>}
                <div ref={endRef} />
            </div>
            <form onSubmit={handleSend} className="p-3 bg-white border-t border-slate-200 flex gap-2 shrink-0">
                <input value={draft} onChange={e=>setDraft(e.target.value)} placeholder="Écrire une réponse..." disabled={sending} className="flex-1 border-2 border-slate-100 rounded-xl px-4 py-2 outline-none focus:border-emerald-500 text-sm transition" />
                <button type="submit" disabled={sending||!draft.trim()} title="Envoyer le message" className="bg-emerald-600 text-white p-3 rounded-xl hover:bg-emerald-700 transition disabled:opacity-50 shadow-sm"><ArrowUp size={18} /></button>
            </form>
        </div>
    );
};

const PublicContactForm = ({ chantierId, showToast, onSuccess, isPreview, hideAlert = false }) => {
    const [submitting, setSubmitting] = useState(false);
    const [isAlert, setIsAlert] = useState(false);
    const [mountTime] = useState(Math.floor(Date.now() / 1000));

    return (
        <form onSubmit={async (e) => {
            e.preventDefault(); 
            if (isPreview) {
                if (showToast) showToast("Ceci est un aperçu interactif. La messagerie n'est pas fonctionnelle ici.", "info");
                return;
            }
            setSubmitting(true);
            
            const data = { 
                chantierId, 
                detail: e.target.detail.value, 
                author: e.target.email.value, 
                isAlert: isAlert ? 1 : 0, 
                hp_text: e.target.hp_text.value, 
                hp_time: e.target.hp_time.value 
            };
            
            try {
                await fetch(window.ECO_CONFIG.apiBaseUrl + 'interactions', { method: 'POST', body: JSON.stringify(data) });
                showToast("Message envoyé. Le responsable vous répondra par e-mail.", "success");
                e.target.reset(); setIsAlert(false); if(onSuccess) onSuccess();
            } catch(err) { showToast("Erreur d'envoi", "error"); }
            setSubmitting(false);
        }} className="space-y-3">
            
            <input type="text" name="hp_text" className="absolute opacity-0 -z-10 w-0 h-0" tabIndex="-1" autoComplete="off" />
            <input type="hidden" name="hp_time" value={mountTime} />

            <input name="email" type="email" required placeholder="Votre e-mail (pour recevoir la réponse)" className="w-full border-2 border-slate-200 rounded-xl p-3 text-sm outline-none focus:border-slate-800 transition" />
            <textarea name="detail" required rows="5" placeholder="Votre message..." className="w-full border-2 border-slate-200 rounded-xl p-3 text-sm outline-none focus:border-slate-800 transition resize-none"></textarea>
            
            {!hideAlert && (
                <label className="flex items-center gap-2 cursor-pointer p-2 border border-slate-200 rounded-lg hover:bg-slate-50 transition select-none mt-1">
                    <input type="checkbox" checked={isAlert} onChange={(e)=>setIsAlert(e.target.checked)} className="w-4 h-4 accent-red-500 shrink-0" />
                    <span className="text-[11px] font-bold text-slate-700 leading-tight">Signaler une urgence (nuisance grave, danger)</span>
                </label>
            )}
            
            <button type="submit" disabled={submitting} className="w-full bg-slate-900 text-white py-3 rounded-xl font-black uppercase tracking-widest text-xs hover:bg-slate-800 transition flex justify-center items-center gap-2 shadow-md disabled:opacity-50 mt-3">
                {submitting ? <Loader className="animate-spin w-4 h-4"/> : <MessageSquare size={14}/>} Envoyer
            </button>
        </form>
    );
};

// =========================================================================
// 7. ÉDITEUR DE PANNEAU ET GESTION DES ENTITÉS
// =========================================================================

const EntityCard = ({ data, type, index, lotIndex, onEdit, onDelete, onDragStart, onDragOver, onDrop }) => {
    const isLot = type === 'lot';
    const logoSrc = data.logoId ? `?api=file/download&type=image&id=${data.logoId}` : data.logoUrl;

    return (
        <div draggable onDragStart={(e) => onDragStart(e, {type, index, lotIndex})} onDragOver={onDragOver} onDrop={(e) => onDrop(e, {type, index, lotIndex})} className={`bg-white border rounded-xl p-3 flex flex-col gap-2 shadow-sm relative group transition hover:border-slate-300 ${isLot ? 'border-slate-300 mb-3' : 'border-slate-100'}`}>
            <div className="flex items-start justify-between cursor-move" title="Déplacer (Drag et Drop)">
                <div className="flex items-center gap-2 flex-1 min-w-0">
                    <GripVertical size={16} className="text-slate-300 group-hover:text-slate-500 shrink-0" />
                    {logoSrc && <img src={logoSrc} alt="logo" className="w-8 h-8 object-contain rounded bg-slate-50 border p-0.5 shrink-0" />}
                    <div className="min-w-0 flex-1">
                        <p className="font-bold text-xs text-slate-800 truncate">{data.name || 'Sans nom'}</p>
                        {!isLot && <p className="text-[10px] text-slate-500 truncate">{data.role || 'Rôle non défini'}</p>}
                    </div>
                </div>
                <div className="flex gap-1 shrink-0 ml-2">
                    <button type="button" onClick={() => onEdit({type, index, lotIndex}, data)} title="Modifier l'élément" className="p-1.5 text-slate-400 hover:text-blue-600 hover:bg-blue-50 rounded"><Edit size={14}/></button>
                    <button type="button" onClick={() => onDelete({type, index, lotIndex})} title="Supprimer cet élément" className="p-1.5 text-slate-400 hover:text-red-600 hover:bg-red-50 rounded"><Trash2 size={14}/></button>
                </div>
            </div>
            {isLot && (
                <div className="pl-6 pt-2 border-t border-slate-100 flex flex-col gap-2">
                    {data.entreprises?.map((ent, eIdx) => (
                        <EntityCard key={ent.id || eIdx} data={ent} type="entreprise" index={eIdx} lotIndex={index} onEdit={onEdit} onDelete={onDelete} onDragStart={onDragStart} onDragOver={onDragOver} onDrop={onDrop} />
                    ))}
                    <button type="button" onClick={() => onEdit({type: 'entreprise', lotIndex: index}, {name:'', role:'', description:'', phone:'', email:'', website:'', logoId:'', logoUrl:''})} className="text-[10px] font-bold text-slate-500 hover:text-slate-800 flex items-center gap-1 py-1.5 px-2 bg-slate-50 rounded-lg border border-dashed border-slate-300 w-fit transition"><Plus size={12}/> Ajouter une entreprise à ce lot</button>
                </div>
            )}
        </div>
    );
};

const EntityEditorModal = ({ editingEntity, setEditingEntity, saveEditedEntity }) => {
    const isLot = editingEntity.location.type === 'lot';
    const [uploadingLogo, setUploadingLogo] = useState(false);
    
    const updateField = (field, val) => setEditingEntity({ ...editingEntity, data: { ...editingEntity.data, [field]: val } });
    
    const handleLogoUpload = async (e) => {
        const file = e.target.files[0]; if(!file) return;
        setUploadingLogo(true);
        try {
            const id = await window.uploadFile(file, 'image');
            updateField('logoId', id); updateField('logoUrl', URL.createObjectURL(file));
        } catch(err) { alert(err.message); } finally { setUploadingLogo(false); }
    };

    const logoSrc = editingEntity.data.logoId ? `?api=file/download&type=image&id=${editingEntity.data.logoId}` : editingEntity.data.logoUrl;

    return (
        <Modal title={isLot ? "Édition du lot" : "Édition de l'intervenant"} onClose={() => setEditingEntity(null)} preventClose={uploadingLogo}>
            <div className="space-y-4">
                <div className="space-y-1"><label className="text-xs font-bold text-slate-500 uppercase block">{isLot ? 'Nom du lot' : 'Nom de la société / personne'}</label><input value={editingEntity.data.name || ''} maxLength="100" onChange={e=>updateField('name', e.target.value)} autoFocus className="w-full border-2 border-slate-200 rounded-xl p-3 text-sm focus:border-slate-800 outline-none transition" /></div>
                {!isLot && (
                    <>
                        <div className="space-y-1"><label className="text-xs font-bold text-slate-500 uppercase block">Rôle / mission</label><input value={editingEntity.data.role || ''} maxLength="100" onChange={e=>updateField('role', e.target.value)} className="w-full border-2 border-slate-200 rounded-xl p-3 text-sm focus:border-slate-800 outline-none transition" placeholder="Ex: Architecte D.P.L.G" /></div>
                        <div className="grid grid-cols-2 gap-4">
                            <div className="space-y-1"><label className="text-xs font-bold text-slate-500 uppercase block">Téléphone (optionnel)</label><input value={editingEntity.data.phone || ''} maxLength="30" onChange={e=>updateField('phone', e.target.value)} className="w-full border-2 border-slate-200 rounded-xl p-3 text-sm focus:border-slate-800 outline-none transition" /></div>
                            <div className="space-y-1"><label className="text-xs font-bold text-slate-500 uppercase block">E-mail (optionnel)</label><input value={editingEntity.data.email || ''} maxLength="100" onChange={e=>updateField('email', e.target.value)} className="w-full border-2 border-slate-200 rounded-xl p-3 text-sm focus:border-slate-800 outline-none transition" /></div>
                        </div>
                        <div className="space-y-1">
                            <label className="text-xs font-bold text-slate-500 uppercase block">Logo (optionnel)</label>
                            <div className="flex items-center gap-4">
                                {logoSrc && <img src={logoSrc} className="w-16 h-16 object-contain rounded-lg border p-1 bg-white" alt="logo" />}
                                <label className="bg-slate-100 hover:bg-slate-200 text-slate-700 px-4 py-2 rounded-xl text-xs font-bold cursor-pointer transition border border-slate-200 flex items-center gap-2">
                                    {uploadingLogo ? <Loader size={14} className="animate-spin"/> : <Image size={14}/>} Changer le logo
                                    <input type="file" accept="image/png, image/jpeg, image/webp" className="hidden" disabled={uploadingLogo} onChange={handleLogoUpload} />
                                </label>
                                {logoSrc && <button onClick={() => {updateField('logoId',''); updateField('logoUrl','');}} title="Supprimer le logo" className="text-xs text-red-500 font-bold">Supprimer</button>}
                            </div>
                        </div>
                    </>
                )}
                <button onClick={saveEditedEntity} disabled={uploadingLogo || !editingEntity.data.name?.trim()} className="w-full bg-slate-900 text-white py-3 rounded-xl font-bold uppercase tracking-widest hover:bg-slate-800 transition shadow-md mt-6 disabled:opacity-50">Valider</button>
            </div>
        </Modal>
    );
};

const ChantierEditorForm = ({ chantier, setChantier, managingChantier, onCancel, onSaveDraft, onPublish, onSaveActive, onPreview, onEditEntity, draggedItem, handleDragStart, handleDragOver, handleDrop, deleteEntity, isSaving, uiMode = 'simplifie', validationErrors = [], settings = {} }) => {
    const [touched, setTouched] = useState({});
    const [uploadingStates, setUploadingStates] = useState({ image: false, pdf: false, moaLogo: false });

    const updateField = (field, val) => setChantier(prev => ({ ...prev, [field]: val }));
    const handleBlur = (field) => setTouched(prev => ({ ...prev, [field]: true }));
    const isError = (field) => validationErrors.length > 0 && (!chantier[field] || String(chantier[field]).trim() === '');

    const handleImageUpload = async (e) => {
        const file = e.target.files[0]; if(!file) return;
        setUploadingStates(p => ({...p, image: true}));
        try { const id = await window.uploadFile(file, 'image'); updateField('imageId', id); updateField('imageUrl', URL.createObjectURL(file)); setTouched(p => ({...p, imageId: true})); } 
        catch(err) { alert(err.message); } finally { setUploadingStates(p => ({...p, image: false})); e.target.value = null; }
    };
    const handlePdfUpload = async (e) => {
        const file = e.target.files[0]; if(!file) return;
        setUploadingStates(p => ({...p, pdf: true}));
        try { const id = await window.uploadFile(file, 'pdf'); updateField('pdfId', id); setTouched(p => ({...p, pdfId: true})); } 
        catch(err) { alert(err.message); } finally { setUploadingStates(p => ({...p, pdf: false})); e.target.value = null; }
    };
    const handleMoaLogoUpload = async (e) => {
        const file = e.target.files[0]; if(!file) return;
        setUploadingStates(p => ({...p, moaLogo: true}));
        try { const id = await window.uploadFile(file, 'image'); updateField('maitreOuvrageLogoId', id); updateField('maitreOuvrageLogoUrl', URL.createObjectURL(file)); setTouched(p => ({...p, moaLogo: true})); } 
        catch(err) { alert(err.message); } finally { setUploadingStates(p => ({...p, moaLogo: false})); e.target.value = null; }
    };

    const isUploading = Object.values(uploadingStates).some(v => v);
    const moaLogoSrc = chantier.maitreOuvrageLogoId ? `?api=file/download&type=image&id=${chantier.maitreOuvrageLogoId}` : chantier.maitreOuvrageLogoUrl;
    const mainImgSrc = chantier.imageId ? `?api=file/download&type=image&id=${chantier.imageId}` : chantier.imageUrl;

    const handleCancelClick = () => {
        if (Object.keys(touched).length > 0 && !isSaving) {
            if (confirm("Vous avez peut-être des modifications non sauvegardées. Êtes-vous sûr de vouloir annuler ?")) {
                onCancel();
            }
        } else {
            onCancel();
        }
    };

    const showOpt = (key) => {
        if (uiMode !== 'simplifie') return true;
        return settings?.[`simp_opt_${key}`] === '1';
    };

    return (
        <div className="flex flex-col h-full bg-white relative">
            <div className="flex-1 overflow-y-auto p-4 sm:p-8 custom-scrollbar pb-32 space-y-8">
                
                <div className="bg-slate-50 p-4 sm:p-6 rounded-2xl border border-slate-100 space-y-6 shadow-sm">
                    <h3 className="font-black text-slate-800 border-b pb-2 flex items-center gap-2"><MapPin size={18} className="text-emerald-600"/> Identité du panneau</h3>
                    
                    <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                        <div className="space-y-1">
                            <label className="text-xs font-bold text-slate-500 uppercase block">Nom du chantier *</label>
                            <input value={chantier.name || ''} maxLength="120" onChange={e=>updateField('name', e.target.value)} onBlur={() => handleBlur('name')} onFocus={(e) => setTimeout(() => e.target.scrollIntoView({ behavior: 'smooth', block: 'center' }), 300)} disabled={uiMode === 'delege' || (managingChantier?.status === 'Actif' && managingChantier?.offerType === 'purchase')} className={`w-full border-2 rounded-xl p-3 text-sm outline-none transition disabled:bg-slate-100 disabled:text-slate-400 disabled:cursor-not-allowed ${isError('name') ? 'border-red-500 bg-red-50' : 'border-slate-200 focus:border-emerald-500'}`} placeholder="Ex: Résidence Cambon" />
                        </div>
                        <div className="space-y-1">
                            <label className="text-xs font-bold text-slate-500 uppercase block">Ville / lieu *</label>
                            <input value={chantier.location || ''} maxLength="150" onChange={e=>updateField('location', e.target.value)} onBlur={() => handleBlur('location')} onFocus={(e) => setTimeout(() => e.target.scrollIntoView({ behavior: 'smooth', block: 'center' }), 300)} disabled={uiMode === 'delege' || (managingChantier?.status === 'Actif' && managingChantier?.offerType === 'purchase')} className={`w-full border-2 rounded-xl p-3 text-sm outline-none transition disabled:bg-slate-100 disabled:text-slate-400 disabled:cursor-not-allowed ${isError('location') ? 'border-red-500 bg-red-50' : 'border-slate-200 focus:border-emerald-500'}`} placeholder="Ex: Fréjus" />
                        </div>
                    </div>

                    <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                        <div className="space-y-1">
                            <label className="text-xs font-bold text-slate-500 uppercase block">Maître d'ouvrage (optionnel)</label>
                            <div className="flex gap-2">
                                <input value={chantier.maitreOuvrage || ''} maxLength="120" onChange={e=>{updateField('maitreOuvrage', e.target.value); handleBlur('maitreOuvrage');}} onFocus={(e) => setTimeout(() => e.target.scrollIntoView({ behavior: 'smooth', block: 'center' }), 300)} disabled={uiMode === 'delege'} className="flex-1 border-2 border-slate-200 rounded-xl p-3 text-sm focus:border-emerald-500 outline-none transition disabled:bg-slate-100 disabled:text-slate-400 disabled:cursor-not-allowed" placeholder="Société ou nom" />
                                {uiMode !== 'simplifie' && (
                                    <label className="h-[46px] bg-slate-100 border border-slate-200 text-slate-600 rounded-xl px-3 flex items-center justify-center cursor-pointer hover:bg-slate-200 transition shrink-0" title="Ajouter un logo pour le maître d'ouvrage">
                                        {uploadingStates.moaLogo ? <Loader size={16} className="animate-spin" /> : <><Image size={16} className="sm:mr-1" /><span className="hidden sm:block text-xs font-bold">Logo</span></>}
                                        <input type="file" accept="image/png, image/jpeg, image/webp" className="hidden" disabled={uploadingStates.moaLogo} onChange={handleMoaLogoUpload} />
                                    </label>
                                )}
                            </div>
                            {moaLogoSrc && (
                                <div className="flex items-center gap-2 mt-2 bg-white p-2 rounded-xl border border-slate-200 w-fit shadow-sm">
                                    <img src={moaLogoSrc} alt="Logo MOA" className="h-8 object-contain" />
                                    <button type="button" onClick={() => {updateField('maitreOuvrageLogoId',''); updateField('maitreOuvrageLogoUrl',''); setTouched(p => ({...p, moaLogo: true}));}} title="Supprimer le logo" className="text-red-500 hover:text-red-700 p-1"><Trash2 size={14}/></button>
                                </div>
                            )}
                        </div>
                        <div className="space-y-1">
                            <label className="text-xs font-bold text-slate-500 uppercase block">N° permis / DP (optionnel)</label>
                            <input value={chantier.permitNumber || ''} maxLength="50" onChange={e=>{updateField('permitNumber', e.target.value); handleBlur('permitNumber');}} onFocus={(e) => setTimeout(() => e.target.scrollIntoView({ behavior: 'smooth', block: 'center' }), 300)} disabled={uiMode === 'delege'} className="w-full border-2 border-slate-200 rounded-xl p-3 text-sm focus:border-emerald-500 outline-none transition uppercase disabled:bg-slate-100 disabled:text-slate-400 disabled:cursor-not-allowed" placeholder="PC 000 000 00 00000" />
                        </div>
                    </div>
                </div>

                <div className={`p-4 rounded-2xl border space-y-4 shadow-sm ${(!chantier.pdfId && validationErrors.length > 0) ? 'bg-red-50 border-red-200' : 'bg-blue-50 border-blue-100'}`}>
                    <h3 className={`font-black flex items-center gap-2 ${(!chantier.pdfId && validationErrors.length > 0) ? 'text-red-900' : 'text-blue-900'}`}><FileDigit size={18}/> Arrêté légal (obligatoire)</h3>
                    <div className="space-y-1">
                        <label className="text-xs font-bold text-slate-500 uppercase block flex items-center gap-1">Permis de construire (PDF - max 5 Mo)</label>
                        <input type="file" accept="application/pdf" disabled={uploadingStates.pdf} onChange={handlePdfUpload} className={`w-full text-xs file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-xs file:font-bold file:bg-white cursor-pointer ${(!chantier.pdfId && validationErrors.length > 0) ? 'file:text-red-700 hover:file:bg-red-100' : 'file:text-blue-700 hover:file:bg-blue-100'}`} />
                        {uploadingStates.pdf && <p className="text-xs text-blue-600 font-bold flex items-center gap-1 mt-2"><Loader size={12} className="animate-spin"/> Upload en cours...</p>}
                        {chantier.pdfId && !uploadingStates.pdf && (
                            <div className="flex items-center gap-2 mt-2 bg-white p-2 rounded-xl border border-blue-200 shadow-sm w-fit">
                                <span className="text-xs text-emerald-600 font-bold flex items-center gap-1 px-2"><Check size={14}/> PDF actif</span>
                                <button type="button" onClick={() => {updateField('pdfId', ''); setTouched(p => ({...p, pdfId: true}));}} className="text-xs text-red-500 hover:text-red-700 font-bold px-2 border-l" title="Supprimer le PDF">Supprimer</button>
                            </div>
                        )}
                    </div>
                </div>

                {(showOpt('description') || showOpt('image') || showOpt('theme') || showOpt('link') || showOpt('emergency') || showOpt('schedule')) && uiMode !== 'delege' && (
                    <div className="bg-slate-50 p-4 sm:p-6 rounded-2xl border border-slate-100 space-y-6 shadow-sm">
                        <h3 className="font-black text-slate-800 border-b pb-2 flex items-center gap-2"><Settings size={18} className="text-emerald-600"/> Options avancées</h3>
                        
                        {showOpt('description') && <div className="space-y-1"><label className="text-xs font-bold text-slate-500 uppercase block">Description des travaux (optionnel)</label><textarea value={chantier.description || ''} maxLength="800" onChange={e=>{updateField('description', e.target.value); handleBlur('description');}} onFocus={(e) => setTimeout(() => e.target.scrollIntoView({ behavior: 'smooth', block: 'center' }), 300)} disabled={uiMode === 'delege'} className="w-full border-2 border-slate-200 rounded-xl p-3 text-sm focus:border-emerald-500 outline-none transition resize-none disabled:bg-slate-100 disabled:text-slate-400 disabled:cursor-not-allowed" placeholder="Ex: Rénovation de la façade et isolation thermique" /></div>}
                        
                        <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
                            {showOpt('image') && (
                                <div className="space-y-1">
                                    <label className="text-xs font-bold text-slate-500 uppercase block flex items-center gap-1">Image du panneau (max 5 Mo)</label>
                                    <input type="file" accept="image/png, image/jpeg, image/webp" disabled={uploadingStates.image} onChange={handleImageUpload} className="w-full text-xs file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-xs file:font-bold file:bg-emerald-50 file:text-emerald-700 hover:file:bg-emerald-100 cursor-pointer" />
                                    {uploadingStates.image && <p className="text-xs text-emerald-600 font-bold mt-2">Upload en cours...</p>}
                                    {mainImgSrc && !uploadingStates.image && (
                                        <div className="flex flex-col items-center justify-center mt-2 border p-2 rounded-xl bg-white shadow-sm w-fit">
                                            <img src={mainImgSrc} alt="Aperçu" className="h-16 object-contain mb-2 rounded" />
                                            <button type="button" onClick={() => {updateField('imageId', ''); updateField('imageUrl', ''); setTouched(p => ({...p, imageId: true}));}} className="text-xs text-red-500 font-bold" title="Supprimer l'image">Supprimer</button>
                                        </div>
                                    )}
                                </div>
                            )}
                            {showOpt('theme') && (
                                <div className="space-y-2">
                                    <label className="text-xs font-bold text-slate-500 uppercase block flex items-center gap-1"><Palette size={12} /> Couleur du thème</label>
                                    <div className={`flex flex-wrap gap-2 ${uiMode === 'delege' ? 'opacity-50 pointer-events-none' : ''}`}>
                                        {window.predefinedThemes.map(c => (<button key={c} type="button" onClick={() => {updateField('themeColor', c); handleBlur('themeColor');}} title={`Couleur ${c}`} className={`w-8 h-8 rounded-full border-2 transition-transform ${chantier.themeColor === c ? 'border-slate-800 scale-110' : 'border-white shadow-sm'}`} style={{backgroundColor: c}}></button>))}
                                    </div>
                                </div>
                            )}
                        </div>

                        <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
                            {showOpt('link') && <div className="space-y-1"><label className="text-xs font-bold text-slate-500 uppercase block flex items-center gap-1"><ExternalLink size={12}/> Lien promoteur</label><input value={chantier.promoterLink || ''} maxLength="255" onChange={e=>{updateField('promoterLink', e.target.value); handleBlur('promoterLink');}} onFocus={(e) => setTimeout(() => e.target.scrollIntoView({ behavior: 'smooth', block: 'center' }), 300)} className="w-full border-2 border-slate-200 rounded-xl p-3 text-sm focus:border-emerald-500 outline-none transition" /></div>}
                            {showOpt('emergency') && <div className="space-y-1"><label className="text-xs font-bold text-red-500 uppercase block flex items-center gap-1"><Phone size={12}/> N° d'urgence</label><input value={chantier.emergencyPhone || ''} maxLength="30" onChange={e=>{updateField('emergencyPhone', e.target.value); handleBlur('emergencyPhone');}} onFocus={(e) => setTimeout(() => e.target.scrollIntoView({ behavior: 'smooth', block: 'center' }), 300)} className="w-full border-2 border-red-200 rounded-xl p-3 text-sm outline-none focus:border-red-500 transition" placeholder="06XXXXXXXX" /></div>}
                        </div>
                        
                        {showOpt('schedule') && <div className="space-y-1"><label className="text-xs font-bold text-slate-500 uppercase block flex items-center gap-1"><Clock size={12}/> Horaires des nuisances sonores autorisés</label><input value={chantier.noiseSchedule || ''} maxLength="100" onChange={e=>{updateField('noiseSchedule', e.target.value); handleBlur('noiseSchedule');}} onFocus={(e) => setTimeout(() => e.target.scrollIntoView({ behavior: 'smooth', block: 'center' }), 300)} className="w-full border-2 border-slate-200 rounded-xl p-3 text-sm focus:border-emerald-500 outline-none transition" placeholder="8h à 17h" /></div>}
                    </div>
                )}

                {uiMode !== 'simplifie' && (
                    <div className="bg-slate-50 p-4 sm:p-6 rounded-2xl border border-slate-100 shadow-sm">
                        <div className="flex justify-between items-center mb-6 border-b pb-2">
                            <h3 className="font-black text-slate-800 flex items-center gap-2"><Users size={18} className="text-emerald-600"/> L'équipe du chantier</h3>
                        </div>
                        
                        <div className="space-y-6">
                            <div>
                                <h4 className="text-xs font-black text-slate-500 uppercase mb-3 tracking-wider">Intervenants principaux</h4>
                                <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
                                    {chantier.intervenants?.map((inter, idx) => (
                                        <EntityCard key={inter.id || idx} data={inter} type="intervenant" index={idx} onEdit={onEditEntity} onDelete={(loc) => {deleteEntity(loc); handleBlur('intervenants');}} onDragStart={handleDragStart} onDragOver={handleDragOver} onDrop={(e, loc) => {handleDrop(e, loc); handleBlur('intervenants');}} />
                                    ))}
                                </div>
                                <button type="button" onClick={() => onEditEntity({type: 'intervenant'}, {name:'', role:'', description:'', phone:'', email:'', website:'', logoId:'', logoUrl:''})} className="mt-3 text-xs font-bold text-emerald-600 hover:text-emerald-800 flex items-center gap-1 py-2 px-3 bg-emerald-50 rounded-lg transition border border-emerald-200 shadow-sm"><Plus size={14}/> Ajouter un intervenant</button>
                            </div>
                            
                            <div className="border-t border-slate-200 pt-6">
                                <h4 className="text-xs font-black text-slate-500 uppercase mb-3 tracking-wider">Sous-traitants par lots</h4>
                                <div className="space-y-4">
                                    {chantier.lots?.map((lot, lIdx) => (
                                        <EntityCard key={lot.id || lIdx} data={lot} type="lot" index={lIdx} onEdit={onEditEntity} onDelete={(loc) => {deleteEntity(loc); handleBlur('lots');}} onDragStart={handleDragStart} onDragOver={handleDragOver} onDrop={(e, loc) => {handleDrop(e, loc); handleBlur('lots');}} />
                                    ))}
                                </div>
                                <button type="button" onClick={() => onEditEntity({type: 'lot'}, {name:'', entreprises:[]})} className="mt-3 text-xs font-bold text-blue-600 hover:text-blue-800 flex items-center gap-1 py-2 px-3 bg-blue-50 rounded-lg transition border border-blue-200 shadow-sm"><Plus size={14}/> Créer un nouveau lot</button>
                            </div>
                        </div>
                    </div>
                )}

            </div>

            <div className="shrink-0 p-4 bg-white border-t border-slate-200 flex justify-between gap-4 z-10 shadow-[0_-10px_20px_-10px_rgba(0,0,0,0.05)]">
                <button id="editor-cancel-btn" type="button" onClick={handleCancelClick} disabled={isSaving || isUploading} title="Annuler les modifications" className="px-4 sm:px-6 py-3 rounded-xl font-bold text-slate-500 hover:bg-slate-100 transition disabled:opacity-50">Annuler</button>
                <div className="flex gap-2 w-full justify-end">
                    {onPreview && (
                        <button type="button" onClick={onPreview} disabled={isSaving || isUploading} title="Aperçu du panneau" className="hidden sm:flex bg-blue-50 text-blue-700 py-3 px-6 rounded-xl font-black uppercase tracking-widest hover:bg-blue-100 transition disabled:opacity-50 items-center gap-2">
                            <Eye size={18}/> Aperçu
                        </button>
                    )}
                    {onSaveDraft && (
                        <button type="button" onClick={onSaveDraft} disabled={isSaving || isUploading} title="Enregistrer en tant que brouillon (hors ligne)" className="bg-slate-100 text-slate-600 py-3 px-4 sm:px-6 rounded-xl font-black uppercase tracking-widest hover:bg-slate-200 transition disabled:opacity-50 flex items-center gap-2">
                            {isSaving ? <Loader className="animate-spin w-5 h-5"/> : 'Enregistrer (brouillon)'}
                        </button>
                    )}
                    {(onPublish || onSaveActive) && (
                        <button type="button" onClick={onPublish || onSaveActive} disabled={isSaving || isUploading} title="Publier ce panneau et le rendre visible" className="bg-emerald-600 text-white py-3 px-4 sm:px-8 rounded-xl font-black uppercase tracking-widest hover:bg-emerald-700 transition shadow-lg disabled:opacity-50 flex items-center justify-center gap-2">
                            {isSaving ? <Loader className="animate-spin w-5 h-5"/> : (managingChantier?.status === 'Actif' ? 'Publier (Actif)' : 'Publier')}
                        </button>
                    )}
                </div>
            </div>
        </div>
    );
};

const PreviewModal = ({ chantier, onClose, initialType = 'virtual', showToast, interactions = [], refreshData }) => {
    const [viewType, setViewType] = useState(initialType);
    const [generatingA1, setGeneratingA1] = useState(false);
    return (
        <div className="fixed inset-0 bg-slate-900/90 z-[300] flex items-center justify-center p-2 sm:p-4 backdrop-blur-md animate-in fade-in" onMouseDown={onClose}>
            <div className="bg-slate-100 rounded-3xl w-full max-w-5xl h-[95vh] flex flex-col shadow-2xl overflow-hidden border border-slate-200" onMouseDown={e => e.stopPropagation()}>
                <div className="p-4 bg-white border-b flex justify-between items-center shrink-0">
                    <div className="flex bg-slate-100 p-1 rounded-xl">
                        <button onClick={()=>setViewType('virtual')} title="Aperçu smartphone" className={`px-4 py-2 rounded-lg text-xs font-bold transition flex items-center gap-2 ${viewType === 'virtual' ? 'bg-white shadow-sm text-slate-900' : 'text-slate-500 hover:text-slate-700'}`}><Smartphone size={14}/> Virtuel</button>
                        <button onClick={()=>setViewType('physical')} title="Aperçu panneau physique" className={`px-4 py-2 rounded-lg text-xs font-bold transition flex items-center gap-2 ${viewType === 'physical' ? 'bg-white shadow-sm text-slate-900' : 'text-slate-500 hover:text-slate-700'}`}><HardHat size={14}/> Panneau A1</button>
                    </div>
                    <button onClick={onClose} title="Fermer l'aperçu" className="p-2 hover:bg-slate-100 rounded-xl text-slate-500 transition"><X size={20}/></button>
                </div>
                <div className="flex-1 overflow-auto flex items-center justify-center p-4 relative bg-slate-200/50">
                    {viewType === 'virtual' ? (
                        <div className="w-[375px] h-[812px] bg-white rounded-[3rem] shadow-2xl border-[8px] border-slate-900 overflow-hidden relative shrink-0 scale-[0.8] sm:scale-100 origin-top">
                            <div className="absolute top-0 inset-x-0 h-6 bg-slate-900 rounded-b-3xl w-40 mx-auto z-50"></div>
                            <div className="h-full w-full overflow-y-auto custom-scrollbar relative"><window.RiverainView chantier={{...chantier, id: 'demo-chantier'}} showToast={showToast} interactions={interactions} refreshData={refreshData} isPreview={true} /></div>
                        </div>
                    ) : (
                        <div className="w-full h-full flex flex-col items-center justify-center gap-6">
                            <div className="w-full max-w-3xl bg-white shadow-2xl border border-slate-200 shrink-0 pointer-events-none">
                                <window.PrintA1View chantier={chantier} />
                            </div>
                            <button onClick={async () => {
                                setGeneratingA1(true);
                                try { const blob = await window.generateA1PDF(chantier); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `panneau_A1.pdf`; link.click(); } catch(e) { showToast("Erreur PDF", "error"); }
                                setGeneratingA1(false);
                            }} disabled={generatingA1} title="Générer et télécharger le PDF haute définition" className="bg-slate-900 text-white px-6 py-3 rounded-xl font-bold flex items-center gap-2 shadow-lg hover:bg-slate-800 disabled:opacity-50 z-10">{generatingA1 ? <Loader className="animate-spin" size={16}/> : <Download size={16}/>} Télécharger le PDF A1 haute définition</button>
                        </div>
                    )}
                </div>
            </div>
        </div>
    );
};

// =========================================================================
// 8. REGISTRE GLOBAL
// =========================================================================

Object.assign(window, Icons);
Object.assign(window, {
  DashboardLayout, StatCard, PriceInput, Modal,
  ChatBox, PublicContactForm, EntityCard, EntityEditorModal,
  ChantierEditorForm, PreviewModal
});

/* EOF ===== [_soclecommun.jsx] =============== */