if (typeof process === 'undefined') {
    window.process = { env: {} };
}

import Select from './vendor/react-select.min.js';

const React = window.React;
const { useState, useEffect, useMemo, useRef } = window.React;
const createRoot = window.ReactDOM?.createRoot;
const axios = window.axios;

const PackageManager = () => {
    const [isPackagesOpen, setIsPackagesOpen] = useState(false);
    const [readinessStatus, setReadinessStatus] = useState({}); // Pour gérer le chargement par outil
    const [containers, setContainers] = useState([]);
    const [isDockerLoading, setIsDockerLoading] = useState(true);
    const [packages, setPackages] = useState([]);
    const [filter, setFilter] = useState('');
    const [progress, setProgress] = useState({});
    const [output, setOutput] = useState({});
    const [isLoading, setIsLoading] = useState({});
    const [expanded, setExpanded] = useState({});
    const [sshStatus, setSshStatus] = useState({ success: false, message: 'Connecting via SSH...' });
    const [loadStartTime] = useState(Date.now());
    const [isPackagesLoading, setIsPackagesLoading] = useState(true);
    const isInitialFetch = useRef(true);
    const pollingIntervals = useRef({});
    const isPackagesOpenRef = useRef(false);
    const [selectedOption, setSelectedOption] = useState(null);
    const [serverStats, setServerStats] = useState({ distro: 'Scanning...', ram: '0,0,0', disk: '0,0,0,0', cpu: '0' });
    const [isSyncing, setIsSyncing] = useState(false);
    const [syncMessage, setSyncMessage] = useState('');
    const [ansiblePackages, setAnsiblePackages] = useState([]);
    const [isAnsibleLoading, setIsAnsibleLoading] = useState(true);
    const readinessRef = useRef(null);
    useEffect(() => { isPackagesOpenRef.current = isPackagesOpen; }, [isPackagesOpen]);

    const isAnsibleReady = window.wpkginstAjax.readiness?.ansible?.installed;
    const [highlightFix, setHighlightFix] = useState(false);
    const [highlightSync, setHighlightSync] = useState(false);
    // useEffect REST
    // Définition de checkStatus accessible partout dans le composant
    const checkStatus = () => {
        if (isInitialFetch.current) {
            setIsPackagesLoading(true);
            setIsDockerLoading(true);
        }
    
        const skipPkgs = !isPackagesOpenRef.current ? '&skip_packages=1' : '';
        return axios.get('/wp-json/wpkginst/v1/full-status?t=' + Date.now() + skipPkgs, {
            headers: { 'X-WP-Nonce': wpkginstAjax.restNonce },
            timeout: 30000
        })
        .then((response) => {
            const data = response.data;
    
            // l'état SSH
            setSshStatus({
                success: data.ssh.success,
                message: data.ssh.message || 'SSH Connected'
            });
    
            if (data.ssh.success) {
                // les stats serveur (CPU, RAM, etc.)
                setServerStats(data.stats);
    
                // Mise à jour des packages (sans les filtres qui bloquent)
                if (Array.isArray(data.packages)) {
                    setPackages(data.packages);
                }
    
                // Docker & Ansible
                setContainers(data.containers || []);
                setAnsiblePackages(data.ansible || []);
            }
    
            isInitialFetch.current = false;
        })
        .catch((err) => {
            console.error("Erreur de synchronisation API:", err);
            setSshStatus({ success: false, message: 'API connection error' });
        })
        .finally(() => {
            setIsPackagesLoading(false);
            setIsDockerLoading(false);
            setIsAnsibleLoading(false);
        });
    };

    // Ton useEffect devient tout simple
    useEffect(() => {
        checkStatus();
        const interval = setInterval(checkStatus, 35000);
        return () => {
            clearInterval(interval);
            if (pollingIntervals.current) {
                Object.values(pollingIntervals.current).forEach(clearInterval);
            }
        };
    }, []);
    /*
    useEffect(() => {
        const checkStatus = () => {
            // 1. Si c'est le premier fetch, on peut activer les loaders globalement
            if (isInitialFetch.current) {
                setIsPackagesLoading(true);
                setIsDockerLoading(true);
                //setIsAnsibleLoading(true);
            }

            // 2. Un seul appel vers la nouvelle route API REST
            axios.get('/wp-json/wpkginst/v1/full-status', {
                headers: { 'X-WP-Nonce': wpkginstAjax.restNonce },
                timeout: 30000 // On donne plus de temps car la requête traite tout
            })
            .then((response) => {
                const data = response.data;

                // Mise à jour de l'état SSH
                setSshStatus({
                    success: data.ssh.success,
                    message: data.ssh.message || 'SSH Connected'
                });

                // Si le SSH est OK, on dispatch toutes les données reçues
                if (data.ssh.success) {
                    // Stats serveur
                    setServerStats(data.stats);

                    // Packages PHP
                    if (Array.isArray(data.packages)) {
                        setPackages(prevPackages => {
    if (isInitialFetch.current) return data.packages;

    return data.packages.map(newPkg => {
        // On cherche si on a déjà ce package dans notre état local actuel
        const localPkg = prevPackages.find(p => p.name === newPkg.name);

        // CONDITION CLÉ : Si le package local est en train de charger (isLoading)
        // OU si l'action vient juste de finir mais que le polling n'a pas encore vu le changement
        if (isLoading[newPkg.name]) {
            return localPkg; // On garde l'état local (avec le loader et l'ancien statut)
        }

        // Si l'installation vient de finir (isLoading est repassé à false)
        // on attend que le serveur confirme le changement avant de lâcher la priorité
        if (localPkg && localPkg.installed !== newPkg.installed && !isLoading[newPkg.name]) {
             // Si le serveur dit "pas installé" mais qu'on vient de finir l'install,
             // on garde l'état "installé" localement pendant un cycle de plus (optimisme)
             return newPkg;
        }

        return newPkg;
    });
});
                    }

                    // Docker Containers
                    setContainers(data.containers || []);

                    // Ansible Catalog
                    if (data.ansible && data.ansible.length > 0) {
                        setAnsiblePackages(data.ansible);
                    } else {
                        setAnsiblePackages([]);
                    }
                }

                // Une fois le premier succès terminé, on bascule le ref
                isInitialFetch.current = false;
            })
            .catch((err) => {
                console.error("Erreur de synchronisation API:", err);
                setSshStatus({ success: false, message: 'API connection error' });
                setAnsiblePackages([]);
            })
            .finally(() => {
                // On coupe systématiquement les loaders
                setIsPackagesLoading(false);
                setIsDockerLoading(false);
                setIsAnsibleLoading(false);
            });
        };

        // Exécution immédiate
        checkStatus();

        // Intervalle de sécurité (60s recommandé pour éviter le crash)
        const interval = setInterval(checkStatus, 35000);

        return () => {
            clearInterval(interval);
            // On nettoie aussi tes autres intervalles de polling (logs, etc.)
            if (pollingIntervals.current) {
                Object.values(pollingIntervals.current).forEach(clearInterval);
            }
        };
    }, []);
*/
    const handleAction = (packageName, action) => {
        setIsLoading(prev => ({ ...prev, [packageName]: true }));
        setExpanded(prev => ({ ...prev, [packageName]: true }));
        setOutput(prev => ({ ...prev, [packageName]: "> Starting operation...\n" }));

        const formData = new FormData();
        formData.append('action', action === 'install' ? 'wpkginst_install_package' : 'wpkginst_uninstall_package');
        formData.append('package', packageName);
        formData.append('nonce', wpkginstAjax.nonce);

        axios.post(wpkginstAjax.ajax_url, formData).then(res => {
            // On lance le polling
            const interval = setInterval(() => {
                const pollData = new FormData();
                pollData.append('action', 'wpkginst_get_background_log');

                // On ajuste le nom du log selon l'action
                const logType = action === 'install' ? 'install' : 'uninstall';
                pollData.append('log_file', `/tmp/wpkginst_${logType}_${packageName}.log`);

                pollData.append('package', packageName);
                pollData.append('nonce', wpkginstAjax.nonce);

                axios.post(wpkginstAjax.ajax_url, pollData).then(pollRes => {
                    const data = pollRes.data?.data;
                    const output = data?.output;

                    if (output) {
                        setOutput(prev => ({ ...prev, [packageName]: output }));
                    }

                    if (data?.finished === true) {
                        clearInterval(interval);
                        // On appelle checkStatus pour mettre à jour les paquets (installé/non installé)
                        // AVANT d'enlever le loader du bouton
                        checkStatus().then(() => {
                            setIsLoading(prev => ({ ...prev, [packageName]: false }));
                        });
                    }
                }).catch(err => {
                    console.error("Erreur polling logs:", err);
                    clearInterval(interval);
                    setIsLoading(prev => ({ ...prev, [packageName]: false }));
                });
            }, 2000);
        }).catch(err => {
            console.error("Erreur initiale:", err);
            setIsLoading(prev => ({ ...prev, [packageName]: false }));
        }); // <-- Fermeture du axios.post().catch()
    }; // <-- Fermeture du handleAction

    const handleDockerAction = (id, action) => {
        setIsLoading(prev => ({ ...prev, [id]: true }));
        const formData = new FormData();
        formData.append('action', 'wpkginst_docker_action');
        formData.append('id', id);
        formData.append('docker_action', action);
        formData.append('nonce', wpkginstAjax.nonce);

        axios.post(wpkginstAjax.ajax_url, formData)
            .then(() => axios.get(wpkginstAjax.ajax_url, {
                params: { action: 'wpkginst_fetch_docker_containers', nonce: wpkginstAjax.nonce }
            }))
            .then(res => { if(res.data.success) setContainers(res.data.data.containers); })
            .finally(() => setIsLoading(prev => ({ ...prev, [id]: false })));
    };

    const handleRunPlaybook = (file, id) => {
        const ansibleKey = `ansible_${id}`;
    
        // 1. Initialisation de l'UI
        setIsLoading(prev => ({ ...prev, [ansibleKey]: true }));
        setExpanded(prev => ({ ...prev, [ansibleKey]: true }));
        setOutput(prev => ({ ...prev, [ansibleKey]: "> Initializing async deployment...\n" }));
    
        const formData = new FormData();
        formData.append('action', 'wpkginst_run_playbook');
        formData.append('nonce', wpkginstAjax.nonce);
        formData.append('playbook', file);
    
        axios.post(window.wpkginstAjax.ajax_url, formData)
            .then(response => {
                if (response.data.success) {
                    const logFile = response.data.data.log_file;
    
                    // 2. Lancement du Polling
                    const pollInterval = setInterval(() => {
                        const pollData = new FormData();
                        pollData.append('action', 'wpkginst_get_background_log');
                        pollData.append('log_file', logFile);
                        pollData.append('nonce', wpkginstAjax.nonce);
    
                        axios.post(window.wpkginstAjax.ajax_url, pollData)
                            .then(pollRes => {
                                if (pollRes.data.success) {
                                    const newLogs = pollRes.data.data.output;
                                    setOutput(prev => ({ ...prev, [ansibleKey]: newLogs }));
    
                                    // 3. Condition d'arrêt (si Ansible a fini)
                                    if (newLogs.includes("PLAY RECAP") || pollRes.data.data.status === 'completed') {
                                        clearInterval(pollInterval);
                                        setIsLoading(prev => ({ ...prev, [ansibleKey]: false }));
                                    }
                                }
                            })
                            .catch(() => clearInterval(pollInterval));
                    }, 2000); // Lecture toutes les 2 secondes
                }
            })
            .catch(error => {
                setOutput(prev => ({ ...prev, [ansibleKey]: `FATAL ERROR: ${error.message}` }));
                setIsLoading(prev => ({ ...prev, [ansibleKey]: false }));
            });
    };

    const handleSyncCatalog = async () => {
        setIsSyncing(true);
        setSyncMessage("STAGING: Initializing synchronization...");

        const formData = new FormData();
        formData.append('action', 'wpkginst_sync_catalog');
        formData.append('nonce', wpkginstAjax.nonce);

        try {
            const response = await axios.post(wpkginstAjax.ajax_url, formData);
            const resData = response.data.data;

            // Fonction interne pour transformer n'importe quel objet en texte lisible
            const formatLog = (input) => {
                if (typeof input === 'string') return input;
                if (typeof input === 'object' && input !== null) {
                    return input.log || input.message || JSON.stringify(input);
                }
                return String(input);
            };

            if (response.data.success) {
                setSyncMessage(`SUCCESS: ${formatLog(resData.log)}`);
            } else {
                const rawError = formatLog(resData.log || resData.message);
                setSyncMessage(`ERROR_SYSTEM: ${rawError}`);
            }
        } catch (e) {
            setSyncMessage(`NETWORK_ERROR: ${e.message}`);
        } finally {
            setIsSyncing(false);
        }
    };

    const filteredPackages = useMemo(() => {
        if (selectedOption) {
            return packages.filter(pkg => pkg.name === selectedOption.value);
        }
        return packages.filter(pkg => pkg.name.toLowerCase().includes(filter.toLowerCase()));
    }, [packages, filter, selectedOption]);

    const renderReadinessDashboard = (readiness) => {
        const tools = readiness || {};
        const handleFix = (toolKey) => {
            const tool = tools[toolKey];
            if (!tool || !tool.install_cmd || !sshStatus.success) return;

            setReadinessStatus(prev => ({ ...prev, [toolKey]: 'loading' }));
            setOutput(prev => ({ ...prev, [`readiness_${toolKey}`]: `> Initializing fix for ${toolKey}...` }));

            const formData = new FormData();
            formData.append('action', 'wpkginst_fix_readiness');
            formData.append('tool_key', toolKey);
            formData.append('nonce', wpkginstAjax.nonce);

            axios.post(wpkginstAjax.ajax_url, formData)
                .then(response => {
                    const output = (response.data.data?.output || '').toLowerCase();

                    // LA BARRIÈRE : On vérifie si la sortie console contient des erreurs fatales
                    const hasFailed = output.includes('permission denied') ||
                                      output.includes('not found') ||
                                      output.includes('err:') ||
                                      output.includes('failed:');

                    if (response.data.success && !hasFailed) {
                        // VRAI SUCCÈS
                        setReadinessStatus(prev => ({ ...prev, [toolKey]: 'success' }));
                        setOutput(prev => ({ ...prev, [`readiness_${toolKey}`]: response.data.data.output || 'Success!' }));

                        // Optionnel : Si tu veux rafraîchir les stats sans recharger la page
                        // fetchServerStats();
                    } else {
                        // ÉCHEC (Soit PHP a dit false, soit le texte contient une erreur)
                        setReadinessStatus(prev => ({ ...prev, [toolKey]: 'error' }));

                        const errorMsg = hasFailed
                            ? `ERROR: Insufficient privileges or invalid command.\n${response.data.data.output}`
                                            : (response.data.data?.message || 'Unknown error');

                        setOutput(prev => ({ ...prev, [`readiness_${toolKey}`]: errorMsg }));
                        console.error("Fix failure:", errorMsg);
                    }
                })
                .catch((error) => {
                    setReadinessStatus(prev => ({ ...prev, [toolKey]: 'error' }));
                    setOutput(prev => ({ ...prev, [`readiness_${toolKey}`]: `ERROR: Cannot reach the server.` }));
                });
        };

        const renderToolBadge = (name, data) => {
            const versionText = data.version || '';
            const versionLow = versionText.toLowerCase();

            // Logique de détection
            const hasError = versionLow.includes('unknown') ||
                             versionLow.includes('bash:') ||
                             versionLow.includes('not found') ||
                             versionLow.includes('denied');

            const isActuallyReady = data.installed && !hasError;
            const isPermissionIssue = versionLow.includes('permission denied');
            const currentStatus = readinessStatus[name]; // 'loading', 'success', 'error' ou undefined

            return React.createElement('div', { key: name, className: 'flex items-center justify-between p-4 bg-gray-800 rounded-lg border border-gray-700 shadow-inner' },
                React.createElement('div', { className: 'flex flex-col flex-1' },
                    React.createElement('span', { className: 'text-[10px] font-bold uppercase tracking-widest text-gray-500 mb-1' }, name.replace('_', ' ')),
                    React.createElement('span', { className: `text-[11px] font-mono truncate max-w-[200px] pr-2 ${!isActuallyReady ? 'text-red-300' : 'text-gray-400'}` },
                        versionText.split('\n')[0].substring(0, 40) || (isActuallyReady ? 'Active' : 'Not detected')
                    )
                ),
                React.createElement('div', { className: 'flex items-center gap-3' },
                    // CONDITION 1 : Si c'est prêt, on affiche juste le badge READY vert
                    isActuallyReady ? (
                        React.createElement('span', { className: 'text-[9px] px-2 py-1 rounded font-black min-w-[55px] text-center text-green-400 bg-green-900/30' }, 'READY')
                    ) : (
                        // CONDITION 2 : Si ce n'est pas prêt, on affiche le bouton d'action (FIX, INSTALL ou DONE)
                        // On NE montre PAS le badge "ERROR" ici pour éviter le doublon
                        React.createElement('button', {
                            onClick: () => handleFix(name),
                            disabled: currentStatus === 'loading',
                            className: `text-[9px] px-2 py-1 rounded font-bold transition-all min-w-[60px] ${
                                (name === 'ansible' && highlightFix) ? 'ring-4 ring-yellow-400 scale-105 shadow-[0_0_20px_#facc15]' : ''
                            } ${
                                currentStatus === 'loading' ? 'bg-yellow-600 animate-pulse' :
                                currentStatus === 'success' ? 'bg-green-600' :
                                isPermissionIssue ? 'bg-orange-600' : 'bg-blue-600 hover:bg-blue-500'
                            } text-white`
                        },
                        currentStatus === 'loading' ? 'INSTALL...' :
                        currentStatus === 'success' ? 'DONE' :
                        isPermissionIssue ? 'PRIVILEGE?' : 'FIX')
                    )
                )
            );
        };

        return React.createElement('div', { className: 'mb-8', ref: readinessRef },
            React.createElement('h3', { className: 'text-white text-[10px] font-black mb-3 uppercase tracking-[0.2em] flex items-center opacity-40' },
                React.createElement('span', { className: 'mr-2' }, '▼'),
                'Infrastructure Readiness'
            ),
            React.createElement('div', { className: 'grid grid-cols-1 md:grid-cols-3 gap-4' },
                Object.keys(tools).map(key => renderToolBadge(key, tools[key]))
            ),
            React.createElement('div', { className: 'mt-4 bg-black rounded-lg p-3 font-mono text-[10px] border border-gray-800' },
                React.createElement('div', { className: 'text-gray-500 mb-2' }, '> Infrastructure deployment console...'),
                React.createElement('pre', { className: 'text-blue-400 overflow-y-auto max-h-32' },
                    Object.entries(readinessStatus).map(([tool, status]) =>
                        status === 'loading' ? `[SYSTEM] Installing ${tool}...\n` : ''
                    )
                )
            ),
            Object.keys(readinessStatus).some(k => output[`readiness_${k}`]) && React.createElement('div', {
                className: 'mt-4 bg-black/80 rounded-lg p-4 font-mono text-[11px] border border-blue-900/30 shadow-2xl'
            },
                React.createElement('div', { className: 'text-blue-500 mb-2 flex items-center gap-2' },
                    React.createElement('span', { className: 'animate-pulse' }, '●'),
                    'INFRASTRUCTURE_LOGS:'
                ),
                React.createElement('button', {
                    onClick: () => {
                        const newOutput = { ...output };
                        Object.keys(newOutput).forEach(k => {
                            if(k.startsWith('readiness_')) delete newOutput[k];
                        });
                        setOutput(newOutput);
                    },
                    className: 'text-[9px] bg-red-900/50 hover:bg-red-800 px-2 py-1 rounded text-white font-bold'
                }, 'CLOSE & REFRESH'),
                Object.keys(readinessStatus).map(key =>
                    output[`readiness_${key}`] && React.createElement('pre', {
                        key: `log_${key}`,
                        className: 'text-gray-300 whitespace-pre-wrap mb-2 p-2 bg-white/5 rounded'
                    }, `[${key.toUpperCase()}] ${output[`readiness_${key}`]}`)
                )
            )
        );
    };

    // RENDU FINAL DU COMPOSANT
    return React.createElement('div', { className: 'p-6 max-w-7xl mx-auto' },
        renderReadinessDashboard(window.wpkginstAjax.readiness),

        // Header & Gauges avec Intégration de la Grue
        React.createElement('div', { className: 'mb-8 bg-gray-900 p-6 rounded-xl shadow-2xl border-b-4 border-blue-500 text-white' },
            React.createElement('div', { className: 'flex justify-between items-center mb-6' },
                React.createElement('div', null,
                    React.createElement('h2', { className: 'text-2xl font-black tracking-tighter text-blue-400' }, 'WP DEVOPS DASHBOARD'),
                    React.createElement('p', { className: 'text-[10px] font-mono text-gray-500' }, `OS: ${serverStats.distro}`)
                ),

                // --- GROUPE ACTIONS & STATUT ---
                React.createElement('div', { className: 'flex items-center gap-3' },
                    // BOUTON SYNC (LA GRUE)
                    React.createElement('button', {
                        onClick: handleSyncCatalog,
                        disabled: isSyncing || !sshStatus.success,
                        className: `flex items-center bg-blue-600 hover:bg-blue-500 px-3 py-1.5 rounded-full border border-blue-400 transition-all shadow-[0_0_15px_rgba(37,99,235,0.2)] ${isSyncing ? 'animate-pulse cursor-wait' : ''} ${highlightSync ? 'ring-4 ring-orange-500 scale-110 shadow-[0_0_25px_#f97316]' : ''}`
                    },
                        React.createElement('span', { className: 'text-[9px] font-black text-white' }, isSyncing ? 'SYNCING...' : '🏗️ SYNC ANSIBLE CATALOG')
                    ),
                    // INDICATEUR SSH
                    React.createElement('div', { className: 'flex items-center bg-black/50 px-3 py-1.5 rounded-full border border-gray-700' },
                        React.createElement('span', { className: `h-2 w-2 rounded-full mr-2 flex-shrink-0 ${sshStatus.success ? 'bg-green-500 shadow-[0_0_8px_#00ff00]' : isInitialFetch.current ? 'bg-yellow-400 animate-pulse' : 'bg-red-500'}` }),
                        React.createElement('span', { className: 'text-[10px] font-mono' },
                            !sshStatus.success && isInitialFetch.current
                                ? 'Establishing SSH connection…'
                                : sshStatus.message
                        )
                    )
                )
            ),

            // ZONE DE MESSAGE DYNAMIQUE (La phrase qui s'auto-écrase)
            syncMessage ? React.createElement('div', {
                className: `mb-6 p-4 rounded border-l-4 font-mono text-[11px] shadow-lg animate-in fade-in slide-in-from-top-2 duration-300 ${
                    syncMessage.includes('ERROR') || syncMessage.includes('FATAL')
                    ? 'bg-red-900/20 border-red-600 text-red-200'
                    : 'bg-blue-900/20 border-blue-500 text-blue-300'
                }`
            },
                React.createElement('div', { className: 'flex justify-between items-start mb-2' },
                    React.createElement('span', { className: 'font-bold uppercase tracking-widest text-[9px] opacity-60' },
                        syncMessage.includes('ERROR') ? '[ SYSTEM_FAILURE_DUMP ]' : '[ SYSTEM_SYNC_LOG ]'
                    ),
                    React.createElement('button', {
                        onClick: () => setSyncMessage(""),
                        className: 'text-[9px] hover:text-white border border-current px-1 rounded'
                    }, 'CLOSE')
                ),
                React.createElement('pre', {
                    className: 'whitespace-pre-wrap break-all bg-black/40 p-3 rounded border border-white/5 max-h-40 overflow-y-auto'
                }, syncMessage)
            ) : null,

            // LES GAUGES NUCLEAIRES
            React.createElement('div', { className: 'grid grid-cols-3 gap-8' },
                renderNuclearGauge('RAM', serverStats.ram?.split(',')[1], serverStats.ram?.split(',')[0], 'MB'),
                renderNuclearGauge('DISK', serverStats.disk?.split(',')[1], serverStats.disk?.split(',')[0], 'GB'),
                renderNuclearGauge('CPU Load', serverStats.cpu, 100, '%')
            )
        ),

        // Search Select
        React.createElement(Select, {
            options: packages.map(p => ({ value: p.name, label: p.name })),
            onChange: (opt) => setSelectedOption(opt),
            onInputChange: (val) => setFilter(val),
            placeholder: 'Search for a specific package...',
            className: 'mb-8 shadow-sm',
            isClearable: true
        }),

        // Packages Table
        // Section Stats & Accordéon des Packages
        React.createElement('div', { className: 'flex flex-col gap-4 mb-12' },
            // 1. L'en-tête (Barre de contrôle)
            React.createElement('div', { className: 'flex items-center justify-between bg-white p-6 rounded-[2rem] border border-slate-100 shadow-sm' },
                React.createElement('div', { className: 'flex items-center gap-4' },
                    React.createElement('span', { className: 'text-sm font-medium text-slate-500' }, 'Installed packages:'),
                    React.createElement('span', { className: 'px-3 py-1 bg-blue-50 text-blue-600 rounded-full font-bold text-sm' },
                        `${packages.filter(p => p.installed).length} / ${packages.length}`
                    )
                ),
                React.createElement('button', {
                    onClick: () => {
                        const next = !isPackagesOpen;
                        setIsPackagesOpen(next);
                        if (next && packages.length === 0) {
                            isPackagesOpenRef.current = true;
                            checkStatus();
                        }
                    },
                    className: 'flex items-center gap-2 px-4 py-2 rounded-xl border border-slate-200 hover:bg-slate-50 transition-all text-xs font-bold text-slate-600'
                },
                    isPackagesOpen ? 'Hide details' : 'Manage PHP packages',
                    React.createElement('span', {
                        className: `transition-transform duration-300 ${isPackagesOpen ? 'rotate-180' : ''}`
                    }, '▼')
                )
            ),

            // 2. Le corps de l'accordéon (Contient ta table originale)
            React.createElement('div', {
                className: `overflow-hidden transition-all duration-500 ease-in-out ${isPackagesOpen ? 'max-h-[5000px] opacity-100' : 'max-h-0 opacity-0'}`
            },
                React.createElement('div', { className: 'bg-white rounded-[2rem] border border-slate-100 shadow-lg overflow-hidden' },
                    React.createElement('table', { className: 'w-full text-left border-collapse' },
                        React.createElement('thead', { className: 'bg-slate-50 border-b border-slate-100' },
                            React.createElement('tr', null,
                                ['Package', 'Statut', 'Action', 'Progression', 'Log'].map(h =>
                                    React.createElement('th', { key: h, className: 'px-6 py-4 text-[10px] font-black text-slate-400 uppercase tracking-widest' }, h)
                                )
                            )
                        ),
                        React.createElement('tbody', { className: 'divide-y divide-slate-50' },
                            isPackagesLoading ?
                                [1,2,3].map(i => React.createElement('tr', { key: i },
                                    React.createElement('td', { colSpan: 5, className: 'px-6 py-8 animate-pulse bg-gray-50/50' },
                                        React.createElement('div', { className: 'h-4 bg-gray-200 rounded w-full' })
                                    )
                                )) :
                                filteredPackages.map(pkg => [
                                    React.createElement('tr', { key: pkg.name, className: 'hover:bg-slate-50 transition-colors' },
                                        React.createElement('td', { className: 'px-6 py-4 font-medium text-slate-900' }, pkg.name),
                                        React.createElement('td', { className: 'px-6 py-4' },
                                            React.createElement('span', { className: `px-2 py-1 rounded-md text-[10px] font-bold ${pkg.installed ? 'bg-green-100 text-green-700' : 'bg-slate-100 text-slate-500'}` }, 
                                                pkg.installed ? 'INSTALLED' : 'AVAILABLE'
                                            )
                                        ),
                                        React.createElement('td', { className: 'px-6 py-4' },
                                            React.createElement('button', {
                                                onClick: () => handleAction(pkg.name, pkg.installed ? 'uninstall' : 'install'),
                                                disabled: isLoading[pkg.name],
                                                className: `px-4 py-1.5 rounded-lg text-xs font-bold transition-all ${
                                                    pkg.installed ? 'bg-white border border-red-200 text-red-600 hover:bg-red-50' : 'bg-blue-600 text-white hover:bg-blue-700'
                                                } ${isLoading[pkg.name] ? 'opacity-50 cursor-wait' : ''}`
                                            }, isLoading[pkg.name] ? 'Please wait...' : (pkg.installed ? 'Remove' : 'Install'))
                                        ),
                                        React.createElement('td', { className: 'px-6 py-4 w-48' },
                                            React.createElement('div', { className: 'w-full bg-slate-100 rounded-full h-1.5 overflow-hidden' },
                                                React.createElement('div', {
                                                    className: `h-1.5 rounded-full transition-all shadow-sm ${isLoading[pkg.name] ? 'bg-blue-400 animate-pulse' : 'bg-blue-600'}`,
                                                    style: {
                                                        width: progress[pkg.name] || '0%',
                                                        transition: 'width 0.8s cubic-bezier(0.4, 0, 0.2, 1)'
                                                    }
                                                })
                                            )
                                        ),
                                        React.createElement('td', { className: 'px-6 py-4 text-center' },
                                            React.createElement('button', {
                                                onClick: () => setExpanded(prev => ({...prev, [pkg.name]: !prev[pkg.name]})),
                                                className: `p-2 rounded-md transition-colors ${expanded[pkg.name] ? 'bg-blue-50 text-blue-600' : 'text-slate-300 hover:text-slate-600'}`
                                            }, '👁️')
                                        )
                                    ),
                                    expanded[pkg.name] && React.createElement('tr', { key: `${pkg.name}-log` },
                                        React.createElement('td', { colSpan: 5, className: 'px-6 py-4 bg-slate-900' },
                                            React.createElement('pre', { className: 'text-[11px] text-green-400 font-mono overflow-x-auto max-h-60 whitespace-pre-wrap' },
                                                output[pkg.name] || `> Initializing ${pkg.name}...`
                                            )
                                        )
                                    )
                                ])
                        )
                    )
                )
            )
        ),

        // --- SECTION AUTOMATISATION (ANSIBLE) ---
        React.createElement('h3', {
          className: 'text-2xl font-bold mb-8 text-slate-800 flex items-center gap-3 tracking-tight'
        },
          React.createElement('span', { className: 'text-3xl' }, '🤖'),
          'Automation & Playbooks'
        ),

        React.createElement('div', { className: 'grid grid-cols-1 lg:grid-cols-2 gap-8 mb-12' },
           isAnsibleLoading ?
            [1,2,3,4].map(i =>
              React.createElement('div', {
                key: i,
                className: 'h-64 bg-gray-200 animate-pulse rounded-[2rem] border border-gray-100'
                // className: 'h-64 bg-slate-50 animate-pulse rounded-[2rem] border border-slate-100'
              })
            ) :
          // 2. État "Catalogue absent" (Seulement si le chargement est bien fini ET vide)
          (!ansiblePackages || ansiblePackages.length === 0) ? (
            React.createElement('div', {
              className: 'col-span-full bg-white border border-slate-100 rounded-[2rem] p-16 text-center shadow-sm'
            },
              React.createElement('div', { className: 'text-6xl mb-6 grayscale opacity-20' }, '🏗️'),
              React.createElement('h3', { className: 'text-xl font-bold text-slate-900 mb-2' }, 'No catalog found'),
              React.createElement('p', { className: 'text-slate-500 mb-8 max-w-sm mx-auto text-sm' },
                'The playbook directory could not be found. A sync is required.'
              ),
              React.createElement('button', {
                onClick: () => {
                  window.scrollTo({ top: 0, behavior: 'smooth' });
                  setHighlightSync(true);
                  setTimeout(() => setHighlightSync(false), 3000);
                },
                className: 'bg-blue-600 hover:bg-blue-500 text-white text-[10px] font-black tracking-[0.2em] uppercase py-3 px-10 rounded-xl shadow-lg transition-all hover:scale-105 active:scale-95'
              }, 'Sync now')
            )
          ) : (
            ansiblePackages.map(pkg => {
              const isReady = isAnsibleReady;
              const isRunning = isLoading[`ansible_${pkg.id}`];
              const isExpanded = expanded[`ansible_${pkg.id}`];

              let icon = pkg.icon || '📜';
              if (pkg.name.toLowerCase().includes('redis')) icon = '🔴';
              if (pkg.name.toLowerCase().includes('mariadb') || pkg.name.toLowerCase().includes('mysql')) icon = '🗄️';

              return React.createElement('div', {
                key: pkg.id,
                className: 'group bg-white rounded-[2rem] overflow-hidden border border-slate-100 shadow-sm hover:shadow-md transition-all duration-500'
              },
                React.createElement('div', { className: 'p-8' },
                  React.createElement('div', { className: 'flex items-start gap-5 mb-8' },
                    React.createElement('div', {
                      className: 'w-14 h-14 flex-shrink-0 rounded-2xl flex items-center justify-center text-3xl bg-slate-50 grayscale opacity-80 group-hover:grayscale-0 group-hover:opacity-100 transition-all' 
                    }, icon),
                    React.createElement('div', { className: 'flex-1' },
                      React.createElement('h4', { className: 'font-bold text-lg text-slate-900 mb-1 tracking-tight' }, pkg.name),
                      React.createElement('p', { className: 'text-slate-400 text-xs leading-relaxed line-clamp-2' }, pkg.description)
                    )
                  ),

                  React.createElement('div', { className: 'flex gap-2' },
                    React.createElement('button', {
                      onClick: () => {
                        if (isReady) handleRunPlaybook(pkg.playbook, pkg.id);
                      },
                      disabled: isReady && isRunning,
                      style: { flexBasis: '66%', flexShrink: 0 },
                      className: `px-4 py-2.5 rounded-xl text-xs font-bold tracking-wide uppercase transition-all shadow-sm ${
                        !isReady
                          ? 'bg-slate-100 text-slate-400 border border-slate-100'
                          : isRunning
                            ? 'bg-blue-600 text-white animate-pulse'
                            : 'bg-blue-600 text-white hover:bg-blue-500 active:scale-95'
                      }`
                    },
                      !isReady ? 'Unavailable' : (isRunning ? 'Running...' : 'Deploy')
                    ),

                    React.createElement('button', {
                      onClick: () => setExpanded(prev => ({...prev, [`ansible_${pkg.id}`]: !isExpanded})),
                      style: { flexBasis: '34%', flexShrink: 0 },
                      className: `py-2.5 rounded-xl border-2 text-xs font-bold tracking-wide uppercase transition-all ${
                        isExpanded
                        ? 'bg-slate-900 border-blue-600 text-blue-400 shadow-lg'
                        : 'border-slate-200 text-slate-400 hover:bg-blue-600 hover:border-blue-600 hover:text-white hover:shadow-[0_0_15px_rgba(37,99,235,0.4)]'
                      }`
                    }, 'Logs')
                  )
                ),

                // Section Console - Style sombre
                isExpanded && React.createElement('div', {
                  className: 'bg-slate-950 border-t border-slate-800 p-6'
                },
                  React.createElement('pre', {
                    id: `console-ansible-${pkg.id}`,
                    className: 'text-blue-400/90 font-mono text-[10px] overflow-auto max-h-48 whitespace-pre-wrap leading-relaxed'
                  },
                    output[`ansible_${pkg.id}`] || '> Connection established. Awaiting signal...'
                  )
                )
              );
            })
          )
        ),

        // Docker Section
        React.createElement('h3', { className: 'text-xl font-bold mb-6 text-gray-800 flex items-center' },
            React.createElement('span', { className: 'p-2 bg-blue-100 rounded-lg mr-3' }, '🐳'),
            'Containers Infrastructure'
        ),
        React.createElement('div', { className: 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6' },
            //isDockerLoading ? [1,2].map(i => React.createElement('div', { key: i, className: 'h-32 bg-gray-100 animate-pulse rounded-xl' })) :
            (isDockerLoading && containers.length === 0) ? [1,2].map(i => React.createElement('div', { key: i, className: 'h-32 bg-gray-100 animate-pulse rounded-xl' })) :
            containers.map(container => React.createElement('div', { key: container.ID, className: 'bg-white p-5 rounded-xl shadow-md border border-gray-100' },
                React.createElement('div', { className: 'flex justify-between items-start mb-4' },
                    React.createElement('div', null,
                        React.createElement('h4', { className: 'font-bold text-gray-900' }, container.Names),
                        React.createElement('p', { className: 'text-xs text-gray-400 font-mono' }, container.Image)
                    ),
                    React.createElement('span', { className: `text-[10px] px-2 py-1 rounded-full font-black uppercase ${container.Status.includes('Up') ? 'bg-green-100 text-green-600' : 'bg-red-100 text-red-600'}` },
                        container.Status.includes('Up') ? 'Online' : 'Stopped'
                    )
                ),
                React.createElement('div', { className: 'flex gap-2' },
                    React.createElement('button', {
                        onClick: () => handleDockerAction(container.ID, container.Status.includes('Up') ? 'stop' : 'start'),
                        disabled: isLoading[container.ID],
                        className: `flex-1 py-2 rounded-lg text-xs font-bold ${isLoading[container.ID] ? 'opacity-50' : ''} ${container.Status.includes('Up') ? 'bg-gray-100 text-gray-700' : 'bg-green-600 text-white'}`
                    }, isLoading[container.ID] ? '...' : (container.Status.includes('Up') ? 'Stop' : 'Start')),
                    React.createElement('button', {
                        onClick: () => handleDockerAction(container.ID, 'restart'),
                        disabled: isLoading[container.ID],
                        className: `px-3 py-2 bg-blue-50 text-blue-600 rounded-lg hover:bg-blue-100 ${isLoading[container.ID] ? 'animate-pulse' : ''}`
                    }, '🔄')
                )
            ))
        )
    );
};

// HELPER GAUGE (Doit être en dehors de PackageManager ou dedans avant le return)
const renderNuclearGauge = (label, used, total, unit) => {
    const valUsed = parseFloat(used) || 0;
    const valTotal = parseFloat(total) || 1;
    const percent = Math.min(Math.round((valUsed / valTotal) * 100), 100);
    const color = percent > 90 ? '#ff4444' : (percent > 70 ? '#ffbb33' : '#00ffcc');

    return React.createElement('div', { className: 'flex flex-col' },
        React.createElement('div', { className: 'flex justify-between text-[10px] font-mono mb-1 text-gray-400' },
            React.createElement('span', null, label),
            React.createElement('span', null, `${used}/${total} ${unit}`)
        ),
        React.createElement('div', { className: 'h-1.5 bg-gray-800 rounded-full overflow-hidden border border-gray-700' },
            React.createElement('div', {
                style: {
                    width: `${percent}%`,
                    backgroundColor: color,
                    boxShadow: `0 0 10px ${color}`,
                    transition: 'width 1.5s cubic-bezier(0.4, 0, 0.2, 1)'
                },
                className: 'h-full'
            })
        )
    );
};

const rootEl = document.getElementById('wpkginst-package-manager');
if (rootEl) createRoot(rootEl).render(React.createElement(PackageManager));
