document.addEventListener('DOMContentLoaded', () => {

    // --- INIT ICONS ---
    if (typeof lucide !== 'undefined') {
        lucide.createIcons();
    }

    // --- UTILS ---
    const dom = (id) => document.getElementById(id);
    const show = (el) => el && el.classList.remove('hidden');
    const hide = (el) => el && el.classList.add('hidden');

    const showToast = (msg) => {
        const t = dom('toast');
        if (!t) return;
        t.textContent = msg;
        show(t);
        setTimeout(() => hide(t), 3000);
    };
    window.showToast = showToast;

    const showConfirmModal = (title, message, options = {}) => {
        return new Promise((resolve) => {
            const confirmText = options.confirmText || 'Confirmer';
            const cancelText = options.cancelText || 'Annuler';
            const isDestructive = options.isDestructive !== false;
            
            const overlay = document.createElement('div');
            overlay.className = 'modal-overlay';
            overlay.style.zIndex = '30000';
            overlay.innerHTML = `
                <div class="modal-content" style="max-width: 400px; text-align: center; animation: modalFadeIn 0.2s ease-out;">
                    <div style="margin-bottom: 1rem; color: ${isDestructive ? 'var(--primary)' : '#60a5fa'};">
                        <i data-lucide="${isDestructive ? 'alert-triangle' : 'help-circle'}" style="width: 48px; height: 48px; margin: 0 auto;"></i>
                    </div>
                    <h3 style="margin-bottom: 0.75rem; font-size: 1.25rem; font-weight: 700; color: white;">${title}</h3>
                    <p style="font-size: 0.9rem; color: var(--text-sec); margin-bottom: 1.5rem; line-height: 1.4;">${message}</p>
                    
                    <div style="display: flex; flex-direction: column; gap: 8px;">
                        <button id="confirm-yes-btn" class="${isDestructive ? 'btn-primary' : 'btn-success'}" style="width: 100%; display: flex; justify-content: center; align-items: center; gap: 8px; padding: 12px;">
                            ${confirmText}
                        </button>
                        <button id="confirm-no-btn" class="btn-action" style="width: 100%; background: transparent; border: 1px solid var(--border); color: var(--text-sec); justify-content: center; display: flex; align-items: center; padding: 12px;">
                            ${cancelText}
                        </button>
                    </div>
                </div>
            `;
            
            document.body.appendChild(overlay);
            if (window.lucide) {
                window.lucide.createIcons({ root: overlay });
            }
            
            const cleanUp = (value) => {
                overlay.style.opacity = '0';
                overlay.style.transition = 'opacity 0.2s ease';
                setTimeout(() => {
                    overlay.remove();
                }, 200);
                resolve(value);
            };
            
            overlay.querySelector('#confirm-yes-btn').onclick = () => cleanUp(true);
            overlay.querySelector('#confirm-no-btn').onclick = () => cleanUp(false);
            
            overlay.onclick = (e) => {
                if (e.target === overlay) cleanUp(false);
            };
        });
    };

    const updateSiteStatusUI = (isOffline, message) => {
        let banner = dom('offline-banner');
        if (!banner) {
            banner = document.createElement('div');
            banner.id = 'offline-banner';
            banner.style = "background: #e50914; color: white; text-align: center; padding: 10px; font-weight: 700; position: sticky; top: 0; z-index: 9999; display: none; font-size: 0.9rem;";
            document.body.prepend(banner);
        }
        if (isOffline) {
            banner.textContent = `⚠️ SITE SOURCE INDISPONIBLE : ${message || 'Vérification en cours...'}`;
            banner.style.display = 'block';
        } else {
            banner.style.display = 'none';
        }
    };

    const apiCall = async (endpoint, method = 'GET', body = null) => {
        if (!endpoint.startsWith('/api')) {
            endpoint = endpoint.startsWith('/') ? `/api${endpoint}` : `/api/${endpoint}`;
        }
        try {
            const opts = {
                method,
                headers: { 'Content-Type': 'application/json' }
            };
            if (body) opts.body = JSON.stringify(body);

            const res = await fetch(endpoint, opts);
            const text = await res.text();

            if (!res.ok) {
                let err = `Erreur ${res.status}`;
                try { err = JSON.parse(text).error || err; } catch (e) { }
                throw new Error(err);
            }
            return text ? JSON.parse(text) : {};
        } catch (e) {
            console.error(`API ${endpoint}:`, e);
            throw e;
        }
    };

    // --- STATE & LOOPS MANAGER ---
    const state = {
        downloadInterval: null,
        trendingData: { films: [], series: [], recent: [] },
        activeSources: [],
        availableSources: [], // Dynamically populated from /status
        sourceLabels: {},
    };

    // --- GESTION INTELLIGENTE DES BOUCLES ---

    const getPref = (key, defaultValue) => {
        if (state.currentUser && state.currentUser.preferences && state.currentUser.preferences[key] !== undefined) {
            return state.currentUser.preferences[key];
        }
        const local = localStorage.getItem(key);
        if (local !== null) return local === 'true' ? true : (local === 'false' ? false : local);
        return defaultValue;
    };

    const setPref = async (key, value) => {
        localStorage.setItem(key, value);
        if (state.currentUser) {
            if (!state.currentUser.preferences) state.currentUser.preferences = {};
            state.currentUser.preferences[key] = value;
        }
        try {
            await apiCall('/api/preferences', 'POST', { key, value });
        } catch (e) {
            console.error('Erreur sauvegarde pref', e);
        }
    };
    // 1. Gestion Téléchargements (Actif seulement sur l'onglet)
    const startDownloadLoop = () => {
        if (state.downloadInterval) clearInterval(state.downloadInterval);
        loadDownloads(); // Appel immédiat
        state.downloadInterval = setInterval(loadDownloads, 5000); // Mise à jour toutes les 5s
        console.log("Flux Téléchargement : ACTIVÉ");
    };





    // La boucle des téléchargements a été déplacée à la fin du fichier.

    // --- LOGIN --- (handled in login.ejs inline script, not here)

    const checkSession = async () => {
        try {
            const res = await apiCall('/check-session');
            if (res.isLoggedIn) {
                // Stocker les infos user pour usage dans l'app
                state.currentUser = res.user || null;
                if (dom('login-form')) {
                    const allowedPages = ['/trending', '/recent', '/search', '/downloads', '/manual', '/settings'];
                    const savedPage = localStorage.getItem('defaultPage') || '/trending';
                    window.location.href = allowedPages.includes(savedPage) ? savedPage : '/trending';
                } else {
                    initApp();
                }
            } else {
                if (!dom('login-form')) {
                    window.location.href = '/login';
                }
            }
        } catch (e) { }
    };

    const initApp = async () => {
        hide(dom('login-overlay'));
        show(dom('app-container'));

        const getCookie = (name) => {
            const value = `; ${document.cookie}`;
            const parts = value.split(`; ${name}=`);
            if (parts.length === 2) return parts.pop().split(';').shift();
            return null;
        };

        const showMustChangePasswordOverlay = () => {
            const existing = document.getElementById('change-password-overlay');
            if (existing) return;

            const overlay = document.createElement('div');
            overlay.id = 'change-password-overlay';
            overlay.innerHTML = `
                <div class="change-password-box">
                    <h2>Sécurité requise</h2>
                    <p>Votre compte utilise un mot de passe temporaire ou réinitialisé. Vous devez définir un nouveau mot de passe sécurisé pour continuer.</p>
                    
                    <div class="password-requirements" style="text-align: left;">
                        <strong>Exigences du mot de passe :</strong>
                        <ul style="margin-top: 8px;">
                            <li id="req-length" class="invalid" style="display: flex; align-items: center; gap: 6px; font-size: 0.8rem;"><span class="icon-holder"><i data-lucide="x" style="width:14px;height:14px;"></i></span> Au moins 8 caractères</li>
                            <li id="req-upper" class="invalid" style="display: flex; align-items: center; gap: 6px; font-size: 0.8rem;"><span class="icon-holder"><i data-lucide="x" style="width:14px;height:14px;"></i></span> Au moins une majuscule (A-Z)</li>
                            <li id="req-number" class="invalid" style="display: flex; align-items: center; gap: 6px; font-size: 0.8rem;"><span class="icon-holder"><i data-lucide="x" style="width:14px;height:14px;"></i></span> Au moins un chiffre (0-9)</li>
                            <li id="req-special" class="invalid" style="display: flex; align-items: center; gap: 6px; font-size: 0.8rem;"><span class="icon-holder"><i data-lucide="x" style="width:14px;height:14px;"></i></span> Au moins un caractère spécial</li>
                            <li id="req-match" class="invalid" style="display: flex; align-items: center; gap: 6px; font-size: 0.8rem;"><span class="icon-holder"><i data-lucide="x" style="width:14px;height:14px;"></i></span> Mots de passe identiques</li>
                        </ul>
                    </div>

                    <form id="force-change-pw-form" style="margin-top: 1rem;">
                        <div style="margin-bottom: 1rem; text-align: left;">
                            <label for="force-new-pw" style="display: block; margin-bottom: 6px;">Nouveau mot de passe</label>
                            <div class="password-container">
                                <input type="password" id="force-new-pw" required autocomplete="new-password">
                                <button type="button" class="toggle-password" tabindex="-1">
                                    <i data-lucide="eye" class="eye-icon"></i>
                                </button>
                            </div>
                        </div>

                        <div style="margin-bottom: 1.25rem; text-align: left;">
                            <label for="force-confirm-pw" style="display: block; margin-bottom: 6px;">Confirmer le mot de passe</label>
                            <div class="password-container">
                                <input type="password" id="force-confirm-pw" required autocomplete="new-password">
                                <button type="button" class="toggle-password" tabindex="-1">
                                    <i data-lucide="eye" class="eye-icon"></i>
                                </button>
                            </div>
                        </div>

                        <div id="force-pw-error" style="color: #ef4444; font-size: 0.85rem; display: none; font-weight: 600; margin-bottom: 1rem; text-align: left;"></div>

                        <button type="submit" id="btn-force-pw-submit" class="btn-primary" style="width: 100%; display: flex; justify-content: center; align-items: center; gap: 8px;" disabled>
                            Mettre à jour le mot de passe
                        </button>
                        
                        <button type="button" id="btn-force-logout" class="btn-action" style="width: 100%; background: transparent; border: 1px solid var(--border); color: var(--text-sec); margin-top: 0.5rem; justify-content: center; display: flex; align-items: center; gap: 8px;">
                            Se déconnecter
                        </button>
                    </form>
                </div>
            `;
            document.body.appendChild(overlay);
            if (window.lucide) {
                window.lucide.createIcons({ root: overlay });
            }

            const newPwInput = overlay.querySelector('#force-new-pw');
            const confirmPwInput = overlay.querySelector('#force-confirm-pw');
            const form = overlay.querySelector('#force-change-pw-form');
            const errorDiv = overlay.querySelector('#force-pw-error');
            const submitBtn = overlay.querySelector('#btn-force-pw-submit');
            const logoutBtn = overlay.querySelector('#btn-force-logout');

            const validateInputs = () => {
                if (!window.AuthHelpers) return;
                const val = newPwInput.value;
                const confirmVal = confirmPwInput.value;

                const statuses = AuthHelpers.validateComplexity(val, confirmVal);
                AuthHelpers.updateRequirementsUI(overlay, statuses);

                submitBtn.disabled = !statuses.allValid;
            };

            newPwInput.addEventListener('input', validateInputs);
            confirmPwInput.addEventListener('input', validateInputs);

            if (window.AuthHelpers) {
                AuthHelpers.initPasswordToggles(overlay);
            }

            logoutBtn.onclick = async () => {
                try {
                    await apiCall('/logout', 'POST');
                    window.location.href = '/login';
                } catch (e) {
                    window.location.href = '/login';
                }
            };

            form.onsubmit = async (e) => {
                e.preventDefault();
                errorDiv.style.display = 'none';
                errorDiv.textContent = '';

                try {
                    const res = await apiCall('/change-password', 'POST', { newPassword: newPwInput.value });
                    if (res.success) {
                        showToast('✓ Mot de passe mis à jour avec succès !');
                        overlay.remove();
                        if (state.currentUser) {
                            state.currentUser.mustChangePassword = false;
                        }
                    }
                } catch (err) {
                    errorDiv.textContent = err.message || "Une erreur est survenue.";
                    errorDiv.style.display = 'block';
                }
            };
        };

        // --- Forced Password Change Checker ---
        if (state.currentUser && state.currentUser.mustChangePassword) {
            showMustChangePasswordOverlay();
            return; // Bloquer la suite de l'initialisation de l'application
        }

        // --- Auth Error Toast Checker ---
        const authError = getCookie('authError');
        if (authError) {
            // Delete the cookie
            document.cookie = "authError=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
            showToast(decodeURIComponent(authError).replace(/\+/g, ' '));
        }
        
        // --- JDownloader Toggle ---
        const toggleJd = document.getElementById('toggle-jd');
        if (toggleJd) {
            toggleJd.checked = getPref('useJD', false);
            toggleJd.addEventListener('change', (e) => setPref('useJD', e.target.checked));
        }

        // --- Default Preferred Page ---
        const selectDefaultPage = document.getElementById('select-default-page');
        if (selectDefaultPage) {
            const setCookie = (name, value, days = 365) => {
                const date = new Date();
                date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
                document.cookie = `${name}=${value}; expires=${date.toUTCString()}; path=/`;
            };

            const savedPage = getPref('defaultPage', '/trending');
            selectDefaultPage.value = savedPage;
            
            // Sync cookie
            setCookie('defaultPage', savedPage);

            selectDefaultPage.addEventListener('change', (e) => {
                const newPage = e.target.value;
                setCookie('defaultPage', newPage);
                setPref('defaultPage', newPage);
                showToast('Page par défaut mise à jour');
            });
        }

        // --- Source Detection & Dynamic Options ---
        try {
            const statusData = await apiCall('/status');
            state.activeSources = statusData.activeSources || [];
            state.availableSources = statusData.availableSources || [];
            state.sourceLabels = statusData.sourceLabels || {};
            renderSourcesUI();
            updateLocalDbFiltersVisibility();
        } catch(e) { console.error('Erreur détection source:', e); }

        loadTrending();
        lucide.createIcons();
        document.querySelectorAll('input[name="trending-type"]').forEach(radio => {
            radio.addEventListener('change', renderTrending);
        });

        // --- HEARTBEAT : Détection source down + Refresh Tendances ---
        let wasOffline = false;
        const checkSourceStatus = async () => {
            try {
                const s = await apiCall('/status');
                updateSiteStatusUI(s.isOffline, s.message);
                state.activeSources = s.activeSources || [];
                state.sourceLabels = s.sourceLabels || {};
                
                const searchInput = dom('search-input');
                const searchBtn = dom('btn-search-trigger');
                if (searchInput) searchInput.disabled = s.isOffline;
                if (searchBtn) searchBtn.disabled = s.isOffline;

                if (!s.isOffline && (wasOffline || (!state.trendingData.films.length && !state.trendingData.series.length))) {
                    console.log('[Heartbeat] Site source en ligne, rechargement des tendances...');
                    loadTrending();
                }
                wasOffline = s.isOffline;
                updateLocalDbFiltersVisibility();
            } catch (e) {
                wasOffline = true;
                updateSiteStatusUI(true, 'Connexion au serveur perdue...');
            }
        };

        setInterval(checkSourceStatus, 30000);

        // ========================= ADMIN USER MANAGEMENT =========================
        const adminUsersList = dom('admin-users-list');
        if (adminUsersList && state.currentUser && state.currentUser.role === 'admin') {
            
            const loadAdminUsers = async () => {
                try {
                    const users = await apiCall('/admin/users');
                    adminUsersList.innerHTML = '';

                    users.forEach(user => {
                        const isCurrentUser = state.currentUser && state.currentUser.username === user.username;
                        const roleColor = user.role === 'admin' ? 'var(--primary)' : '#22c55e';
                        const roleLabel = user.role === 'admin' ? 'Admin' : 'Utilisateur';
                        
                        const item = document.createElement('div');
                        item.className = 'admin-user-item';
                        item.style.cssText = 'display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; background: var(--bg-main); border: 1px solid var(--border); border-radius: 10px;';
                        
                        item.innerHTML = `
                            <div style="display: flex; align-items: center; gap: 10px;">
                                <div style="width: 36px; height: 36px; border-radius: 50%; background: ${user.role === 'admin' ? 'rgba(229,9,20,0.15)' : 'rgba(34,197,94,0.15)'}; display: flex; align-items: center; justify-content: center;">
                                    <i data-lucide="${user.role === 'admin' ? 'shield' : 'user'}" style="width: 16px; height: 16px; color: ${roleColor};"></i>
                                </div>
                                <div>
                                    <div style="font-weight: 600; font-size: 0.9rem;">${user.username}${isCurrentUser ? ' <span style="font-size: 0.7rem; color: var(--text-sec);">(vous)</span>' : ''}</div>
                                    <div style="font-size: 0.75rem; color: ${roleColor}; font-weight: 500;">${roleLabel}</div>
                                </div>
                            </div>
                            <div style="display: flex; gap: 6px;">
                                <button class="admin-reset-pw-btn" data-id="${user.id}" data-name="${user.username}" title="Réinitialiser le mot de passe" style="background: rgba(96,165,250,0.2); border: 1px solid rgba(96,165,250,0.4); color: #60a5fa; padding: 6px 10px; border-radius: 6px; cursor: pointer; font-size: 0.8rem;">
                                    <i data-lucide="key" style="width: 14px; height: 14px;"></i>
                                </button>
                                ${!isCurrentUser ? `<button class="admin-delete-user-btn" data-id="${user.id}" data-name="${user.username}" title="Supprimer" style="background: rgba(239,68,68,0.15); border: 1px solid rgba(239,68,68,0.3); color: #ef4444; padding: 6px 10px; border-radius: 6px; cursor: pointer; font-size: 0.8rem;">
                                    <i data-lucide="trash-2" style="width: 14px; height: 14px;"></i>
                                </button>` : ''}
                            </div>
                        `;
                        adminUsersList.appendChild(item);
                    });

                    // Re-init Lucide icons for the newly added elements
                    if (typeof lucide !== 'undefined') lucide.createIcons();

                    // Bind delete buttons
                    document.querySelectorAll('.admin-delete-user-btn').forEach(btn => {
                        btn.addEventListener('click', async () => {
                            const userId = btn.dataset.id;
                            const userName = btn.dataset.name;
                            
                            const confirmed = await showConfirmModal(
                                "Supprimer l'utilisateur", 
                                `Êtes-vous sûr de vouloir supprimer définitivement l'utilisateur "${userName}" ? Cette action est irréversible.`, 
                                { confirmText: 'Supprimer', cancelText: 'Annuler', isDestructive: true }
                            );
                            if (!confirmed) return;

                            try {
                                await apiCall(`/admin/users/${userId}`, 'DELETE');
                                showToast(`Utilisateur "${userName}" supprimé.`);
                                loadAdminUsers();
                            } catch (err) {
                                showToast('Erreur: ' + err.message);
                            }
                        });
                    });

                    // Bind reset password buttons
                    document.querySelectorAll('.admin-reset-pw-btn').forEach(btn => {
                        btn.addEventListener('click', async () => {
                            const userId = btn.dataset.id;
                            const userName = btn.dataset.name;
                            
                            const confirmed = await showConfirmModal(
                                "Réinitialiser le mot de passe", 
                                `Voulez-vous réinitialiser le mot de passe de l'utilisateur "${userName}" ? Un nouveau mot de passe aléatoire temporaire sera généré.`, 
                                { confirmText: 'Réinitialiser', cancelText: 'Annuler', isDestructive: false }
                            );
                            if (!confirmed) return;

                            try {
                                const result = await apiCall(`/admin/users/${userId}/reset-password`, 'POST');
                                if (result.generatedPassword) {
                                    showPasswordModal(result.generatedPassword);
                                }
                            } catch (err) {
                                showToast('Erreur: ' + err.message);
                            }
                        });
                    });

                } catch (err) {
                    console.error('[Admin] Erreur chargement users:', err);
                }
            };

            // Show password modal helper
            const showPasswordModal = (password) => {
                const modal = dom('admin-password-modal');
                const pwDisplay = dom('admin-generated-password');
                if (!modal || !pwDisplay) return;

                pwDisplay.textContent = password;
                show(modal);
                modal.style.display = ''; // Clear inline styles if any

                const copyBtn = dom('admin-copy-password-btn');
                const closeBtn = dom('admin-close-modal-btn');

                const closeModal = () => { hide(modal); };

                if (copyBtn) {
                    copyBtn.onclick = () => {
                        navigator.clipboard.writeText(password).then(() => {
                            copyBtn.textContent = '✓ Copié !';
                            setTimeout(() => { copyBtn.textContent = 'Copier le mot de passe'; }, 2000);
                        }).catch(() => {
                            showToast('Erreur clipboard. Sélectionnez et copiez manuellement.');
                        });
                    };
                }
                if (closeBtn) closeBtn.onclick = closeModal;
            };

            // Add user button
            const addUserBtn = dom('admin-add-user-btn');
            if (addUserBtn) {
                addUserBtn.addEventListener('click', async () => {
                    const usernameInput = dom('admin-new-username');
                    const roleSelect = dom('admin-new-role');
                    if (!usernameInput) return;

                    const username = usernameInput.value.trim();
                    if (!username) {
                        showToast("Nom d'utilisateur requis.");
                        return;
                    }

                    try {
                        const result = await apiCall('/admin/users', 'POST', {
                            username: username,
                            role: roleSelect ? roleSelect.value : 'user'
                        });

                        if (result.success && result.generatedPassword) {
                            usernameInput.value = '';
                            showPasswordModal(result.generatedPassword);
                            loadAdminUsers();
                        }
                    } catch (err) {
                        showToast('Erreur: ' + err.message);
                    }
                });
            }

            // Initial load
            loadAdminUsers();
        }
    };

    // --- SOURCE MANAGEMENT ---
    function renderSourcesUI() {
        const container = dom('sources-sortable-container');
        if (!container) return;

        container.innerHTML = '';

        // Sort available sources so that active ones appear first in their priority order
        const allSources = [...state.activeSources];
        state.availableSources.forEach(sourceName => {
            if (!allSources.includes(sourceName)) {
                allSources.push(sourceName);
            }
        });

        const updateWarning = () => {
            const warningEl = dom('primary-source-warning');
            if (warningEl) {
                // Find first active source
                const firstActive = state.activeSources[0];
                if (firstActive === 'hydracker') {
                    warningEl.style.display = 'flex';
                } else {
                    warningEl.style.display = 'none';
                }
            }
        };

        allSources.forEach(sourceName => {
            const item = document.createElement('div');
            item.className = 'sortable-source-item';
            item.setAttribute('draggable', 'true');
            item.dataset.name = sourceName;

            const isActive = state.activeSources.includes(sourceName);
            const isPrimary = state.activeSources[0] === sourceName;
            const displayName = state.sourceLabels[sourceName] || sourceName.toUpperCase();

            item.innerHTML = `
                <div style="display: flex; align-items: center; gap: 12px; min-width: 0; flex: 1;">
                    <div class="drag-handle" title="Faites glisser pour réordonner">
                        <i data-lucide="grip-vertical" style="width: 18px; height: 18px;"></i>
                    </div>
                    <div style="width: 10px; height: 10px; border-radius: 50%; background: ${isActive ? 'var(--success)' : '#4b5563'}; flex-shrink: 0;"></div>
                    <span style="font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 250px;">${displayName}</span>
                    ${isPrimary ? '<span class="primary-badge" style="font-size: 0.7rem; background: var(--primary); color: white; padding: 2px 6px; border-radius: 4px; font-weight: 700; flex-shrink: 0;">Principale</span>' : ''}
                </div>
                <div style="display: flex; align-items: center; gap: 8px;">
                    <input type="checkbox" value="${sourceName}" ${isActive ? 'checked' : ''} style="width: 20px; height: 20px; cursor: pointer;">
                </div>
            `;

            // Drag and drop event listeners
            item.addEventListener('dragstart', (e) => {
                item.classList.add('dragging');
                e.dataTransfer.effectAllowed = 'move';
            });

            item.addEventListener('dragend', async () => {
                item.classList.remove('dragging');
                
                // Rebuild the priority order from the DOM
                const items = Array.from(container.querySelectorAll('.sortable-source-item'));
                const newOrderedSources = items.map(el => el.dataset.name);
                
                // Extract active sources in their new order
                const newActiveSources = newOrderedSources.filter(name => {
                    const checkbox = container.querySelector(`[data-name="${name}"] input[type="checkbox"]`);
                    return checkbox && checkbox.checked;
                });
                
                await updateActiveSources(newActiveSources);
            });

            // Toggle switch logic
            const checkbox = item.querySelector('input[type="checkbox"]');
            checkbox.addEventListener('change', async () => {
                // To maintain order, we rebuild the list order from the DOM
                const items = Array.from(container.querySelectorAll('.sortable-source-item'));
                const newOrderedSources = items.map(el => el.dataset.name);
                
                const newActiveSources = newOrderedSources.filter(name => {
                    const cb = container.querySelector(`[data-name="${name}"] input[type="checkbox"]`);
                    return cb && cb.checked;
                });
                
                await updateActiveSources(newActiveSources);
            });

            container.appendChild(item);
        });

        // Dragover logic on container to allow real-time visual sorting
        container.addEventListener('dragover', (e) => {
            e.preventDefault();
            const draggingEl = container.querySelector('.dragging');
            if (!draggingEl) return;
            
            const siblings = Array.from(container.querySelectorAll('.sortable-source-item:not(.dragging)'));
            
            const nextSibling = siblings.find(sibling => {
                const rect = sibling.getBoundingClientRect();
                const boxCenter = rect.top + rect.height / 2;
                return e.clientY < boxCenter;
            });
            
            if (nextSibling) {
                container.insertBefore(draggingEl, nextSibling);
            } else {
                container.appendChild(draggingEl);
            }
        });

        updateWarning();
        lucide.createIcons(); // Reactivate icons for newly injected HTML
    }

    // --- UI UPDATES ---
    function updateLocalDbFiltersVisibility() {
        const hasLocalDb = state.activeSources.includes('localdb');
        document.querySelectorAll('.localdb-filter').forEach(el => {
            if (hasLocalDb) {
                el.classList.remove('hidden');
            } else {
                el.classList.add('hidden');
                // If a hidden radio is checked, default back to 'film'
                const radio = el.querySelector('input[type="radio"]');
                if (radio && radio.checked) {
                    const defaultRadio = document.querySelector('input[name="search-type"][value="film"]');
                    if (defaultRadio) defaultRadio.checked = true;
                }
            }
        });
    }

    async function updateActiveSources(sources) {
        try {
            const res = await apiCall('/set-sources', 'POST', { sources });
            state.activeSources = res.activeSources;
            renderSourcesUI();
            updateLocalDbFiltersVisibility();
            showToast('Sources mises à jour');
            loadTrending();
        } catch(e) {
            showToast('Erreur sources: ' + e.message);
            renderSourcesUI(); // Revert UI
        }
    }




    // --- DOWNLOADS (LIST) ---
    const loadDownloads = async () => {
        const list = dom('downloads-list');
        if (!list) return;

        try {
            const data = await apiCall('/download-status');
            list.innerHTML = '';

            if (!data || !data.length) {
                list.innerHTML = `
                    <div class="empty-state-modern">
                        <i data-lucide="hard-drive-download"></i>
                        <p>Aucun téléchargement actif</p>
                    </div>`;
                lucide.createIcons();
                return;
            }

            data.forEach(dl => {
                const item = document.createElement('div');
                item.className = 'dl-card';
                const isDone = dl.percent >= 100;
                const barColor = isDone ? 'var(--success)' : 'var(--accent)';

                item.innerHTML = `
                    <div class="dl-icon">
                        <i data-lucide="${isDone ? 'check-circle' : 'loader-2'}" class="${!isDone ? 'spin-slow' : ''}"></i>
                    </div>
                    <div class="dl-content">
                        <div class="dl-header">
                            <span class="dl-title">${dl.name}</span>
                            <span class="dl-percentage">${Math.round(dl.percent)}%</span>
                        </div>
                        <div class="dl-bar-bg">
                            <div class="dl-bar-fill" style="width: ${dl.percent}%; background: ${barColor};"></div>
                        </div>
                        <div class="dl-status-text">${isDone ? 'Terminé' : 'Téléchargement en cours...'}</div>
                    </div>
                    <button class="btn-jd-delete" title="Supprimer de JDownloader" style="background: none; border: none; color: var(--text-sec); cursor: pointer; padding: 8px; margin-left: 8px; border-radius: 8px; transition: all 0.2s;">
                        <i data-lucide="trash-2" style="width: 18px; height: 18px;"></i>
                    </button>
                `;

                // Attach delete handler
                const deleteBtn = item.querySelector('.btn-jd-delete');
                deleteBtn.onmouseover = () => { deleteBtn.style.color = '#ef4444'; deleteBtn.style.background = 'rgba(239,68,68,0.1)'; };
                deleteBtn.onmouseout = () => { deleteBtn.style.color = 'var(--text-sec)'; deleteBtn.style.background = 'none'; };
                deleteBtn.onclick = async (e) => {
                    e.stopPropagation();
                    const confirmed = await showConfirmModal(
                        "Supprimer de JDownloader", 
                        `Êtes-vous sûr de vouloir supprimer "${dl.name}" de JDownloader ?`, 
                        { confirmText: 'Supprimer', cancelText: 'Annuler', isDestructive: true }
                    );
                    if (!confirmed) return;
                    try {
                        await apiCall('/jd/remove-link', 'POST', { linkIds: [dl.uuid] });
                        showToast(`🗑️ ${dl.name} supprimé`);
                        loadDownloads();
                    } catch (err) {
                        showToast('Erreur : ' + err.message);
                    }
                };

                list.appendChild(item);
            });
            lucide.createIcons();
        } catch (e) { }
    };

    const btnRefreshDownloads = dom('btn-refresh-downloads');
    if (btnRefreshDownloads) {
        btnRefreshDownloads.onclick = loadDownloads;
    }


    // --- UTILS: BLOCKING LOADER & STATE HELPERS ---



    const toggleBlockingLoader = (show, msg = "Traitement en cours...") => {
        let loader = document.getElementById('blocking-loader');
        if (!loader) {
            loader = document.createElement('div');
            loader.id = 'blocking-loader';
            loader.className = 'hidden';
            loader.innerHTML = `<div class="loader"></div><p id="blocking-msg"></p>`;
            document.body.appendChild(loader);
        }
        if (show) {
            document.getElementById('blocking-msg').textContent = msg;
            loader.classList.remove('hidden');
        } else {
            loader.classList.add('hidden');
        }
    };

    // --- PROXY IMAGE HELPER ---
    // Passe les URLs HTTPS des posters par le proxy serveur pour éviter le blocage mixed-content
    const proxyImageUrl = (url) => {
        if (!url) return '';
        // Si l'image est déjà locale ou en HTTP sur notre domaine, pas besoin de proxy
        if (url.startsWith('/') || url.startsWith('data:')) return url;
        // Proxy les URLs HTTPS via le serveur
        if (url.startsWith('https://')) {
            return `/api/proxy-image?url=${encodeURIComponent(url)}`;
        }
        return url;
    };

    // --- TRENDING & CARDS ---
    const createCard = (movie) => {
        const div = document.createElement('div');
        div.className = 'card';

        const posterSrc = proxyImageUrl(movie.image);

        // Build subtitle: quality + lang for ZT, year for Hydracker
        let subtitle = movie.year || '';
        let cleanedTitle = movie.title;

        // Clean ZT titles: "Show Name - Saison X [Quality]" -> "Show Name - Saison X"
        if (movie.source === 'zt') {
            const parts = [];
            
            // Extract quality info from title if present: "Title [1080p]" -> "Title"
            const titleQualityMatch = cleanedTitle.match(/(.*)\s+\[([^\]]+)\]$/);
            if (titleQualityMatch) {
                cleanedTitle = titleQualityMatch[1].trim();
                const qualityFromTitle = titleQualityMatch[2].trim();
                if (!movie.quality) movie.quality = qualityFromTitle;
            }

            if (movie.year) parts.push(movie.year);
            if (movie.quality) parts.push(movie.quality);
            if (movie.lang) parts.push(movie.lang);
            subtitle = parts.join(' — ') || '';
        }

        const typeBadge = movie.type === 'series' || movie.type === 'anime' ? `<span class="type-badge">${movie.type === 'anime' ? 'Anime' : 'Série'}</span>` : '';

        div.innerHTML = `
            <div class="poster-container">
                <img src="${posterSrc}" loading="lazy" alt="${cleanedTitle}" onerror="this.style.display='none'">
                <div class="source-badge" style="position: absolute; top: 8px; right: 8px; background: rgba(0,0,0,0.7); color: white; padding: 2px 8px; border-radius: 4px; font-size: 0.7rem; font-weight: 700; text-transform: uppercase; backdrop-filter: blur(4px); border: 1px solid rgba(255,255,255,0.1);">
                    ${movie.source}
                </div>
            </div>
            <div class="card-info">
                <div class="card-title">${cleanedTitle}</div>
                <div class="card-year">${typeBadge} ${subtitle}</div>
            </div>
        `;
        div.addEventListener('click', () => handleSelection(movie));
        return div;
    };


    const renderTrending = () => {
        const grid = dom('trending-grid');
        if (!grid) return;

        const type = document.querySelector('input[name="trending-type"]:checked').value;
        const itemsToDisplay = type === 'film' ? state.trendingData.films : state.trendingData.series;

        grid.innerHTML = '';

        if (!itemsToDisplay || !itemsToDisplay.length) {
            if (dom('offline-banner') && dom('offline-banner').textContent.includes('Aucune source configurée')) {
                grid.innerHTML = `
                    <div style="grid-column: 1/-1; text-align: center; padding: 4rem 2rem; color: var(--text-sec);">
                        <i data-lucide="settings-2" style="width: 48px; height: 48px; margin-bottom: 1.5rem; opacity: 0.5;"></i>
                        <h3 style="color: white; margin-bottom: 0.5rem;">Aucune source configurée</h3>
                        <p style="margin-bottom: 2rem; max-width: 400px; margin-left: auto; margin-right: auto;">
                            Pour afficher du contenu, activez au moins une source dans les paramètres. ZT est recommandé par défaut.
                        </p>
                        <button class="btn-primary" onclick="document.querySelector('[data-target=\'section-settings\']').click()" style="padding: 10px 24px;">
                            Aller aux Paramètres
                        </button>
                    </div>`;
                lucide.createIcons();
            } else {
                grid.innerHTML = '<p style="padding:1rem">Aucune tendance trouvée.</p>';
            }
            return;
        }

        itemsToDisplay.forEach(m => grid.appendChild(createCard(m)));
    };

    const renderRecent = () => {
        const grid = dom('recent-grid');
        if (!grid) return;

        const itemsToDisplay = state.trendingData.recent || [];

        grid.innerHTML = '';

        if (!itemsToDisplay || !itemsToDisplay.length) {
            grid.innerHTML = '<p style="padding:1rem; opacity:0.7;">Aucun ajout récent trouvé.</p>';
            return;
        }

        itemsToDisplay.forEach(m => grid.appendChild(createCard(m)));
    };

    const loadTrending = async () => {
        const trendingGrid = dom('trending-grid');
        const recentGrid = dom('recent-grid');
        if (!trendingGrid && !recentGrid) return;

        try {
            const data = await apiCall('/api/trending');

            // Mise à jour de la bannière si le site est down
            updateSiteStatusUI(data.isSiteOffline, data.siteOfflineMessage);

            state.trendingData = data;

            // Si le serveur n'a pas encore fini de scrapper au démarrage
            if (data.films.length === 0 && data.series.length === 0 && (!data.recent || data.recent.length === 0)) {
                if (trendingGrid) {
                    trendingGrid.innerHTML = `
                        <div style="grid-column: 1/-1; text-align: center; padding: 3rem; color: var(--text-sec);">
                            <div class="loader"></div>
                            <p>Le serveur prépare les tendances, un instant...</p>
                        </div>`;
                }
                if (recentGrid) {
                    recentGrid.innerHTML = `
                        <div style="grid-column: 1/-1; text-align: center; padding: 3rem; color: var(--text-sec);">
                            <div class="loader"></div>
                            <p>Le serveur prépare les ajouts récents, un instant...</p>
                        </div>`;
                }
                setTimeout(loadTrending, 3000); // On réessaye dans 3 secondes
                return;
            }

            renderTrending();
            renderRecent();
        } catch (e) {
            console.error("Erreur tendances/récents:", e);
            if (trendingGrid) {
                trendingGrid.innerHTML = '<p style="padding:1rem; color: #e50914;">⚠️ Erreur de liaison avec le serveur.</p>';
            }
            if (recentGrid) {
                recentGrid.innerHTML = '<p style="padding:1rem; color: #e50914;">⚠️ Erreur de liaison avec le serveur.</p>';
            }
        }
    };

    document.querySelectorAll('input[name="trending-type"]').forEach(radio => {
        radio.addEventListener('change', renderTrending);
    });

    // --- SEARCH ---
    const searchInput = dom('search-input');
    const searchBtn = dom('btn-search-trigger');
    const searchRadios = document.querySelectorAll('input[name="search-type"]');
    let searchTimeout = null;

    const performSearch = async () => {
        const q = searchInput ? searchInput.value.trim() : '';
        const grid = dom('search-results');
        if (!q) {
            if (grid) grid.innerHTML = '';
            return;
        }

        // ZT requires min 4 characters
        if (state.activeSources.includes('zt') && state.activeSources.length === 1 && q.length < 4) {
            if (grid) grid.innerHTML = '<p style="padding:1rem; opacity:0.7;">Minimum 4 caractères pour la recherche sur ZT.</p>';
            return;
        }
        
        const typeEl = document.querySelector('input[name="search-type"]:checked');
        const type = typeEl ? typeEl.value : 'film';
        
        if (grid) grid.innerHTML = '<div class="loader-wrapper"><div class="loader"></div></div>';
        
        try {
            const res = await apiCall('/search', 'POST', { title: q, mediaType: type });
            // Vérification si la recherche n'a pas changé entre temps
            if (searchInput.value.trim() !== q) return;
            
            if (grid) {
                grid.innerHTML = '';
                if (!res || !res.length) {
                    if (dom('offline-banner') && dom('offline-banner').textContent.includes('Aucune source configurée')) {
                        grid.innerHTML = '<p style="padding:1rem; opacity:0.7;">Veuillez configurer une source dans les paramètres.</p>';
                    } else {
                        grid.innerHTML = '<p style="padding:1rem; opacity:0.7;">Aucun résultat.</p>';
                    }
                }
                else res.forEach(m => grid.appendChild(createCard(m)));
            }
        } catch (e) {
            if (grid) grid.innerHTML = `<p style="padding:1rem; color:#ef4444;">Erreur: ${e.message}</p>`;
        }
    };

    if (searchInput) {
        // Recherche instantanée avec debounce
        searchInput.addEventListener('input', () => {
            if (searchTimeout) clearTimeout(searchTimeout);
            searchTimeout = setTimeout(() => {
                performSearch();
            }, 500); // 500ms d'attente
        });

        // Entrée pour valider immédiatement
        searchInput.addEventListener('keypress', (e) => {
            if (e.key === 'Enter') {
                e.preventDefault();
                if (searchTimeout) clearTimeout(searchTimeout);
                performSearch();
            }
        });
    }

    if (searchBtn) {
        searchBtn.addEventListener('click', (e) => {
            e.preventDefault();
            if (searchTimeout) clearTimeout(searchTimeout);
            performSearch();
        });
    }

    // Relancer la recherche si on change de filtre (Film/Série)
    searchRadios.forEach(radio => {
        radio.addEventListener('change', () => {
            if (searchInput && searchInput.value.trim().length > 0) {
                if (searchTimeout) clearTimeout(searchTimeout);
                performSearch();
            }
        });
    });

    // --- MODAL ---
    const handleSelection = async (movie) => {
        showModal(movie.title, '<div class="loader-wrapper"><div class="loader"></div></div>');
        try {
            let ep = '/select-movie';
            if (movie.source === 'hydracker' && movie.hrefPath && movie.hrefPath.includes('download')) {
                ep = '/select-trending';
            }
            const data = await apiCall(ep, 'POST', { hrefPath: movie.hrefPath || '', title: movie.title, type: movie.type, source: movie.source });
            // Ajout du 3ème argument : movie.source
            renderModalOptions(data, movie.title, movie.source);
        } catch (e) {
            dom('modal-body').innerHTML = `<p style="color:red">${e.message}</p>`;
        }
    };

    function parseSizeToMB(sizeStr) {
        if (!sizeStr || sizeStr === 'N/A') return 0;
        const match = sizeStr.match(/([\d.,]+)\s*(gb|go|mb|mo|ko|kb|tb|to)/i);
        if (!match) return 0;
        let size = parseFloat(match[1].replace(',', '.'));
        const unit = match[2].toLowerCase();
        if (unit.includes('gb') || unit.includes('go')) size *= 1024;
        else if (unit.includes('tb')) size *= 1024 * 1024;
        else if (unit.includes('kb') || unit.includes('ko')) size /= 1024;
        return size;
    }

    const getQualityRank = (qualityString) => {
        const lower = qualityString.toLowerCase();
        if (lower.includes("ultra hdlight") && lower.includes("x265")) return 1;
        if (lower.includes("1080p") && lower.includes("x265") || lower.includes("1080p light") || lower.includes("x265")) return 2;
        return 3;
    };

    const renderModalOptions = (data, currentTitle = '', source = '') => {
        const body = dom('modal-body');
        body.innerHTML = '';

        const selectedIds = new Set();
        const updateBatchUI = () => {
            const count = selectedIds.size;
            const container = document.getElementById('batch-download-container');
            if (container) {
                container.style.display = count > 0 ? 'block' : 'none';
                const countSpan = document.getElementById('batch-count');
                if (countSpan) countSpan.textContent = count;
            }
        };

        // --- 0. TYPE DETECTION ---
        const hasSaisonLabel = data.seasons && data.seasons.some(s => s.label.toLowerCase().includes('saison'));
        const hasNumericEpisodes = data.clientOptions && data.clientOptions.some(q => {
            if (!q.episode) return false;
            const lowEp = q.episode.toLowerCase();
            if (lowEp.includes('saison complète') || lowEp.includes('intégrale') || lowEp.includes('pack')) return false;
            // Si c'est un nombre ou contient "Ep", c'est une série
            return /^\d+$/.test(q.episode) || lowEp.includes('ep');
        });
        const isActuallySeries = hasSaisonLabel || hasNumericEpisodes;


        // --- 1. SAISONS / VERSIONS ---
        if (data.seasons && data.seasons.length > 0) {
            const h4 = document.createElement('h4');
            h4.textContent = isActuallySeries ? "Saisons disponibles" : "Qualités & Versions";
            h4.className = "modal-subtitle";
            body.appendChild(h4);

            const seasonsWrapper = document.createElement('div');
            seasonsWrapper.className = 'seasons-wrapper';
            
            data.seasons.forEach(s => {
                const btn = document.createElement('button');
                btn.className = 'version-tab'; // using version-tab for a clean look
                btn.innerHTML = `<span>${s.label}</span>`;
                btn.title = s.label;

                btn.onclick = async () => {
                    body.innerHTML = '<div class="loader-wrapper"><div class="loader"></div></div>';
                    try {
                        const res = await apiCall('/select-season', 'POST', { seasonValue: s.value });
                        res.seasons = data.seasons;
                        
                        const baseTitle = currentTitle.split(' - ')[0];
                        const newTitle = (s.label.toLowerCase().includes('saison') || s.label.toLowerCase().includes('intégrale')) 
                            ? `${baseTitle} - ${s.label}` 
                            : currentTitle;
                        
                        const titleEl = dom('modal-title');
                        if (titleEl) titleEl.textContent = newTitle;
                        console.log(`[Modal] Titre mis à jour : ${newTitle}`);

                        renderModalOptions(res, newTitle, source);
                    } catch (e) {
                        body.innerHTML = `<p style="color:red; padding:1rem;">Erreur: ${e.message}</p>`;
                    }
                };

                seasonsWrapper.appendChild(btn);
            });
            body.appendChild(seasonsWrapper);
            
            const sep = document.createElement('hr');
            sep.className = 'modal-sep';
            body.appendChild(sep);
        }


        // --- 2. FILES ---
        if (!data.clientOptions || !data.clientOptions.length) {
            body.innerHTML += '<p class="empty-msg">Aucun fichier disponible.</p>';
            return;
        }

        const MAX_FILM_SIZE_MB = 45360;

        const enriched = data.clientOptions.map(q => {
            const lowEp = q.episode ? q.episode.toLowerCase() : '';
            const isFullSeason = lowEp.includes('saison complète') || lowEp.includes('intégrale') || lowEp.includes('pack') ? 1 : 0;
            return {
                ...q,
                sizeVal: parseSizeToMB(q.size),
                rank: getQualityRank(q.quality),
                isFullSeason
            };
        })
.filter(q => {
            if (!isActuallySeries) return q.sizeVal <= MAX_FILM_SIZE_MB;
            return true;
        }).sort((a, b) => {
            if (a.isFullSeason !== b.isFullSeason) return b.isFullSeason - a.isFullSeason;
            if (isActuallySeries) {
                const epA = parseInt(String(a.episode || '').replace(/\D/g, '')) || 0;
                const epB = parseInt(String(b.episode || '').replace(/\D/g, '')) || 0;
                if (epA !== epB) return epA - epB;
            }
            if (a.rank !== b.rank) return a.rank - b.rank;
            return a.sizeVal - b.sizeVal;
        });

        if (enriched.length === 0) {
            body.innerHTML += '<p class="empty-msg">Aucun fichier disponible.</p>';
            return;
        }

        // --- 2a. BUILD VERSION TABS ---
        // Gather unique versions from quality field
        const allVersions = [...new Set(enriched.map(q => q.quality || 'Inconnu'))];

        let activeVersion = allVersions[0];

        const h4files = document.createElement('h4');
        h4files.textContent = "Fichiers Disponibles";
        h4files.className = "modal-subtitle";
        body.appendChild(h4files);

        // Version filter tabs (only if >1 version)
        const versionTabsWrap = document.createElement('div');
        versionTabsWrap.className = 'version-tabs';
        body.appendChild(versionTabsWrap);

        const filesContainer = document.createElement('div');
        filesContainer.className = 'files-list';
        body.appendChild(filesContainer);

        const renderFiles = (version) => {
            filesContainer.innerHTML = '';
            const toShow = allVersions.length > 1
                ? enriched.filter(q => (q.quality || 'Inconnu') === version)
                : enriched;

            if (toShow.length === 0) {
                filesContainer.innerHTML = '<p class="empty-msg">Aucun fichier pour cette version.</p>';
                return;
            }

            // Group by host
            const hostGroups = new Map();
            toShow.forEach(q => {
                let hostKey = q.host || 'inconnu';
                if (!hostGroups.has(hostKey)) hostGroups.set(hostKey, []);
                hostGroups.get(hostKey).push(q);
            });

            hostGroups.forEach((items, hostName) => {
                // Host Header
                const hostHeader = document.createElement('div');
                hostHeader.className = "season-group-title";
                hostHeader.style.marginTop = "1rem";
                
                // Friendly host name
                const hostDisplay = hostName
                    .replace(/\.(png|jpg|webp|gif)$/i, '')
                    .replace(/[-_]/g, ' ')
                    .toUpperCase();
                
                hostHeader.textContent = hostDisplay;
                filesContainer.appendChild(hostHeader);

                // Sort items by episode number
                items.sort((a, b) => {
                    if (a.isFullSeason && !b.isFullSeason) return -1;
                    if (!a.isFullSeason && b.isFullSeason) return 1;
                    
                    const numA = a.episode ? parseFloat(a.episode.toString().replace(/[^0-9.]/g, '')) || 0 : 0;
                    const numB = b.episode ? parseFloat(b.episode.toString().replace(/[^0-9.]/g, '')) || 0 : 0;
                    return numA - numB;
                });
                
                const itemsGrid = document.createElement('div');
                itemsGrid.className = isActuallySeries ? "seasons-grid" : "files-list";
                filesContainer.appendChild(itemsGrid);

                items.forEach((q, idx) => {
                    const row = document.createElement('div');
                    let specialClass = '';
                    let rankIcon = '';
                    
                    if (q.isFullSeason) { specialClass = 'quality-gold'; rankIcon = '📦'; }
                    else if (q.rank === 1) { specialClass = 'quality-gold'; rankIcon = '⭐'; }
                    else if (q.rank === 2) { specialClass = 'quality-blue'; rankIcon = '✨'; }

                    const episodeLabel = q.episode
                        ? (q.isFullSeason || !/^\d+$/.test(q.episode) ? q.episode : `Ep. ${q.episode}`)
                        : "Télécharger";

                    // On vérifie si la source est Hydracker
                    const isHydracker = source === 'hydracker';

                    let badgesHtml = '<div style="display: flex; gap: 6px; flex-wrap: wrap; align-items: center; margin-top: 6px;">';
                    if (isActuallySeries && q.size && q.size !== 'N/A') {
                        badgesHtml += `<span class="badge-size">💾 ${q.size}</span>`;
                    }
                    if (q.langs && q.langs.length) {
                        q.langs.forEach(l => {
                            if (l && l !== 'unknown') badgesHtml += `<span class="badge-lang">🎧 ${l.replace('Subs:', '💬').replace('Audio:', '🎧')}</span>`;
                        });
                    }
                    if (q.subs && q.subs.length) {
                        q.subs.forEach(s => {
                            if (s && s !== 'Inconnu') badgesHtml += `<span class="badge-sub">💬 ${s}</span>`;
                        });
                    }
                    badgesHtml += '</div>';
                    if (q.releaseName) {
                        badgesHtml += `<div style="font-size: 0.7rem; color: var(--text-sec); margin-top: 4px; word-break: break-all;">${q.releaseName}</div>`;
                    }

                    if (isActuallySeries) {
                        row.className = `quality-pill ${specialClass}`;
                        row.style.display = 'flex';
                        row.style.justifyContent = 'space-between';
                        row.style.alignItems = 'center';
                        row.style.padding = "8px 14px";
                        row.style.cursor = "pointer";
                        row.style.gap = "20px";
                        
                        let buttonsHtml = '';
                        if (isHydracker) {
                            buttonsHtml = `
                                <div style="display: flex; gap: 6px; align-items: center;">
                                    <button class="btn-action btn-movix" title="Lien Direct (Movix)" style="background: rgba(139, 92, 246, 0.2); border: 1px solid rgba(139, 92, 246, 0.5); color: #8b5cf6; border-radius: 6px; padding: 4px 8px; cursor: pointer; display: flex; align-items: center; transition: all 0.2s;">
                                        <i data-lucide="zap" style="width: 16px; height: 16px;"></i>
                                    </button>
                                    <button class="btn-action btn-dl" title="Télécharger classique" style="background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.1); color: white; border-radius: 6px; padding: 4px 8px; cursor: pointer; display: flex; align-items: center; transition: all 0.2s;">
                                        <i data-lucide="download" style="width: 16px; height: 16px;"></i>
                                    </button>
                                </div>
                            `;
                        } else {
                            buttonsHtml = `
                                <button class="btn-action btn-dl" title="Télécharger" style="background: transparent; border: none; color: white; cursor: pointer; display: flex; align-items: center;">
                                    <i data-lucide="download" style="width: 18px; height: 18px;"></i>
                                </button>
                            `;
                        }

                        const isChecked = selectedIds.has(q.id);
                        row.innerHTML = `
                            <div style="display: flex; flex-direction: column; flex: 1;">
                                <div style="display: flex; align-items: center;">
                                    <div class="batch-checkbox" data-id="${q.id}" style="cursor: pointer; display: flex; align-items: center; color: ${isChecked ? 'var(--primary)' : 'var(--text-sec)'}; margin-right: 8px;">
                                        <i data-lucide="${isChecked ? 'check-square' : 'square'}" style="width: 18px; height: 18px;"></i>
                                    </div>
                                    ${rankIcon ? `<span style="margin-right:5px">${rankIcon}</span>` : ''}
                                    <span style="font-weight: 600;">${episodeLabel}</span>
                                </div>
                                ${badgesHtml}
                            </div>
                            ${buttonsHtml}
                        `;
                    } else {
                        row.className = `file-btn ${specialClass}`;
                        row.style.cursor = "pointer";
                        row.style.display = 'flex';
                        row.style.justifyContent = 'space-between';
                        row.style.alignItems = 'center';

                        const mirrorLabel = items.length > 1 ? ` <span class="mirror-tag">Miroir ${idx + 1}</span>` : '';
                        
                        let buttonsHtml = '';
                        if (isHydracker) {
                            buttonsHtml = `
                                <div class="file-btn-right" style="display: flex; gap: 8px; align-items: center;">
                                    <button class="btn-action btn-movix" title="Lien Direct (Movix)" style="background: rgba(139, 92, 246, 0.15); border: 1px solid #8b5cf6; color: #8b5cf6; padding: 6px 12px; border-radius: 6px; cursor: pointer; display: flex; align-items: center; gap: 6px; font-weight: 600; transition: all 0.2s;">
                                        <i data-lucide="zap" style="width: 16px; height: 16px;"></i> Movix
                                    </button>
                                    <button class="btn-action btn-dl" title="Télécharger classique" style="background: rgba(255, 255, 255, 0.1); border: none; color: white; padding: 6px 12px; border-radius: 6px; cursor: pointer; display: flex; align-items: center; transition: all 0.2s;">
                                        <i data-lucide="download" style="width: 16px; height: 16px;"></i>
                                    </button>
                                </div>
                            `;
                        } else {
                            buttonsHtml = `
                                <div class="file-btn-right">
                                    <button class="btn-action btn-dl" title="Télécharger" style="background: transparent; border: none; color: white; cursor: pointer;">
                                        <i data-lucide="download" class="dl-icon-btn"></i>
                                    </button>
                                </div>
                            `;
                        }

                        const isChecked = selectedIds.has(q.id);
                        row.innerHTML = `
                            <div class="file-btn-left" style="display: flex; flex-direction: column; width: 100%; padding-right: 15px;">
                                <div style="display: flex; align-items: center; justify-content: space-between; width: 100%;">
                                    <div class="file-host" style="display: flex; align-items: center;">
                                        <div class="batch-checkbox" data-id="${q.id}" style="cursor: pointer; display: flex; align-items: center; color: ${isChecked ? 'var(--primary)' : 'var(--text-sec)'}; margin-right: 8px;">
                                            <i data-lucide="${isChecked ? 'check-square' : 'square'}" style="width: 18px; height: 18px;"></i>
                                        </div>
                                        ${rankIcon ? `<span class="rank-icon">${rankIcon}</span>` : ''}
                                        <span class="host-name">${hostDisplay}</span>
                                        ${mirrorLabel}
                                        ${q.episode ? `<span class="episode-tag">${q.episode}</span>` : ''}
                                    </div>
                                    <div class="file-size" style="margin-left: 15px; flex-shrink: 0;">${q.size && q.size !== 'N/A' ? q.size : 'Taille inconnue'}</div>
                                </div>
                                ${badgesHtml}
                            </div>
                            ${buttonsHtml}
                        `;
                    }

                    const chk = row.querySelector('.batch-checkbox');
                    if (chk) {
                        chk.onclick = (e) => {
                            e.stopPropagation();
                            if (selectedIds.has(q.id)) {
                                selectedIds.delete(q.id);
                                chk.innerHTML = '<i data-lucide="square" style="width: 18px; height: 18px;"></i>';
                                chk.style.color = 'var(--text-sec)';
                            } else {
                                selectedIds.add(q.id);
                                chk.innerHTML = '<i data-lucide="check-square" style="width: 18px; height: 18px;"></i>';
                                chk.style.color = 'var(--primary)';
                            }
                            lucide.createIcons({ root: chk });
                            updateBatchUI();
                        };
                    }

                    // On attache l'event listener Movix UNIQUEMENT si on est sur Hydracker
                    if (isHydracker) {
                        row.querySelector('.btn-movix').onclick = async (e) => {
                            e.stopPropagation();
                            toggleBlockingLoader(true, "Débridage Movix en cours...");
                            try {
                                const result = await apiCall(`/movix-decode/${q.id}`, 'GET');
                                toggleBlockingLoader(false);

                                if (result.link) {
                                    let toggleEl = document.getElementById('toggle-jd');
                                    let useJD = toggleEl ? toggleEl.checked : getPref('useJD', false);

                                    if (useJD) {
                                        showToast('Lien Movix envoyé à JDownloader !');
                                        await apiCall('/jd/add', 'POST', { link: result.link, packageName: q.releaseName || 'Movix Download', isSeries: isActuallySeries });
                                    } else {
                                        showDirectLinkModal('Lien Direct Movix', `
                                            <div class="direct-link-box">
                                                <p style="margin-bottom: 12px; color: var(--text-sec); font-size: 0.9rem;">Voici votre lien direct rapide :</p>
                                                <div style="position: relative; width: 100%; margin-bottom: 1.25rem;">
                                                    <input type="text" value="${result.link}" readonly id="direct-link-input" class="select-on-click"
                                                           style="width: 100%; background: #0a0a0a; border: 1px solid var(--border); border-radius: 10px; color: #ffffff; padding: 14px 44px 14px 16px; font-family: monospace; font-size: 0.95rem; text-align: left; box-shadow: inset 0 2px 4px rgba(0,0,0,0.8); outline: none;">
                                                    <button class="copy-btn-target" data-copy-target="direct-link-input" style="position: absolute; right: 12px; top: 50%; transform: translateY(-50%); background: none; border: none; color: var(--text-sec); cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 4px;"
                                                            title="Copier le lien">
                                                        <i data-lucide="copy" style="width: 18px; height: 18px;"></i>
                                                    </button>
                                                </div>
                                                <div class="btn-group" style="display: flex; gap: 10px;">
                                                    <button class="btn-action copy-btn-target" data-copy-target="direct-link-input" style="flex: 1; background: #262626; border: 1px solid var(--border); color: white; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 12px; font-weight: 600; border-radius: 10px; cursor: pointer; transition: all 0.2s;">
                                                        <i data-lucide="copy" style="width: 16px; height: 16px;"></i> Copier le lien
                                                    </button>
                                                    <a href="${result.link}" target="_blank" class="btn-success" style="flex: 1; text-align: center; text-decoration: none; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 12px; font-weight: 600; border-radius: 10px; cursor: pointer; transition: all 0.2s;">
                                                        <i data-lucide="external-link" style="width: 16px; height: 16px;"></i> Ouvrir le lien
                                                    </a>
                                                </div>
                                            </div>
                                        `);
                                    }
                                }
                            } catch (err) {
                                toggleBlockingLoader(false);
                                showToast("Erreur Movix: " + err.message);
                                show(dom('modal-overlay'));
                            }
                        };
                    }

                    // L'event listener classique fonctionne pour toutes les sources
                    row.onclick = async (e) => {
                        e.stopPropagation();
                        let toggleEl = document.getElementById('toggle-jd');
                        let useJD = toggleEl ? toggleEl.checked : getPref('useJD', false);
                        let forcedDirect = (source === 'ztnews');
                        if (forcedDirect) {
                            useJD = false;
                        }
                        toggleBlockingLoader(true, "Récupération du lien...");
                        try {
                            let result = await apiCall('/get-link', 'POST', { chosenId: q.id, useJD });
                            
                            if (result.status === 'challenge' && result.challenge) {
                                toggleBlockingLoader(false);
                                const captchaData = await window.handleCaptchaChallenge(result.challenge);
                                toggleBlockingLoader(true, "Vérification du captcha...");
                                result = await apiCall('/get-link', 'POST', { chosenId: q.id, useJD, captchaData });
                            }
                            
                            toggleBlockingLoader(false);

                            if (useJD) {
                                showToast('Lien envoyé à JDownloader !');
                            } else {
                                if (forcedDirect) {
                                    showToast("⚠️ Cloudflare Turnstile actif. Résolution manuelle requise.");
                                }
                                const titleText = forcedDirect ? 'Lien Direct (Protection Cloudflare)' : 'Lien Direct';
                                const descText = forcedDirect 
                                    ? 'Ce lien est protégé par Cloudflare. Cliquez sur "Ouvrir" pour le déverrouiller manuellement :' 
                                    : 'Voici votre lien direct rapide :';

                                showDirectLinkModal(titleText, `
                                    <div class="direct-link-box">
                                         <p style="margin-bottom: 12px; color: var(--text-sec); font-size: 0.9rem;">${descText}</p>
                                         <div style="position: relative; width: 100%; margin-bottom: 1.25rem;">
                                             <input type="text" value="${result.link}" readonly id="direct-link-input-2" class="select-on-click"
                                                    style="width: 100%; background: #0a0a0a; border: 1px solid var(--border); border-radius: 10px; color: #ffffff; padding: 14px 44px 14px 16px; font-family: monospace; font-size: 0.95rem; text-align: left; box-shadow: inset 0 2px 4px rgba(0,0,0,0.8); outline: none;">
                                         </div>
                                         <div class="btn-group" style="display: flex; gap: 10px;">
                                             <button class="btn-action copy-btn-target" data-copy-target="direct-link-input-2" style="flex: 1; background: #262626; border: 1px solid var(--border); color: white; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 12px; font-weight: 600; border-radius: 10px; cursor: pointer; transition: all 0.2s;">
                                                 <i data-lucide="copy" style="width: 16px; height: 16px;"></i> Copier le lien
                                             </button>
                                             <a href="${result.link}" target="_blank" class="btn-success" style="flex: 1; text-align: center; text-decoration: none; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 12px; font-weight: 600; border-radius: 10px; cursor: pointer; transition: all 0.2s;">
                                                 <i data-lucide="external-link" style="width: 16px; height: 16px;"></i> Ouvrir le lien
                                             </a>
                                         </div>
                                    </div>
                                `);
                            }
                        } catch (err) {
                            toggleBlockingLoader(false);
                            showToast("Erreur: " + err.message);
                            show(dom('modal-overlay'));
                        }
                    };
                    
                    row.querySelectorAll('.btn-action').forEach(b => {
                        b.addEventListener('mouseover', () => b.style.transform = 'scale(1.05)');
                        b.addEventListener('mouseout', () => b.style.transform = 'scale(1)');
                    });

                    itemsGrid.appendChild(row);
                });
            });


            lucide.createIcons();
        };

        if (allVersions.length > 1) {
            allVersions.forEach(version => {
                const tab = document.createElement('button');
                tab.className = 'version-tab';
                tab.textContent = version;
                if (version === activeVersion) tab.classList.add('active');
                tab.onclick = () => {
                    activeVersion = version;
                    versionTabsWrap.querySelectorAll('.version-tab').forEach(t => t.classList.remove('active'));
                    tab.classList.add('active');
                    renderFiles(version);
                };
                versionTabsWrap.appendChild(tab);
            });
        }

        renderFiles(activeVersion);

        const batchDownloadContainer = document.createElement('div');
        batchDownloadContainer.id = 'batch-download-container';
        batchDownloadContainer.style = 'display: none; padding-top: 1rem; border-top: 1px solid var(--border); margin-top: 1rem;';
        batchDownloadContainer.innerHTML = `
            <button class="btn-primary" id="btn-batch-download" style="width: 100%; display: flex; justify-content: center; align-items: center; gap: 8px;">
                <i data-lucide="download"></i> Télécharger la sélection (<span id="batch-count">0</span>)
            </button>
        `;
        body.appendChild(batchDownloadContainer);

        const btnBatch = batchDownloadContainer.querySelector('#btn-batch-download');
        btnBatch.onclick = async () => {
            if (selectedIds.size === 0) return;
            let toggleEl = document.getElementById('toggle-jd');
            let useJD = toggleEl ? toggleEl.checked : getPref('useJD', false);
            let forcedDirect = (source === 'ztnews');
            if (forcedDirect) {
                useJD = false;
            }
            try {
                toggleBlockingLoader(true, "Récupération des liens...");
                let result = await apiCall('/get-links-batch', 'POST', { chosenIds: Array.from(selectedIds), useJD });
                
                if (result.status === 'challenge' && result.challenge) {
                    toggleBlockingLoader(false);
                    const captchaData = await window.handleCaptchaChallenge(result.challenge);
                    toggleBlockingLoader(true, "Vérification du captcha et récupération...");
                    result = await apiCall('/get-links-batch', 'POST', { chosenIds: Array.from(selectedIds), useJD, captchaData });
                }
                
                toggleBlockingLoader(false);

                if (result.errors) {
                    showToast('Erreurs: ' + result.errors.join(', '));
                }

                if (useJD) {
                    showToast(result.message || 'Liens envoyés à JDownloader !');
                } else {
                    if (forcedDirect) {
                        showToast("⚠️ Cloudflare Turnstile actif. Résolution manuelle requise.");
                    }
                    const titleText = forcedDirect ? 'Liens Directs (Protection Cloudflare)' : 'Liens Directs';
                    const descText = forcedDirect 
                        ? 'Ces liens sont protégés par Cloudflare. Copiez-les pour les ouvrir manuellement :'
                        : 'Voici vos liens directs :';

                    showDirectLinkModal(titleText, `
                        <div class="direct-link-box">
                            <p style="margin-bottom: 12px; color: var(--text-sec); font-size: 0.9rem;">${descText}</p>
                            <textarea readonly id="direct-links-input" class="select-on-click"
                                      style="width: 100%; height: 150px; background: #0a0a0a; border: 1px solid var(--border); color: #ffffff; border-radius: 10px; margin-bottom: 1.25rem; padding: 14px; font-family: monospace; font-size: 0.95rem; white-space: pre; resize: none; box-shadow: inset 0 2px 4px rgba(0,0,0,0.8); outline: none;">${(result.links || []).join('\n')}</textarea>
                            <div class="btn-group" style="display: flex; gap: 10px;">
                                <button class="btn-action copy-btn-target" data-copy-target="direct-links-input" style="flex: 1; background: #262626; border: 1px solid var(--border); color: white; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 12px; font-weight: 600; border-radius: 10px; cursor: pointer; transition: all 0.2s;">
                                    <i data-lucide="copy" style="width: 16px; height: 16px;"></i> Tout copier
                                </button>
                            </div>
                        </div>
                    `);
                }
            } catch (err) {
                toggleBlockingLoader(false);
                showToast("Erreur: " + err.message);
                show(dom('modal-overlay'));
            }
        };
        
        updateBatchUI();
        lucide.createIcons({ root: batchDownloadContainer });
    };


    const showModal = (title, content) => {
        dom('modal-title').textContent = title;
        dom('modal-body').innerHTML = content;
        show(dom('modal-overlay'));
    };
    window.showModal = showModal;

    const showDirectLinkModal = (title, content) => {
        const existing = document.getElementById('direct-link-modal-overlay');
        if (existing) existing.remove();
        
        const overlay = document.createElement('div');
        overlay.id = 'direct-link-modal-overlay';
        overlay.className = 'modal-overlay';
        overlay.style.zIndex = '10001';
        overlay.innerHTML = `
            <div class="modal-content" style="max-width: 500px;">
                <div class="modal-header">
                    <h3>${title}</h3>
                    <button id="direct-modal-close"><i data-lucide="x"></i></button>
                </div>
                <div class="modal-body">${content}</div>
            </div>
        `;
        document.body.appendChild(overlay);
        lucide.createIcons({ root: overlay });
        show(overlay);

        // CSP Safe Event Listeners
        const selects = overlay.querySelectorAll('.select-on-click');
        selects.forEach(el => el.addEventListener('click', function() { this.select(); }));

        const copyBtns = overlay.querySelectorAll('.copy-btn-target');
        copyBtns.forEach(btn => {
            btn.addEventListener('click', () => {
                const targetId = btn.getAttribute('data-copy-target');
                const targetEl = document.getElementById(targetId);
                if (targetEl) {
                    navigator.clipboard.writeText(targetEl.value)
                        .then(() => showToast('Copié !'))
                        .catch(() => showToast('Erreur de copie !'));
                }
            });
        });

        const closeBtn = overlay.querySelector('#direct-modal-close');
        if (closeBtn) {
            closeBtn.addEventListener('click', () => {
                hide(overlay);
                setTimeout(() => overlay.remove(), 300);
            });
        }
    };

    window.handleCaptchaChallenge = function(challenge) {
        return new Promise((resolve, reject) => {
            const existing = document.getElementById('captcha-modal-overlay');
            if (existing) existing.remove();
            
            const overlay = document.createElement('div');
            overlay.id = 'captcha-modal-overlay';
            overlay.className = 'modal-overlay';
            overlay.style.zIndex = '10005';

            if (challenge.captcha === 'turnstile') {
                overlay.innerHTML = `
                    <div class="modal-content" style="max-width: 450px; text-align: center;">
                        <div class="modal-header">
                            <h3>Protection Cloudflare</h3>
                            <button id="captcha-modal-close"><i data-lucide="x"></i></button>
                        </div>
                        <div class="modal-body">
                            <p style="margin-bottom: 15px; color: var(--text-sec);">Ce lien est protégé par Cloudflare. Vous devez le résoudre manuellement sur le site source.</p>
                            <p style="margin-bottom: 20px; color: var(--text-sec); font-size: 0.9em;">Une fois sur FlixArt, cliquez sur le lien, résolvez le captcha, puis copiez le lien 1Fichier obtenu pour l'ajouter dans l'onglet "Ajout Manuel" d'Agora.</p>
                            <a href="${challenge.url}" target="_blank" class="btn-action" style="display: inline-flex; align-items: center; gap: 8px; background: var(--primary); color: var(--bg); padding: 12px 20px; border-radius: 8px; text-decoration: none; font-weight: 600;">
                                <i data-lucide="external-link" style="width: 18px; height: 18px;"></i> Ouvrir FlixArt
                            </a>
                        </div>
                    </div>
                `;
            } else {
                overlay.innerHTML = `
                    <div class="modal-content" style="max-width: 400px; text-align: center;">
                        <div class="modal-header">
                            <h3>Vérification requise</h3>
                            <button id="captcha-modal-close"><i data-lucide="x"></i></button>
                        </div>
                        <div class="modal-body">
                            <p style="margin-bottom: 15px; color: var(--text-sec);">Captcha non supporté (${challenge.captcha}).</p>
                        </div>
                    </div>
                `;
            }

            document.body.appendChild(overlay);
            lucide.createIcons({ root: overlay });
            show(overlay);

            const closeBtn = overlay.querySelector('#captcha-modal-close');
            if (closeBtn) {
                closeBtn.addEventListener('click', () => {
                    reject(new Error(challenge.captcha === 'turnstile' ? 'Redirection manuelle requise par Cloudflare.' : 'Captcha annulé.'));
                    hide(overlay);
                    setTimeout(() => overlay.remove(), 300);
                });
            }
        });
    };

    const modalClose = dom('modal-close');
    if (modalClose) {
        modalClose.onclick = () => {
            hide(dom('modal-overlay'));
        };
    }

    const btnLogout = dom('btn-logout');
    if (btnLogout) {
        btnLogout.onclick = async () => {
            await apiCall('/logout', 'POST');
            window.location.href = '/login';
        };
    }

    // --- MANUAL ADD TO JD ---
    const btnManualSubmit = dom('btn-manual-submit');
    if (btnManualSubmit) {
        const typeOptions = document.querySelectorAll('.manual-type-selector .type-option');
        const manualTypeInput = dom('manual-type');
        typeOptions.forEach(opt => {
            opt.onclick = () => {
                typeOptions.forEach(o => o.classList.remove('active'));
                opt.classList.add('active');
                if (manualTypeInput) {
                    manualTypeInput.value = opt.dataset.type;
                }
            };
        });

        btnManualSubmit.onclick = async () => {
            const title = dom('manual-title').value.trim();
            const linksText = dom('manual-links').value.trim();
            const typeValue = manualTypeInput ? manualTypeInput.value : 'film';
            const isSeries = typeValue === 'series';

            if (!title) {
                showToast("⚠️ Veuillez entrer un titre.");
                return;
            }
            if (!linksText) {
                showToast("⚠️ Veuillez ajouter au moins un lien.");
                return;
            }

            toggleBlockingLoader(true, "Envoi des liens à JDownloader...");
            try {
                const res = await apiCall('/jd/add', 'POST', {
                    links: linksText,
                    packageName: title,
                    isSeries: isSeries
                });
                toggleBlockingLoader(false);
                if (res.success) {
                    showToast(`✅ ${res.count} lien(s) envoyé(s) à JDownloader !`);
                    dom('manual-title').value = '';
                    dom('manual-links').value = '';
                    
                    // Reset selector style
                    typeOptions.forEach(o => o.classList.remove('active'));
                    if (typeOptions[0]) typeOptions[0].classList.add('active');
                    if (manualTypeInput) manualTypeInput.value = 'film';

                    setTimeout(() => { window.location.href = '/downloads'; }, 1000);
                } else {
                    showToast("⚠️ Échec de l'envoi.");
                }
            } catch (err) {
                toggleBlockingLoader(false);
                showToast("Erreur: " + err.message);
            }
        };
    }

    // Start
    checkSession();

    // --- DOWNLOAD AUTOMATION ---
    if (dom('downloads-list')) {
        startDownloadLoop();
    }
});