/**
 * =========================================================================
 * PLATEFORME ECO-PANNEAU.FR - VERSION 1.0.0
 * Point d'entrée React (Main) - Routage, Authentification, et État Global
 * =========================================================================
 */

const { useState, useEffect, useCallback } = React;

const SafeIcon = (FallbackText) => window[FallbackText] || (({className}) => <span className={className}>{FallbackText}</span>);

const Loader = SafeIcon('Loader');
const AlertTriangle = SafeIcon('AlertTriangle');
const CheckCircle = SafeIcon('CheckCircle');
const Info = SafeIcon('Info');
const Lock = SafeIcon('Lock');
const Mail = SafeIcon('Mail');
const Building = SafeIcon('Building');
const KeyRound = SafeIcon('KeyRound');
const Shield = SafeIcon('Shield');
const X = SafeIcon('X');

const getPublicView = () => window.AccueilView || null;
const getRiverainView = () => window.RiverainView || null;
const getAdminView = () => window.AdminView || null;
const getClientView = () => window.ClientView || null;
const getPanneauEditor = () => window.PanneauEditorForm || null;
const getEntityEditor = () => window.EntityEditorModal || null;

const FallbackError = ({ name }) => (
    <div className="p-10 m-10 border-2 border-red-500 bg-red-50 text-red-700 rounded-2xl font-bold text-center shadow-lg">
        <AlertTriangle className="mx-auto mb-2 w-8 h-8" />
        Erreur d'affichage : Le composant "{name}" est introuvable. 
        <div className="text-sm font-normal mt-2">Vérifiez que le fichier de la vue a été correctement chargé.</div>
    </div>
);

const DelegateView = ({ token, showToast }) => {
    const [panneau, setPanneau] = useState(null);
    const [loading, setLoading] = useState(true);
    const [isSaving, setIsSaving] = useState(false);
    const [error, setError] = useState(null);
    const [editingEntity, setEditingEntity] = useState(null);

    const PanneauEditor = getPanneauEditor();
    const EntityEditor = getEntityEditor();

    useEffect(() => {
        fetch(window.ECO_CONFIG.apiBaseUrl + 'panneaux/delegated_access&token=' + encodeURIComponent(token) + '&_t=' + Date.now())
            .then(r => r.json())
            .then(d => {
                if (d.status === 'success') {
                    setPanneau(d.data);
                } else {
                    setError(d.message);
                }
                setLoading(false);
            })
            .catch(() => {
                setError("Erreur réseau");
                setLoading(false);
            });
    }, [token]);

    const handleSave = async () => {
        setIsSaving(true);
        try {
            const res = await fetch(window.ECO_CONFIG.apiBaseUrl + 'panneaux/delegated_update', {
                method: 'POST',
                body: JSON.stringify({ token, ...panneau })
            });
            const d = await res.json();
            if (d.status === 'success') {
                showToast("Informations enregistrées avec succès.", "success");
            } else {
                showToast(d.message, 'error');
            }
        } catch (e) {
            showToast("Erreur lors de la sauvegarde.", "error");
        }
        setIsSaving(false);
    };

    if (loading) {
        return (
            <div className="h-screen flex flex-col items-center justify-center bg-slate-50">
                <Loader className="animate-spin text-emerald-600 mb-4 w-8 h-8" />
                <p className="font-bold text-slate-500 uppercase tracking-widest text-sm">Vérification de l'accès...</p>
            </div>
        );
    }

    if (error) {
        return (
            <div className="h-screen flex items-center justify-center bg-slate-50">
                <div className="bg-white p-8 rounded-3xl shadow-xl border border-red-200 text-center max-w-md">
                    <AlertTriangle className="w-12 h-12 text-red-500 mx-auto mb-4" />
                    <h2 className="text-xl font-black text-slate-800 mb-2">Accès refusé</h2>
                    <p className="text-slate-500">{error}</p>
                </div>
            </div>
        );
    }

    return (
        <div className="min-h-screen bg-slate-50 flex flex-col">
            <header className="bg-white border-b border-slate-200 py-4 px-6 flex justify-between items-center sticky top-0 z-50 shadow-sm">
                <div>
                    <h1 className="font-black text-xl text-slate-800 flex items-center gap-2">
                        <Shield className="w-6 h-6 text-blue-600"/> Saisie déléguée
                    </h1>
                    <p className="text-xs text-slate-500">Mise à jour des informations du panneau</p>
                </div>
                <button onClick={handleSave} disabled={isSaving} className="bg-blue-600 text-white px-6 py-2.5 rounded-xl font-bold hover:bg-blue-700 transition flex items-center gap-2 shadow-md disabled:opacity-50">
                    {isSaving ? <Loader className="animate-spin w-4 h-4"/> : <CheckCircle className="w-4 h-4"/>}
                    Enregistrer
                </button>
            </header>
            
            <main className="flex-1 max-w-4xl w-full mx-auto p-4 sm:p-8">
                <div className="bg-blue-50 border border-blue-200 rounded-2xl p-5 mb-8 text-blue-800 text-sm font-medium leading-relaxed">
                    Vous avez été invité à compléter les informations légales de ce panneau (intervenants, sous-traitants, PDF de l'arrêté). Vos modifications seront directement répercutées sur l'affichage public.
                </div>
                
                <div className="bg-white rounded-3xl shadow-xl overflow-hidden border border-slate-200 relative min-h-[500px]">
                    {PanneauEditor ? (
                        <PanneauEditor 
                            panneau={panneau} 
                            setPanneau={setPanneau} 
                            managingPanneau={panneau} 
                            onCancel={() => window.location.href = '?'} 
                            onPublish={handleSave} 
                            onEditEntity={(loc, data) => setEditingEntity({location: loc, data})}
                            deleteEntity={(loc) => {
                                if (!confirm("Supprimer cet élément ?")) return;
                                let newInter = [...(panneau.intervenants || [])];
                                let newLots = JSON.parse(JSON.stringify(panneau.lots || []));
                                
                                if (loc.type === 'intervenant') {
                                    newInter.splice(loc.index, 1);
                                } else if (loc.type === 'lot') {
                                    newLots.splice(loc.index, 1);
                                } else {
                                    newLots[loc.lotIndex].entreprises.splice(loc.index, 1);
                                }
                                
                                setPanneau({ ...panneau, intervenants: newInter, lots: newLots });
                            }}
                            isSaving={isSaving} 
                            uiMode="delege" 
                            lockedFields={panneau.lockedFields || []}
                            showToast={showToast}
                        />
                    ) : <FallbackError name="PanneauEditorForm" />}
                </div>
            </main>
            
            {editingEntity && EntityEditor && (
                <EntityEditor 
                    editingEntity={editingEntity} 
                    setEditingEntity={setEditingEntity} 
                    saveEditedEntity={() => {
                        let newInter = [...(panneau.intervenants || [])];
                        let newLots = JSON.parse(JSON.stringify(panneau.lots || []));
                        const loc = editingEntity.location;
                        
                        if (loc.type === 'intervenant') { 
                            if (loc.index !== undefined) {
                                newInter[loc.index] = editingEntity.data; 
                            } else {
                                newInter.push({...editingEntity.data, id: crypto.randomUUID()}); 
                            }
                        } else if (loc.type === 'lot') { 
                            if (loc.index !== undefined) {
                                newLots[loc.index] = {...newLots[loc.index], ...editingEntity.data}; 
                            } else {
                                newLots.push({...editingEntity.data, id: crypto.randomUUID(), entreprises: []}); 
                            }
                        } else if (loc.type === 'entreprise') { 
                            if (loc.index !== undefined) {
                                newLots[loc.lotIndex].entreprises[loc.index] = editingEntity.data; 
                            } else {
                                newLots[loc.lotIndex].entreprises.push({...editingEntity.data, id: crypto.randomUUID()}); 
                            }
                        }
                        
                        setPanneau({ ...panneau, intervenants: newInter, lots: newLots });
                        setEditingEntity(null);
                    }} 
                    showToast={showToast}
                />
            )}
        </div>
    );
};

const AuthInput = ({ type, name, value, onChange, placeholder, icon }) => (
    <div className="relative">
        <div className="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none text-slate-400">
            {icon}
        </div>
        <input 
            type={type} 
            name={name}
            value={value} 
            onChange={onChange} 
            required 
            placeholder={placeholder} 
            className="w-full pl-11 pr-4 py-3.5 bg-slate-50 border-2 border-slate-100 rounded-xl outline-none focus:border-emerald-500 focus:bg-white transition text-sm font-medium text-slate-800" 
        />
    </div>
);

const AuthModal = ({ initialView = 'login', token = '', onClose, onLoginSuccess, showToast }) => {
    const [view, setView] = useState(initialView);
    const [loading, setLoading] = useState(false);
    const [formData, setFormData] = useState({ email: '', password: '', company: '', code: '', remember_duration: 0 });

    const handleInputChange = (e) => {
        setFormData({ ...formData, [e.target.name]: e.target.value });
    };

    const executeAuth = async (endpoint, dataObj, onSuccessCallback) => {
        setLoading(true);
        try {
            const res = await fetch(window.ECO_CONFIG.apiBaseUrl + endpoint, { 
                method: 'POST', 
                body: JSON.stringify(dataObj) 
            });
            const d = await res.json();
            
            if (d.status === 'success') { 
                onSuccessCallback(d); 
            } else { 
                showToast(d.message, 'error'); 
            }
        } catch(err) { 
            showToast("Erreur réseau", 'error'); 
        }
        setLoading(false);
    };

    const handleLogin = (e) => { 
        e.preventDefault(); 
        
        const payload = { 
            login: formData.email, 
            password: formData.password, 
            remember_duration: formData.remember_duration 
        };
        
        executeAuth('auth/login', payload, d => { 
            if (d.data['2fa_required']) { 
                setView('2fa'); 
                showToast("Veuillez saisir votre code de sécurité.", "info"); 
            } else { 
                setFormData(prev => ({ ...prev, password: '' }));
                onLoginSuccess(d.data.role); 
            } 
        }); 
    };

    const handleResend2FA = async () => {
        setLoading(true);
        try {
            const res = await fetch(window.ECO_CONFIG.apiBaseUrl + 'auth/login', { 
                method: 'POST', 
                body: JSON.stringify({ 
                    login: formData.email, 
                    password: formData.password, 
                    remember_duration: formData.remember_duration 
                }) 
            });
            const d = await res.json();
            
            if (d.status === 'success' && d.data['2fa_required']) {
                showToast("Un nouveau code de sécurité vous a été envoyé.", "success");
            } else {
                showToast(d.message || "Erreur lors du renvoi du code.", "error");
            }
        } catch(err) { 
            showToast("Erreur réseau", "error"); 
        }
        setLoading(false);
    };
    
    const handleVerify2FA = (e) => { 
        e.preventDefault(); 
        
        executeAuth('auth/verify_2fa', { code: formData.code }, d => {
            setFormData(prev => ({ ...prev, password: '', code: '' }));
            onLoginSuccess(d.data.role);
        }); 
    };
    
    const handleRegisterRequest = (e) => { 
        e.preventDefault(); 
        
        executeAuth('auth/register_request', { email: formData.email, company: formData.company }, () => {
            setView('register_sent');
        }); 
    };
    
    const handleRegisterConfirm = (e) => { 
        e.preventDefault(); 
        
        executeAuth('auth/register_confirm', { token, password: formData.password }, d => { 
            showToast("Compte créé avec succès !", "success"); 
            setFormData(prev => ({ ...prev, password: '' })); 
            onLoginSuccess(d.data.role); 
        }); 
    };
    
    const handleForgotRequest = (e) => { 
        e.preventDefault(); 
        
        executeAuth('auth/forgot_password', { email: formData.email }, () => {
            setView('forgot_sent');
        }); 
    };
    
    const handleResetConfirm = (e) => { 
        e.preventDefault(); 
        
        executeAuth('auth/reset_password', { token, password: formData.password }, () => { 
            showToast("Mot de passe modifié avec succès.", "success"); 
            setFormData(prev => ({ ...prev, password: '' })); 
            setView('login'); 
        }); 
    };

    return (
        <div className="fixed inset-0 bg-slate-900/60 backdrop-blur-sm z-[999] flex items-center justify-center p-4 animate-in fade-in duration-200" onMouseDown={onClose}>
            <div className="bg-white rounded-[2rem] w-full max-w-md shadow-2xl overflow-hidden" onMouseDown={e => e.stopPropagation()}>
                <div className="p-8 pb-6 text-center relative">
                    <button onClick={onClose} className="absolute top-6 right-6 text-slate-400 hover:text-slate-700 bg-slate-50 rounded-full p-2 transition">
                        <X className="w-5 h-5"/>
                    </button>
                    <div className="w-16 h-16 bg-emerald-100 text-emerald-600 rounded-2xl flex items-center justify-center mx-auto mb-4 rotate-3">
                        <Lock className="w-8 h-8"/>
                    </div>
                    <h2 className="text-2xl font-black text-slate-800">
                        {view === 'login' ? 'Connexion' : view === 'register' ? 'Créer un compte' : view === '2fa' ? 'Sécurité 2FA' : view.includes('forgot') ? 'Mot de passe oublié' : 'Nouveau mot de passe'}
                    </h2>
                </div>

                <div className="px-8 pb-8">
                    {view === 'login' && (
                        <form onSubmit={handleLogin} className="space-y-4">
                            <AuthInput 
                                type="email" 
                                name="email" 
                                value={formData.email} 
                                onChange={handleInputChange} 
                                placeholder="Adresse e-mail" 
                                icon={<Mail className="w-4 h-4"/>} 
                            />
                            <AuthInput 
                                type="password" 
                                name="password" 
                                value={formData.password} 
                                onChange={handleInputChange} 
                                placeholder="Mot de passe" 
                                icon={<KeyRound className="w-4 h-4"/>} 
                            />
                            
                            <div className="flex items-center justify-between mt-2 px-1">
                                <label className="flex items-center gap-2 cursor-pointer select-none">
                                    <input 
                                        type="checkbox" 
                                        checked={formData.remember_duration > 0} 
                                        onChange={(e) => setFormData({...formData, remember_duration: e.target.checked ? 1296000 : 0})} 
                                        className="w-4 h-4 accent-emerald-600 cursor-pointer" 
                                    />
                                    <span className="text-xs font-bold text-slate-600">Rester connecté</span>
                                </label>
                                {formData.remember_duration > 0 && (
                                    <select 
                                        value={formData.remember_duration} 
                                        onChange={(e) => setFormData({...formData, remember_duration: Number(e.target.value)})} 
                                        className="text-xs border border-slate-200 rounded-lg py-1 px-2 outline-none text-slate-600 bg-white font-bold cursor-pointer"
                                    >
                                        <option value={1296000}>15 jours</option>
                                        <option value={7776000}>3 mois</option>
                                        <option value={15552000}>6 mois</option>
                                        <option value={315360000}>Permanent (déconseillé)</option>
                                    </select>
                                )}
                            </div>

                            <div className="flex justify-end pt-2">
                                <button type="button" onClick={() => setView('forgot')} className="text-xs font-bold text-emerald-600 hover:text-emerald-700">
                                    Mot de passe oublié ?
                                </button>
                            </div>
                            
                            <button type="submit" disabled={loading} className="w-full py-4 bg-slate-900 text-white rounded-xl font-black uppercase tracking-widest hover:bg-slate-800 transition shadow-lg mt-2 flex items-center justify-center gap-2 disabled:opacity-50">
                                {loading ? <Loader className="animate-spin w-4 h-4"/> : 'Se connecter'}
                            </button>
                            
                            <p className="text-center text-sm font-medium text-slate-500 mt-4">
                                Pas encore de compte ? <button type="button" onClick={() => setView('register')} className="text-emerald-600 font-bold hover:underline">Inscrivez-vous</button>
                            </p>
                        </form>
                    )}

                    {view === 'register' && (
                        <form onSubmit={handleRegisterRequest} className="space-y-4">
                            <AuthInput 
                                type="text" 
                                name="company" 
                                value={formData.company} 
                                onChange={handleInputChange} 
                                placeholder="Nom complet ou raison sociale" 
                                icon={<Building className="w-4 h-4"/>} 
                            />
                            <AuthInput 
                                type="email" 
                                name="email" 
                                value={formData.email} 
                                onChange={handleInputChange} 
                                placeholder="Adresse e-mail pro" 
                                icon={<Mail className="w-4 h-4"/>} 
                            />
                            
                            <button type="submit" disabled={loading} className="w-full py-4 bg-emerald-600 text-white rounded-xl font-black uppercase tracking-widest hover:bg-emerald-700 transition shadow-lg mt-2 flex items-center justify-center gap-2 disabled:opacity-50">
                                {loading ? <Loader className="animate-spin w-4 h-4"/> : 'Commencer gratuitement'}
                            </button>
                            
                            <p className="text-center text-sm font-medium text-slate-500 mt-4">
                                Déjà inscrit ? <button type="button" onClick={() => setView('login')} className="text-slate-800 font-bold hover:underline">Connectez-vous</button>
                            </p>
                        </form>
                    )}

                    {view === 'register_sent' && (
                        <div className="text-center space-y-4 py-4">
                            <div className="bg-emerald-50 text-emerald-800 p-4 rounded-xl text-sm font-medium border border-emerald-100">
                                Un lien magique a été envoyé à <strong>{formData.email}</strong>. Cliquez dessus pour activer votre compte.
                            </div>
                            <button type="button" onClick={() => setView('login')} className="text-sm font-bold text-slate-500 hover:text-slate-800">
                                Retour à la connexion
                            </button>
                        </div>
                    )}

                    {view === 'register_confirm' && (
                        <form onSubmit={handleRegisterConfirm} className="space-y-4">
                            <p className="text-sm text-slate-600 text-center mb-4">
                                Dernière étape : choisissez un mot de passe sécurisé pour protéger votre compte.
                            </p>
                            <AuthInput 
                                type="password" 
                                name="password" 
                                value={formData.password} 
                                onChange={handleInputChange} 
                                placeholder="Votre mot de passe (min 8 car.)" 
                                icon={<Lock className="w-4 h-4"/>} 
                            />
                            <button type="submit" disabled={loading} className="w-full py-4 bg-emerald-600 text-white rounded-xl font-black uppercase tracking-widest hover:bg-emerald-700 transition shadow-lg mt-2 flex items-center justify-center gap-2 disabled:opacity-50">
                                {loading ? <Loader className="animate-spin w-4 h-4"/> : 'Valider et accéder'}
                            </button>
                        </form>
                    )}

                    {view === '2fa' && (
                        <form onSubmit={handleVerify2FA} className="space-y-4">
                            <p className="text-sm text-slate-600 text-center mb-4">
                                Un code de sécurité vous a été envoyé par e-mail ou est disponible sur votre application d'authentification.
                            </p>
                            <AuthInput 
                                type="text" 
                                name="code" 
                                value={formData.code} 
                                onChange={handleInputChange} 
                                placeholder="Code à 6 chiffres" 
                                icon={<Shield className="w-4 h-4"/>} 
                            />
                            <button type="submit" disabled={loading} className="w-full py-4 bg-slate-900 text-white rounded-xl font-black uppercase tracking-widest hover:bg-slate-800 transition shadow-lg mt-2 flex items-center justify-center gap-2 disabled:opacity-50">
                                {loading ? <Loader className="animate-spin w-4 h-4"/> : 'Vérifier'}
                            </button>
                            
                            <div className="flex justify-between items-center mt-3 pt-3 border-t border-slate-100">
                                <button type="button" onClick={handleResend2FA} disabled={loading} className="text-xs font-bold text-emerald-600 hover:text-emerald-700 disabled:opacity-50 transition">
                                    Renvoyer le code
                                </button>
                                <button type="button" onClick={() => setView('login')} className="text-xs font-bold text-slate-500 hover:text-slate-800 transition">
                                    Annuler
                                </button>
                            </div>
                        </form>
                    )}

                    {view === 'forgot' && (
                        <form onSubmit={handleForgotRequest} className="space-y-4">
                            <p className="text-sm text-slate-600 text-center mb-4">
                                Saisissez l'adresse e-mail associée à votre compte pour recevoir un lien de réinitialisation.
                            </p>
                            <AuthInput 
                                type="email" 
                                name="email" 
                                value={formData.email} 
                                onChange={handleInputChange} 
                                placeholder="Adresse e-mail" 
                                icon={<Mail className="w-4 h-4"/>} 
                            />
                            <button type="submit" disabled={loading} className="w-full py-4 bg-slate-900 text-white rounded-xl font-black uppercase tracking-widest hover:bg-slate-800 transition shadow-lg mt-2 flex items-center justify-center gap-2 disabled:opacity-50">
                                {loading ? <Loader className="animate-spin w-4 h-4"/> : 'Envoyer le lien'}
                            </button>
                            <button type="button" onClick={() => setView('login')} className="w-full text-center text-sm font-bold text-slate-500 mt-4 hover:text-slate-800">
                                Retour à la connexion
                            </button>
                        </form>
                    )}

                    {view === 'forgot_sent' && (
                        <div className="text-center space-y-4 py-4">
                            <div className="bg-blue-50 text-blue-800 p-4 rounded-xl text-sm font-medium border border-blue-100">
                                Si un compte existe pour cet e-mail, un lien de réinitialisation vous a été envoyé.
                            </div>
                            <button type="button" onClick={() => setView('login')} className="text-sm font-bold text-slate-500 hover:text-slate-800">
                                Retour à la connexion
                            </button>
                        </div>
                    )}

                    {view === 'reset' && (
                        <form onSubmit={handleResetConfirm} className="space-y-4">
                            <p className="text-sm text-slate-600 text-center mb-4">
                                Saisissez votre nouveau mot de passe (8 caractères minimum avec majuscule et chiffre).
                            </p>
                            <AuthInput 
                                type="password" 
                                name="password" 
                                value={formData.password} 
                                onChange={handleInputChange} 
                                placeholder="Nouveau mot de passe" 
                                icon={<KeyRound className="w-4 h-4"/>} 
                            />
                            <button type="submit" disabled={loading} className="w-full py-4 bg-emerald-600 text-white rounded-xl font-black uppercase tracking-widest hover:bg-emerald-700 transition shadow-lg mt-2 flex items-center justify-center gap-2 disabled:opacity-50">
                                {loading ? <Loader className="animate-spin w-4 h-4"/> : 'Modifier le mot de passe'}
                            </button>
                        </form>
                    )}
                </div>
            </div>
        </div>
    );
};

// =========================================================================
// 3. COMPOSANT RACINE (MAIN APP) - ORCHESTRATION GLOBALE
// =========================================================================

const App = () => {
    const [session, setSession] = useState({ loaded: false, role: 'public', user_id: null, is_impersonating: false });
    const [data, setData] = useState({ panneaux: [], clients: [], interactions: [], invoices: [], settings: {}, prices: {}, stats: {} });
    const [loading, setLoading] = useState(true);
    
    const [toast, setToast] = useState(null);
    const [authConfig, setAuthConfig] = useState(null);
    const [globalLoading, setGlobalLoading] = useState(false);
    const [actionResult, setActionResult] = useState(null);
    const [globalPanic, setGlobalPanic] = useState(null); 

    const showToast = useCallback((msg, type = 'info') => {
        const id = Date.now();
        setToast({ msg, type, id });
        setTimeout(() => setToast(current => current?.id === id ? null : current), 4000);
    }, []);

    useEffect(() => {
        const handleOptimisticMsg = (e) => {
            const newMsg = e.detail;
            setData(prev => {
                const merged = [...(prev.interactions || []), newMsg];
                // CORRECTION : Contournement du bug Date Safari avec le wrapper String
                merged.sort((a, b) => new Date(String(a.created_at || '').replace(' ', 'T')).getTime() - new Date(String(b.created_at || '').replace(' ', 'T')).getTime());
                return {
                    ...prev,
                    interactions: merged
                };
            });
        };
        window.addEventListener('optimistic_message', handleOptimisticMsg);
        return () => window.removeEventListener('optimistic_message', handleOptimisticMsg);
    }, []);

    useEffect(() => {
        const originalFetch = window.fetch;
        window.fetch = async function() {
            const urlStr = arguments[0] instanceof Request ? arguments[0].url : arguments[0];
            const isSilent = typeof urlStr === 'string' && urlStr.includes('silent=1');
            
            if (!isSilent) {
                window.activeApiCalls = (window.activeApiCalls || 0) + 1;
                window.dispatchEvent(new CustomEvent('api_call_start'));
            }
            try {
                const response = await originalFetch.apply(this, arguments);
                
                if (response.status === 423) {
                    try {
                        const errorData = await response.clone().json();
                        if (errorData.status === 'panic') {
                            setGlobalPanic({
                                message: errorData.message,
                                mode: errorData.data?.panic_mode || 'seal' 
                            });
                        }
                    } catch(e) {
                        setGlobalPanic({
                            message: "Alerte de sécurité. Verrouillage du site en cours.",
                            mode: 'shield'
                        });
                    }
                }
                
                if (response.status === 401) {
                    const url = new URL(arguments[0], window.location.origin);
                    if (url.searchParams.get('api') !== 'auth/me' && url.searchParams.get('api') !== 'auth/login') {
                        window.dispatchEvent(new CustomEvent('session_expired'));
                    }
                }
                return response;
            } finally {
                if (!isSilent) {
                    window.activeApiCalls = Math.max(0, window.activeApiCalls - 1);
                    if (window.activeApiCalls === 0) window.dispatchEvent(new CustomEvent('api_call_end'));
                }
            }
        };

        let timeout;
        const handleStart = () => {
            if (window.activeApiCalls === 1) { 
                // CORRECTION : Le délai du loader global passe de 1000 à 3000 ms
                timeout = setTimeout(() => setGlobalLoading(true), 3000); 
            }
        };
        const handleEnd = () => {
            if (window.activeApiCalls === 0) { 
                clearTimeout(timeout);
                setGlobalLoading(false);
            }
        };

        window.addEventListener('api_call_start', handleStart);
        window.addEventListener('api_call_end', handleEnd);
        return () => {
            window.removeEventListener('api_call_start', handleStart);
            window.removeEventListener('api_call_end', handleEnd);
            clearTimeout(timeout);
            window.fetch = originalFetch;
        };
    }, []);

    const fetchData = async (silent = false) => {
        try {
            const vid = window.getVisitorId();
            const urlParams = new URLSearchParams(window.location.search);
            const scanId = urlParams.get('scan') || '';
            const threadToken = urlParams.get('thread') || '';
            
            const res = await fetch(window.ECO_CONFIG.apiBaseUrl + `sync&visitor_id=${vid}&scan=${scanId}&thread=${encodeURIComponent(threadToken)}${silent ? '&silent=1' : ''}&_t=${Date.now()}`);
            const d = await res.json();
            
            if (d.status === 'success') {
                setData(prevData => {
                    const newInteractions = d.data.interactions || [];
                    const prevInteractions = prevData.interactions || [];
                    
                    const realPrev = prevInteractions.filter(m => !String(m.id).startsWith('temp_'));
                    const tempMsgs = prevInteractions.filter(m => String(m.id).startsWith('temp_'));
                    
                    let merged = newInteractions.length > realPrev.length 
                        ? newInteractions 
                        : [...newInteractions, ...tempMsgs];
                    
                    // CORRECTION : Contournement du bug Date Safari avec le wrapper String
                    merged.sort((a, b) => new Date(String(a.created_at || '').replace(' ', 'T')).getTime() - new Date(String(b.created_at || '').replace(' ', 'T')).getTime());
                    
                    return { ...d.data, interactions: merged };
                });
            }
        } catch (e) {
            // Silence
        } finally {
            if (!silent) setLoading(false);
        }
    };

    useEffect(() => {
        if (!session.loaded) return;

        const urlParams = new URLSearchParams(window.location.search);
        let updated = false;

        if (urlParams.has('reg_token')) {
            setAuthConfig({ view: 'register_confirm', token: urlParams.get('reg_token') });
            urlParams.delete('reg_token');
            updated = true;
        }
        else if (urlParams.has('reset_token')) {
            setAuthConfig({ view: 'reset', token: urlParams.get('reset_token') });
            urlParams.delete('reset_token');
            updated = true;
        }
        else if (urlParams.has('del_token')) {
            const token = urlParams.get('del_token');
            urlParams.delete('del_token');
            updated = true;
            
            fetch(window.ECO_CONFIG.apiBaseUrl + 'clients/confirm_delete', { 
                method: 'POST', 
                body: JSON.stringify({ token }) 
            })
            .then(r => r.json())
            .then(d => {
                if (d.status === 'success') {
                    setActionResult({ 
                        title: "Compte supprimé", 
                        message: "Votre compte et toutes vos données ont été définitivement supprimés. Au revoir !", 
                        type: "success" 
                    });
                } else {
                    setActionResult({ 
                        title: "Erreur", 
                        message: d.message || "Lien invalide ou expiré.", 
                        type: "error" 
                    });
                }
            });
        }
        else if (urlParams.has('grant_access')) {
            const token = urlParams.get('grant_access');
            urlParams.delete('grant_access');
            updated = true;
            
            if (session.role === 'admin' && !session.is_impersonating) {
                setActionResult({ 
                    title: "Action non autorisée", 
                    message: "En tant qu'administrateur, vous ne pouvez pas vous auto-attribuer l'accès à un compte client de cette manière.", 
                    type: "error" 
                });
            } else {
                fetch(window.ECO_CONFIG.apiBaseUrl + 'clients/grant_access', { 
                    method: 'POST', 
                    body: JSON.stringify({ token }) 
                })
                .then(r => r.json())
                .then(d => {
                    if (d.status === 'success') {
                        setActionResult({ 
                            title: "Accès autorisé", 
                            message: "L'équipe technique a désormais un accès temporaire (24h) à votre compte pour vous assister.", 
                            type: "success" 
                        });
                    } else {
                        setActionResult({ 
                            title: "Lien invalide", 
                            message: "Ce lien d'autorisation est invalide ou a expiré.", 
                            type: "error" 
                        });
                    }
                });
            }
        }

        if (updated) {
            window.history.replaceState({}, '', '?' + urlParams.toString());
        }
    }, [session.loaded, session.role, session.is_impersonating, showToast]);

    useEffect(() => {
        const initSession = async () => {
            try {
                const res = await fetch(window.ECO_CONFIG.apiBaseUrl + 'auth/me');
                const d = await res.json();
                if (d.status === 'success') {
                    setSession({ 
                        loaded: true, 
                        role: d.data.role, 
                        user_id: d.data.user_id, 
                        is_impersonating: d.data.is_impersonating 
                    });
                } else {
                    setSession({ 
                        loaded: true, 
                        role: 'public', 
                        user_id: null, 
                        is_impersonating: false 
                    });
                }
            } catch (e) {
                setSession({ 
                    loaded: true, 
                    role: 'public', 
                    user_id: null, 
                    is_impersonating: false 
                });
            }
        };
        
        initSession();

        const handleSessionExpired = () => {
            setSession({ 
                loaded: true, 
                role: 'public', 
                user_id: null, 
                is_impersonating: false 
            });
            showToast("Votre session a expiré. Veuillez vous reconnecter.", "info");
        };

        window.addEventListener('session_expired', handleSessionExpired);
        return () => window.removeEventListener('session_expired', handleSessionExpired);
    }, [showToast]);

    useEffect(() => {
        if (session.loaded) {
            fetchData();
        }
    }, [session.loaded, session.role]);

    useEffect(() => {
        if (!session.loaded) return;

        let pollingInterval;
        let currentDelay = 1000;
        let lastActivityTime = Date.now();
        let isTabVisible = !document.hidden;

        const performChatSync = async () => {
            if (!isTabVisible) return;

            try {
                const urlParams = new URLSearchParams(window.location.search);
                const scanId = urlParams.get('scan') || '';
                const threadToken = urlParams.get('thread') || '';
                
                const res = await fetch(window.ECO_CONFIG.apiBaseUrl + `interactions/sync&scan=${scanId}&thread=${encodeURIComponent(threadToken)}&silent=1&_t=${Date.now()}`);
                const d = await res.json();
                
                if (d.status === 'success') {
                    setData(prevData => {
                        const prevInteractions = prevData.interactions || [];
                        const newInteractions = d.data.interactions || [];
                        
                        const realPrev = prevInteractions.filter(m => !String(m.id).startsWith('temp_'));
                        let changed = realPrev.length !== newInteractions.length;
                        
                        if (!changed && newInteractions.length > 0 && realPrev.length > 0) {
                            const lastPrev = realPrev[realPrev.length - 1];
                            const lastNew = newInteractions[newInteractions.length - 1];
                            
                            if (lastPrev.id !== lastNew.id || lastPrev.resolved !== lastNew.resolved || lastPrev.isAlert !== lastNew.isAlert) {
                                changed = true;
                            }
                            
                            const prevUnread = realPrev.filter(m => !m.resolved).length;
                            const newUnread = newInteractions.filter(m => !m.resolved).length;
                            if (prevUnread !== newUnread) {
                                changed = true;
                            }
                        }
                        
                        if (changed) {
                            lastActivityTime = Date.now();
                            scheduleNextPoll(1000);
                            
                            const tempMsgs = prevInteractions.filter(m => String(m.id).startsWith('temp_'));
                            let merged = newInteractions.length > realPrev.length 
                                ? newInteractions 
                                : [...newInteractions, ...tempMsgs];
                            
                            // CORRECTION : Contournement bug Date Safari
                            merged.sort((a, b) => new Date(String(a.created_at || '').replace(' ', 'T')).getTime() - new Date(String(b.created_at || '').replace(' ', 'T')).getTime());

                            return { ...prevData, interactions: merged };
                        }
                        return prevData;
                    });
                }
            } catch(e) {}

            const idleTime = Date.now() - lastActivityTime;
            if (idleTime > 120000) {
                currentDelay = 10000;
            } else if (idleTime > 30000) {
                currentDelay = 3000;
            } else {
                currentDelay = 1000;
            }

            scheduleNextPoll(currentDelay);
        };

        const scheduleNextPoll = (delay) => {
            clearTimeout(pollingInterval);
            if (isTabVisible) {
                pollingInterval = setTimeout(performChatSync, delay);
            }
        };

        const handleVisibilityChange = () => {
            isTabVisible = !document.hidden;
            if (isTabVisible) {
                lastActivityTime = Date.now();
                currentDelay = 1000;
                performChatSync();
            } else {
                clearTimeout(pollingInterval);
            }
        };

        const handleUserInteraction = () => {
            if (currentDelay > 1000) {
                lastActivityTime = Date.now();
                currentDelay = 1000;
                scheduleNextPoll(1000);
            } else {
                lastActivityTime = Date.now();
            }
        };

        document.addEventListener('visibilitychange', handleVisibilityChange);
        document.addEventListener('click', handleUserInteraction);
        document.addEventListener('keydown', handleUserInteraction);

        scheduleNextPoll(currentDelay);

        return () => {
            clearTimeout(pollingInterval);
            document.removeEventListener('visibilitychange', handleVisibilityChange);
            document.removeEventListener('click', handleUserInteraction);
            document.removeEventListener('keydown', handleUserInteraction);
        };
    }, [session.loaded]);

    useEffect(() => {
        if (!session.loaded || session.role === 'public') return;

        let globalPollingInterval;
        let currentDelay = 15000; 
        let lastActivityTime = Date.now();
        let isTabVisible = !document.hidden;

        const performGlobalSync = async () => {
            if (!isTabVisible) return;
            await fetchData(true);

            const idleTime = Date.now() - lastActivityTime;
            if (idleTime > 120000) {
                currentDelay = 60000;      
            } else if (idleTime > 30000) {
                currentDelay = 30000;  
            } else {
                currentDelay = 15000;                        
            }

            scheduleNextPoll(currentDelay);
        };

        const scheduleNextPoll = (delay) => {
            clearTimeout(globalPollingInterval);
            if (isTabVisible) {
                globalPollingInterval = setTimeout(performGlobalSync, delay);
            }
        };

        const handleVisibilityChange = () => {
            isTabVisible = !document.hidden;
            if (isTabVisible) {
                lastActivityTime = Date.now();
                currentDelay = 15000;
                performGlobalSync();
            } else {
                clearTimeout(globalPollingInterval);
            }
        };

        const handleUserInteraction = () => {
            if (currentDelay > 15000) {
                lastActivityTime = Date.now();
                currentDelay = 15000;
                scheduleNextPoll(15000);
            } else {
                lastActivityTime = Date.now();
            }
        };

        document.addEventListener('visibilitychange', handleVisibilityChange);
        document.addEventListener('click', handleUserInteraction);
        document.addEventListener('keydown', handleUserInteraction);

        scheduleNextPoll(currentDelay);

        return () => {
            clearTimeout(globalPollingInterval);
            document.removeEventListener('visibilitychange', handleVisibilityChange);
            document.removeEventListener('click', handleUserInteraction);
            document.removeEventListener('keydown', handleUserInteraction);
        };
    }, [session.loaded, session.role]);

    // Chargement initial
    if (!session.loaded || loading) {
        return (
            <div className="flex items-center justify-center h-screen flex-col gap-4 bg-slate-50">
                <Loader className="w-8 h-8 text-emerald-600 animate-spin" />
                <p className="text-sm font-bold text-slate-500 uppercase tracking-widest animate-pulse">Chargement sécurisé...</p>
            </div>
        );
    }

    const urlParams = new URLSearchParams(window.location.search);
    const isScanOrThread = urlParams.has('scan') || urlParams.has('thread');
    const delegateToken = urlParams.get('delegate');

    let ViewToRender = null;
    const isRiverain = session.role === 'public' && isScanOrThread;

    if (session.role === 'admin') {
        const AdminViewComp = getAdminView();
        ViewToRender = AdminViewComp ? <AdminViewComp data={data} refreshData={fetchData} showToast={showToast} /> : <FallbackError name="AdminView" />;
    } else if (session.role === 'client') {
        const ClientViewComp = getClientView();
        ViewToRender = ClientViewComp ? <ClientViewComp data={data} refreshData={fetchData} showToast={showToast} /> : <FallbackError name="ClientView" />;
    } else {
        if (isRiverain) {
            const RiverainViewComp = getRiverainView();
            const scanId = urlParams.get('scan');
            let panneauData = data.panneaux?.find(c => c.id === scanId);
            
            if (!scanId && urlParams.has('thread')) {
                panneauData = {
                    id: 'CONTACT_PUBLIC',
                    name: 'Service client',
                    location: 'Assistance en ligne',
                    themeColor: '#0f172a',
                    hasNoAds: true
                };
            }

            const startTab = urlParams.has('thread') ? 'contact' : 'home';

            ViewToRender = RiverainViewComp ? <RiverainViewComp panneau={panneauData} interactions={data.interactions} settings={data.settings} showToast={showToast} refreshData={fetchData} initialTab={startTab} /> : <FallbackError name="RiverainView" />;
        } else if (delegateToken) {
            window.CURRENT_DELEGATE_TOKEN = delegateToken;
            ViewToRender = <DelegateView token={delegateToken} showToast={showToast} />;
        } else {
            const PublicViewComp = getPublicView();
            ViewToRender = PublicViewComp ? <PublicViewComp data={data} onLoginClick={(view) => setAuthConfig({ view })} showToast={showToast} /> : <FallbackError name="Accueil Public" />;
        }
    }

    const showSiteBanner = !isRiverain && data.settings?.site_banner_active === '1' && data.settings?.site_banner_msg;

    return (
        <div className="flex flex-col min-h-screen w-full">
            {showSiteBanner && (
                <div className="bg-orange-500 text-white text-center py-2.5 px-4 font-bold text-sm z-[99999] relative shadow-md shrink-0">
                    <div dangerouslySetInnerHTML={{ __html: window.DOMPurify ? window.DOMPurify.sanitize(data.settings.site_banner_msg) : data.settings.site_banner_msg.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;') }} className="admin-html" />
                </div>
            )}
            
            <div className="flex-1 flex flex-col relative w-full">
                {ViewToRender}
            </div>
            
            {actionResult && (
                <div className="fixed inset-0 bg-slate-900/80 backdrop-blur-md z-[99999] flex items-center justify-center p-4 animate-in fade-in duration-300">
                    <div className="bg-white rounded-[2rem] w-full max-w-md shadow-2xl overflow-hidden p-8 text-center border border-slate-200">
                        <div className={`w-20 h-20 rounded-full flex items-center justify-center mx-auto mb-6 ${actionResult.type === 'success' ? 'bg-emerald-100 text-emerald-600' : 'bg-red-100 text-red-600'}`}>
                            {actionResult.type === 'success' ? <CheckCircle size={40}/> : <AlertTriangle size={40}/>}
                        </div>
                        <h2 className="text-2xl font-black text-slate-800 mb-3">{actionResult.title}</h2>
                        <p className="text-slate-600 font-medium leading-relaxed mb-8">{actionResult.message}</p>
                        <button onClick={() => setActionResult(null)} className="w-full bg-slate-900 text-white py-4 rounded-xl font-black uppercase tracking-widest hover:bg-slate-800 transition shadow-xl">
                            Fermer
                        </button>
                    </div>
                </div>
            )}

            {authConfig && (
                <AuthModal 
                    initialView={authConfig.view} 
                    token={authConfig.token || ''}
                    onClose={() => setAuthConfig(null)} 
                    showToast={showToast}
                    onLoginSuccess={(role) => {
                        setAuthConfig(null);
                        setSession(prev => ({ ...prev, role }));
                        fetchData();
                    }}
                />
            )}

            {globalLoading && (
                <div className="fixed top-4 sm:top-6 left-1/2 transform -translate-x-1/2 z-[100000] bg-slate-900/95 backdrop-blur-md text-white px-5 py-2.5 rounded-full shadow-2xl flex items-center gap-3 animate-in fade-in slide-in-from-top-4 border border-slate-700">
                    <Loader className="w-4 h-4 animate-spin text-emerald-400" />
                    <span className="text-xs font-bold tracking-widest uppercase">Un instant...</span>
                </div>
            )}
            
            {toast && (
                <div className="fixed bottom-4 right-4 sm:bottom-6 sm:right-6 z-[9999] animate-in slide-in-from-bottom-5 fade-in duration-300">
                    <div className={`flex items-center gap-3 px-5 py-4 rounded-2xl shadow-2xl border font-bold text-sm backdrop-blur-md
                        ${toast.type === 'error' ? 'bg-red-500/95 border-red-400 text-white' : 
                          toast.type === 'success' ? 'bg-emerald-600/95 border-emerald-500 text-white' : 
                          'bg-slate-800/95 border-slate-700 text-white'}`}
                    >
                        <div className="shrink-0">
                            {toast.type === 'error' ? <AlertTriangle className="w-5 h-5"/> : 
                             toast.type === 'success' ? <CheckCircle className="w-5 h-5"/> : <Info className="w-5 h-5"/>}
                        </div>
                        <div className="max-w-xs break-words leading-tight">{toast.msg}</div>
                    </div>
                </div>
            )}

            {globalPanic && (
                <div className={`fixed inset-0 z-[999999] flex items-center justify-center p-4 transition-all duration-300 ${globalPanic.mode === 'shield' ? 'bg-slate-900' : 'bg-slate-900/80 backdrop-blur-sm'}`}>
                    <div className="bg-slate-800 p-8 md:p-10 rounded-[2rem] max-w-xl w-full border border-slate-700 shadow-2xl text-center animate-in fade-in zoom-in-95 duration-300">
                        <div className="w-20 h-20 bg-red-500/20 text-red-500 rounded-2xl flex items-center justify-center mx-auto mb-6 rotate-3">
                            <AlertTriangle className="w-10 h-10" />
                        </div>
                        <h1 className="text-2xl font-black text-red-400 mb-4 uppercase tracking-widest">
                            {globalPanic.mode === 'shield' ? 'Bouclier anti-DDoS actif' : 'Action bloquée par sécurité'}
                        </h1>
                        <p className="text-slate-300 font-medium leading-relaxed mb-8 text-sm md:text-base">
                            {globalPanic.message}
                        </p>
                        {globalPanic.mode === 'seal' ? (
                            <button onClick={() => setGlobalPanic(null)} className="w-full bg-slate-700 hover:bg-slate-600 text-white font-black uppercase tracking-widest py-4 rounded-xl transition shadow-lg">
                                J'ai compris, fermer
                            </button>
                        ) : (
                            <button onClick={() => window.location.reload()} className="w-full bg-slate-700 hover:bg-slate-600 text-white font-black uppercase tracking-widest py-4 rounded-xl transition shadow-lg">
                                Recharger la page
                            </button>
                        )}
                    </div>
                </div>
            )}
        </div>
    );
};

const rootElement = document.getElementById('root');
if (rootElement) {
    const root = window.ReactDOM.createRoot(rootElement);
    root.render(<App />);
}

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