document.addEventListener('DOMContentLoaded', () => {
    const fileUpload = document.getElementById('file-upload');
    const chatForm = document.getElementById('chat-form');
    const chatInput = document.getElementById('chat-input');
    const messagesList = document.getElementById('messages-list');
    const typingIndicator = document.getElementById('typing-indicator');

    function scrollToBottom(force = false) {
        if (!messagesList) return;
        
        // Smart scroll: only scroll if user is already at the bottom or if forced (e.g. sending a message)
        const threshold = 150; // pixels margin
        const isAtBottom = messagesList.scrollHeight - messagesList.scrollTop <= messagesList.clientHeight + threshold;
        
        if (force || isAtBottom) {
            messagesList.scrollTo({
                top: messagesList.scrollHeight,
                behavior: 'smooth'
            });
            
            // Backup for non-smooth support or rendering delays
            setTimeout(() => {
                if (force || messagesList.scrollHeight - messagesList.scrollTop <= messagesList.clientHeight + threshold + 200) {
                    messagesList.scrollTop = messagesList.scrollHeight;
                }
            }, 100);
        }
    }

    // Unified Emoji Categories - Expanded for "Complete" feel
    const EMOJI_CATEGORIES = {
        'Smileys': ['😀', '😃', '😄', '😁', '😆', '😅', '🤣', '😂', '🙂', '🙃', '😉', '😊', '😇', '🥰', '😍', '🤩', '😘', '😗', '😚', '😙', '😋', '😛', '😜', '🤪', '😝', '🤑', '🤗', '🤭', '🤫', '🤔', '🤐', '🤨', '😐', '😑', '😶', '😏', '😒', '🙄', '😬', '🤥', '😌', '😔', '😪', '🤤', '😴', '😷', '🤒', '🤕', '🤢', '🤮', '🤧', '🥵', '🥶', '🥴', '😵', '🤯', '🤠', '🥳', '😎', '🤓', '🧐', '😕', '😟', '🙁', '☹️', '😮', '😯', '😲', '😳', '🥺', '😦', '😧', '😨', '😰', '😥', '😢', '😭', '😱', '😖', '😣', '😞', '😓', '😩', '😫', '🥱', '😤', '😡', '😠', '🤬', '😈', '👿', '👹', '👺', '💀', '☠️', '💩', '🤡', '👻', '👽', '👾', '🤖', '😺', '😸', '😻', '😼', '😽', '🙀', '😿', '😾', '🙈', '🙉', '🙊', '💋', '💌', '💘', '💝', '💖', '💗', '💓', '💞', '💕', '💟', '❣️', '💔', '❤️', '🧡', '💛', '💚', '💙', '💜', '🖤', '🤍', '🤎', '💯', '💢', '💥', '💫', '💦', '💨', '🕳️', '💣', '💬', '👁️‍🗨️', '🗨️', '🗯️', '💭', '💤', '🪐', '🌠', '🎇', '🎆', '🌇', '🌆', '🏙️', '🌃', '🌌'],
        'Gestures': ['👋', '🤚', '🖐️', '✋', '🖖', '👌', '🤏', '✌️', '🤞', '🤟', '🤘', '🤙', '👈', '👉', '👆', '🖕', '👇', '☝️', '👍', '👎', '✊', '👊', '🤛', '🤜', '👏', '🙌', '👐', '🤲', '🤝', '🙏', '✍️', '💅', '🤳', '💪', '🦾', '🦵', '🦿', '🦶', '👂', '🦻', '👃', '🧠', '🦷', '🦴', '👀', '👁️', '👅', '👄', '🖖', '🤘', '🤙', '🖐️', '🖕', '🖖', '✍️', '🤳', '💪', '🦾'],
        'People': ['👶', '🧒', '👦', '👧', '🧑', '👱', '👨', '👩', '🧓', '👴', '👵', '👮', '🕵️', '💂', '👷', '🤴', '👸', '👳', '👲', '🧕', '🤵', '👰', '🤰', '🤱', '👼', '🎅', '🤶', '🦸', '🦹', '🧙', '🧚', '🧛', '🧜', '🧝', '🧞', '🧟', '💆', '💇', '🚶', '🏃', '💃', '🕺', '🕴️', '👯', '🧖', '🧗', '🤺', '🏇', '⛷️', '🏂', '🏌️', '🏄', '🚣', '🏊', '⛹️', '🏋️', '🚴', '🚵', '🤸', '🤼', '🤽', '🤾', '🤹', '🧘', '🛀', '🛌'],
        'Animals': ['🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼', '🐨', '🐯', '🦁', '🐮', '🐷', '🐽', '🐸', '🐵', '🙈', '🙉', '🙊', '🐒', '🐔', '🐧', '🐦', '🐤', '🐣', '🐥', '🦆', '🦅', '🦉', '🦇', '🐺', '🐗', '🐴', '🦄', '🐝', '🐛', '🦋', '🐌', '🐞', '🐜', '🦟', '🦗', '🕷️', '🕸️', '蠍', '🐢', '🐍', '🦎', '🦖', '🦕', '🐙', '🦑', '🦐', '🦞', '🦀', '🐡', '🐠', '🐟', '🐬', '🐳', '🐋', '🦈', '🐊', '🐅', '🐆', '🦓', '🦍', '🦧', '🐘', '🦛', '🦏', '🐪', '🐫', '🦒', '🦘', '🦬', '🐃', '🐂', '🐄', '🐎', '🐖', '🐏', '🐑', '🐐', '🦌', '🐕', '🐩', '🦮', '🐕‍🦺', '🐈', '🐈‍⬛', '🐓', '🦃', '🦚', '🦜', '🦢', '🦩', '🕊️', '🐇', '🦝', '🦨', '🦡', '🦦', '🦥', '🐁', '🐀', '🐿️', '🦔', '🐾', '🐉', '🐲', '🌵', '🎄', '🌲', '🌳', '🌴', '🌱', '🌿', '☘️', '🍀', '🎍', '🎋', '🍃', '🍂', '🍁', '🍄', '🐚', '🌾'],
        'Nature': ['💐', '🌷', '🌹', '🥀', '🌺', '🌸', '🌼', '🌻', '🌞', '🌝', '🌛', '🌜', '🌚', '🌕', '🌖', '🌗', '🌘', '🌑', '🌒', '🌓', '🌔', '🌙', '🌎', '🌍', '🌏', '🪐', '💫', '⭐️', '🌟', '✨', '⚡️', '☄️', '💥', '🔥', '🌪️', '🌈', '☀️', '🌤️', '⛅️', '🌥️', '☁️', '🌦️', '🌧️', '🌨️', '🌩️', '❄️', '☃️', '⛄️', '🌬️', '💨', '💧', '💦', '☔️', '☂️', '🌊', '🌫️', '⛰️', '🏔️', '🗻', '🌋', '🏜️', '🏖️', '🏝️', '🏕️', '⛺️'],
        'Food': ['🍏', '🍎', '🍐', '🍊', '🍋', '🍌', '🍉', '🍇', '🍓', '🍈', '🍒', '🍑', '🥭', '🍍', '🥥', '🥝', '🍅', '🍆', '🥑', '🥦', '🥬', '🥒', '🌽', '🥕', '🧄', '🧅', '🍄', '🥜', '🌰', '🍞', '🥐', '🥖', '🥨', '🥯', '🥞', '🧇', '🧀', '🍖', '🍗', '🥩', '🥓', '🍔', '🍟', '🍕', '🌭', '🥪', '🌮', '🌯', '🥙', '🧆', '🍳', '🥘', '🍲', '🥣', '🥗', '🍿', 'バター', '🧂', '🥫', '🍱', '🍘', '🍙', '🍚', '🍛', '🍜', '🍝', '🍠', '🍢', '🍣', '🍤', '🍥', '🥮', '🍡', '🥟', '🥠', '🥡', '🍦', '🍧', '🍨', '🍩', '🍪', '🎂', '🍰', '🧁', '🥧', '🍫', '🍬', '🍭', '🍮', '🍯', '🍼', '🥛', '☕️', '🍵', '🧉', '🥤', '🧃', '🍺', '🍻', '🥂', '🍷', '🥃', '🍸', '🍹', '🍾', '🧊', '🥄', '🍴', '🍽️'],
        'Activities': ['⚽️', '🏀', '🏈', '⚾️', '🥎', '🎾', '🏐', '🏉', '🎱', '🏓', '🏸', '🥅', '🏒', '🏑', '🏏', '⛳️', '🏹', '🎣', '🥊', '🥋', '🛹', '🛷', '⛸️', '🥌', '🎿', '⛷️', '🏂', '🏋️', '🤺', '🤼', '🤸', '⛹️', '🤽', '🤾', '🤹', '🧘', '🏇', '🚣', '🏊', '🚴', '🚵', '🧗', '🎖️', '🏆', '🏅', '🥇', '🥈', '🥉', '🎫', '🎟️', '🎭', '🎨', '🎬', '🎤', '🎧', '🎼', '🎹', '🥁', '🎷', '🎺', '🎸', '🪕', '🎻', '🎲', '♟️', '🎯', 'コツ', '🎮', '🎰', '🧩'],
        'Travel': ['🚗', '🚕', '🚙', '🚌', '🚎', '🏎️', '🚓', '🚑', '🚒', '🚐', '🚚', '🚛', '🚜', '🛵', '🚲', '🛴', '🚏', '🛣️', '🛤️', '⛽️', '🚨', '🚥', '🚦', '🚧', '⚓️', '⛵️', '🚤', '🛳️', '⛴️', '🚢', '✈️', '🛫', '🛬', '💺', '🚁', '🚟', 'ケーブル', '🚡', '🚀', '🛸', '🛰️', '⌛️', '⏳', '⌚️', '⏰', '⏱️', '⏲️', '🕰️', '🌡️', '🌃', '🏙️', '🌄', '🌅', '🌆', '🌇', '🌉', '🎠', '🎡', '🎢', '🚂', '🚃', '🚄', '🚅', '🚆', '🚇', '🚈', '🚉', '🚊', '🚝', '🚞', '🚋'],
        'Objects': ['⌚️', '📱', '📲', '💻', '⌨️', '🖱️', '🖲️', '🕹️', '🗜️', '💽', '💾', '💿', '📀', '📼', '📷', '📸', '📹', '🎥', '📽️', '🎞️', '📞', '📠', '📺', '📻', '🎙️', '🎚️', '🎛️', '🧭', '⏱️', '⏲️', '⏰', '🕰️', '⌛️', '⏳', '📡', '🔋', 'プラグ', '💡', '🔦', '🕯️', '🪔', '🧯', '🛢️', '💸', '💵', '💴', '💶', '💷', '💰', '💳', '💎', '⚖️', '🧰', 'レンチ', '🔨', '⚒️', '🛠️', '⛏️', 'ナット', '⚙️', '🧱', '鎖', '🧲', '🔫', '💣', '🧨', '🪓', 'ナイフ', '🗡️', '⚔️', '盾', '🚬', '⚰️', '⚱️', '🏺', '水晶', '🧿', '📿', '💈', '⚗️', '望遠鏡', '🔬', '🕳️', '💊', '💉', '🩸', 'DNA', '🦠', '🧫', '🧪', '🌡️', '🧹', 'カゴ', '🧻', '石鹸', 'スポンジ', '🪒', 'ローション', '🛎️', '鍵', '🗝️', 'ドア', '椅子', 'ソファ', 'ベッド', '🛌', 'テディベア', '額縁', '袋', 'カート', '🎁', '🎈', '🎏', 'リボン', '🎊', '🎉', '人形', '提灯', '🎐', '🧧', '✉️', '📩', '📨', '📧', '💌', '📥', '📤', '📦', '🏷️', 'フォルダ', '📂', 'カレンダー', '📆', '🗒️', '🗓️', '📇', 'チャート', '📉', '📊', 'クリップボード', '画鋲', '📍', '📎', '🖇️', '定規', '📐', 'ハサミ', '🗃️', 'キャビネット', 'ゴミ箱', '🔒', '🔓', '🔏', '🔐', '鍵', '🗝️'],
        'Symbols': ['💘', '💝', '💖', '💗', '💓', '💞', '💕', '💟', '❣️', '💔', '❤️', '🧡', '💛', '💚', '💙', '💜', '🖤', '🤍', '🤎', '💯', '💢', '💥', '💫', '💦', '💨', '🕳️', '💣', '💬', '👁️‍🗨️', '🗨️', '🗯️', '💭', '💤', '🌐', '♠️', '♥️', '♦️', '♣️', 'ジョーカー', '🀄️', '🎴', '🔇', '🔈', '🔉', '🔊', '📢', '📣', '📯', '🔔', '🔕', '🎼', '🎵', '🎶', '💹', 'ATM', '🚮', '🚰', '♿️', '🚹', '🚺', '🚻', '🚼', '🚾', '🛂', 'カスタム', 'バゲージ', '🛅', '⚠️', '🚸', '⛔️', '🚫', '🚳', '🚯', '🚱', '🚷', '📵', '🔞', '放射能', 'バイオ', '⬆️', '↗️', '➡️', '↘️', '⬇️', '↙️', '⬅️', '↖️', '↕️', '↔️', '↩️', '↪️', '⤴️', '⤵️', '🔃', '🔄', '🔙', '🔚', '🔛', '🔜', '🔝', '🛐', '⚛️', '🕉️', '✡️', '☸️', '☯️', '✝️', '☦️', '☪️', '☮️', '🕎', '🔯', '♈️', '♉️', '♊️', '♋️', '♌️', '♍️', '♎️', '♏️', '♐️', '♑️', '♒️', '♓️', '⛎', '🔀', '🔁', '🔂', '▶️', '⏩', '⏭️', '⏯️', '◀️', '⏪', '⏮️', '🔼', '⏫', '🔽', '⏬', '⏸️', '⏹️', '⏺️', '⏏️', '🎦', '🔅', '🔆', '📶', '📳', '📴', '➕', '➖', '➗', '✖️', '♾️', '‼️', '⁉️', '❓', '❔', '❕', '❗️', '〰️', '💱', '💲', '⚕️', '♻️', '⚜️', '🔱', '📛', '🔰', '⭕️', '✅', '☑️', '✔️', '✖️', '❌', '❎', '➰', '➿', '〽️', '✳️', '✴️', '❇️', '‼️', '🈁', '🈂️', '🈷️', '🈶', '🈯️', '🉐', '🈹', '🈚️', '🈲', '🉑', '🈸', '🈴', '🈳', '㊗️', '㊙️', '🈺', '🈵', '🔴', '🟠', '🟡', '🟢', '🔵', '🟣', '🟤', '⚫️', '⚪️', '🟥', '🟧', '🟨', '🟩', '🟦', '🟪', '🟫', '⬛️', '⬜️', '♈', '♉', '♊', '♋', '♌', '♍', '♎', '♏', '♐', '♑', '♒', '♓', '⛎', '☸', '☦', '☦', '☪', '☮', '☯', '♈', '♉', '♊', '♋', '♌', '♍', '♎', '♏', '♐', '♑', '♒', '♓', '⛎', '♀', '♂', '⚕', '♾', '⚓', '⚔', '⚖', '⚗', '⚙', '⚖', '⚓', '⚔'],
        'Flags': ['🏁', '🚩', '🎌', '🏴', '🏳️', '🏳️‍🌈', '🏳️‍⚧️', '🏴‍☠️', '🇦🇫', '🇦🇽', '🇦🇱', '🇩🇿', '🇦🇲', '🇦🇺', '🇦🇹', '🇦🇿', '🇧🇪', '🇧🇷', '🇨🇦', '🇨🇱', '🇨🇳', '🇨🇴', '🇨🇿', '🇩🇰', '🇪🇬', '🇫🇮', '🇫🇷', '🇩🇪', '🇬🇷', '🇭🇰', '🇮🇳', '🇮🇩', '🇮🇪', '🇮🇱', '🇮🇹', '🇯🇵', '🇰🇷', '🇲🇽', '🇳🇱', '🇳🇿', '🇳🇴', '🇵🇰', '🇵🇭', '🇵🇱', '🇵🇹', '🇷🇺', '🇸🇦', '🇸🇬', '🇿🇦', '🇪🇸', '🇸🇪', '🇨🇭', '🇹🇭', '🇹🇷', '🇺🇦', '🇦🇪', '🇬🇧', '🇺🇸', '🇻🇳', '🇦🇷', '🇧🇩', '🇧🇪', '🇧🇴', '🇮🇩', '🇮🇷', '🇮🇶', '🇯🇲', '🇰🇿', '🇰🇪', '🇲🇾', '🇲🇦', '🇳🇬', '🇵🇪', '🇷🇴', '🇷🇸', '🇸🇰', '🇺🇾', '🇿🇼']
    };

    const categoryIcons = {
        'Custom': '⭐',
        'Smileys': '😀',
        'Gestures': '👌',
        'People': '👶',
        'Animals': '🐶',
        'Nature': '🌵',
        'Food': '🍏',
        'Activities': '⚽️',
        'Travel': '🚗',
        'Objects': '⌚️',
        'Symbols': '❤️',
        'Flags': '🏁'
    };

    const ALL_EMOJIS = Object.values(EMOJI_CATEGORIES).flat();

    // Unified custom emote loading and caching
    window.CUSTOM_EMOTES_CACHE = [];
    window.loadCustomEmotes = async () => {
        try {
            const resp = await fetch('api/emotes.php?action=list');
            const data = await resp.json();
            if (data.success) {
                window.CUSTOM_EMOTES_CACHE = data.emotes || [];
                return window.CUSTOM_EMOTES_CACHE;
            }
            return [];
        } catch (e) {
            console.error("Failed to load custom emotes", e);
            return [];
        }
    };

    // Settings Emotes Tab Logic
    async function setupSettingsEmotes() {
        console.log("Setting up Emotes Tab...");
        const sidebar = document.getElementById('settings-emotes-sidebar');
        const grid = document.getElementById('settings-emotes-grid');
        const searchInput = document.getElementById('settings-emotes-search');
        const uploadZone = document.getElementById('custom-emote-upload-zone');
        const uploadInput = document.getElementById('emote-upload-input');

        if (!sidebar || !grid) return;

        const categories = ['Custom', ...Object.keys(EMOJI_CATEGORIES)];
        
        const renderGrid = async (category, searchTerm = '') => {
            grid.innerHTML = '<div class="col-12 text-center p-4"><div class="spinner-border spinner-border-sm text-primary"></div></div>';
            
            if (category === 'Custom' && !searchTerm) {
                if (uploadZone) uploadZone.classList.remove('d-none');
                const emotes = await window.loadCustomEmotes();
                grid.innerHTML = '';
                
                if (emotes.length === 0) {
                    grid.innerHTML = '<div class="col-12 text-center text-muted p-4" style="grid-column: 1 / -1;">Aucune emote personnalisée. Ajoutez-en une !</div>';
                } else {
                    emotes.forEach(emote => {
                        const div = document.createElement('div');
                        div.className = 'role-emoji-item rounded d-flex flex-column align-items-center justify-content-center p-2 text-center position-relative';
                        div.style.cursor = 'pointer';
                        div.style.backgroundColor = 'var(--separator-soft)';
                        div.style.height = 'auto';
                        div.innerHTML = `
                            <img src="${emote.path}" style="width: 32px; height: 32px; object-fit: contain;">
                            <small class="text-white mt-1" style="font-size: 10px; opacity: 0.7;">${emote.code}</small>
                            <div class="emote-actions position-absolute top-0 end-0 p-1 d-none">
                                <button class="btn btn-sm btn-link text-info p-0 me-1 edit-emote" title="Renommer"><i class="fas fa-edit" style="font-size: 10px;"></i></button>
                                <button class="btn btn-sm btn-link text-danger p-0 delete-emote" title="Supprimer"><i class="fas fa-trash" style="font-size: 10px;"></i></button>
                            </div>
                        `;
                        
                        div.onmouseenter = () => div.querySelector('.emote-actions')?.classList.remove('d-none');
                        div.onmouseleave = () => div.querySelector('.emote-actions')?.classList.add('d-none');

                        div.onclick = (e) => {
                            if (e.target.closest('.emote-actions')) return;
                            navigator.clipboard.writeText(emote.code);
                        };

                        div.querySelector('.delete-emote').onclick = async (e) => {
                            e.stopPropagation();
                            if (!confirm(`Supprimer l'emote ${emote.code} ?`)) return;
                            const fd = new FormData();
                            fd.append('id', emote.id);
                            const res = await (await fetch('api/emotes.php?action=delete', { method: 'POST', body: fd })).json();
                            if (res.success) renderGrid('Custom');
                        };

                        div.querySelector('.edit-emote').onclick = async (e) => {
                            e.stopPropagation();
                            const newName = prompt("Nouveau nom (sans les :)", emote.name);
                            if (!newName || newName === emote.name) return;
                            const fd = new FormData();
                            fd.append('id', emote.id);
                            fd.append('name', newName);
                            const res = await (await fetch('api/emotes.php?action=rename', { method: 'POST', body: fd })).json();
                            if (res.success) renderGrid('Custom');
                        };

                        grid.appendChild(div);
                    });
                }
            } else {
                if (uploadZone) uploadZone.classList.add('d-none');
                grid.innerHTML = '';
                const list = searchTerm ? ALL_EMOJIS.filter(e => e.includes(searchTerm)) : EMOJI_CATEGORIES[category];
                
                (list || []).forEach(emoji => {
                    const div = document.createElement('div');
                    div.className = 'role-emoji-item rounded d-flex align-items-center justify-content-center p-2';
                    div.style.cursor = 'pointer';
                    div.style.fontSize = '24px';
                    div.style.backgroundColor = 'var(--separator-soft)';
                    div.textContent = emoji;
                    div.onclick = () => {
                        navigator.clipboard.writeText(emoji);
                    };
                    grid.appendChild(div);
                });
            }
        };

        sidebar.innerHTML = '';
        categories.forEach((cat, idx) => {
            const btn = document.createElement('button');
            btn.className = `btn w-100 text-start text-white border-0 py-2 px-3 mb-1 d-flex align-items-center gap-2 ${idx === 0 ? 'active' : ''}`;
            btn.style.backgroundColor = idx === 0 ? 'var(--separator)' : 'transparent';
            btn.innerHTML = `<i class="fas ${cat === 'Custom' ? 'fa-star' : 'fa-smile'} opacity-75"></i> ${cat}`;
            
            btn.onclick = async () => {
                sidebar.querySelectorAll('button').forEach(b => {
                    b.classList.remove('active');
                    b.style.backgroundColor = 'transparent';
                });
                btn.classList.add('active');
                btn.style.backgroundColor = 'var(--separator)';
                await renderGrid(cat);
            };
            sidebar.appendChild(btn);
        });

        searchInput.oninput = async () => {
            const term = searchInput.value.trim();
            if (term) {
                sidebar.querySelectorAll('button').forEach(b => {
                    b.classList.remove('active');
                    b.style.backgroundColor = 'transparent';
                });
                await renderGrid(null, term);
            } else {
                const activeBtn = sidebar.querySelector('button.active');
                const activeCat = activeBtn ? activeBtn.innerText.trim() : 'Custom';
                await renderGrid(activeCat);
            }
        };

        if (uploadInput) {
            uploadInput.onchange = async () => {
                const file = uploadInput.files[0];
                if (!file) return;
                const fd = new FormData();
                fd.append('emote', file);
                const res = await (await fetch('api/emotes.php?action=upload', { method: 'POST', body: fd })).json();
                if (res.success) renderGrid('Custom');
                else alert(res.error || "Upload failed");
            };
        }

        await renderGrid('Custom');
    }

    const UniversalEmojiPicker = {
        currentPicker: null,
        show: async function(anchor, callback, options = {}) {
            this.hide();
            const picker = document.createElement('div');
            picker.className = 'emoji-picker-container rounded shadow-lg p-0 d-flex flex-column';
            picker.style.position = 'fixed';
            picker.style.zIndex = '10000';
            picker.style.width = options.width || '400px';
            picker.style.height = options.height || '450px';
            picker.style.backgroundColor = '#2b2d31';
            picker.style.border = '1px solid #1e1f22';
            picker.style.display = 'flex';
            picker.style.flexDirection = 'column';

            const mainLayout = document.createElement('div');
            mainLayout.className = 'd-flex flex-grow-1 overflow-hidden';

            const tabs = document.createElement('div');
            tabs.className = 'emoji-sidebar d-flex flex-column p-2 border-end border-secondary custom-scrollbar';
            tabs.style.width = '60px';
            tabs.style.overflowY = 'auto';
            tabs.style.backgroundColor = '#1e1f22';

            const contentArea = document.createElement('div');
            contentArea.className = 'd-flex flex-column flex-grow-1';

            const searchContainer = document.createElement('div');
            searchContainer.className = 'p-2 border-bottom border-secondary';
            const searchInput = document.createElement('input');
            searchInput.type = 'text';
            searchInput.placeholder = 'Search emojis...';
            searchInput.className = 'form-control form-control-sm bg-dark border-secondary text-white';
            searchContainer.appendChild(searchInput);

            const grid = document.createElement('div');
            grid.className = 'emoji-grid flex-grow-1 p-2 overflow-auto custom-scrollbar';
            grid.style.display = 'grid';
            grid.style.gridTemplateColumns = 'repeat(auto-fill, minmax(36px, 1fr))';
            grid.style.gap = '4px';
            grid.style.alignContent = 'start';

            const categories = ['Custom', ...Object.keys(EMOJI_CATEGORIES)];
            
            const renderGrid = async (category, searchTerm = '') => {
                grid.innerHTML = '';
                if (category === 'Custom' && !searchTerm) {
                    const emotes = await window.loadCustomEmotes();
                    emotes.forEach(emote => {
                        const div = document.createElement('div');
                        div.className = 'emoji-item rounded p-1 text-center';
                        div.style.cursor = 'pointer';
                        div.innerHTML = `<img src="${emote.path}" style="width: 24px; height: 24px; object-fit: contain;" title="${emote.code}">`;
                        div.onclick = () => {
                            callback(emote.code);
                            if (!options.keepOpen) this.hide();
                        };
                        grid.appendChild(div);
                    });
                } else {
                    const list = searchTerm ? ALL_EMOJIS.filter(e => e.includes(searchTerm)) : EMOJI_CATEGORIES[category];
                    (list || []).forEach(emoji => {
                        const div = document.createElement('div');
                        div.className = 'emoji-item rounded p-1 text-center';
                        div.style.cursor = 'pointer';
                        div.style.fontSize = '20px';
                        div.textContent = emoji;
                        div.onclick = () => {
                            callback(emoji);
                            if (!options.keepOpen) this.hide();
                        };
                        grid.appendChild(div);
                    });
                }
            };

            categories.forEach(cat => {
                const btn = document.createElement('button');
                btn.className = 'btn btn-link text-white text-decoration-none p-2 mb-1 opacity-75';
                btn.title = cat;
                btn.innerHTML = categoryIcons[cat] || '😀';
                btn.onclick = async () => {
                    tabs.querySelectorAll('button').forEach(b => b.classList.remove('active'));
                    btn.classList.add('active');
                    await renderGrid(cat);
                };
                tabs.appendChild(btn);
            });

            searchInput.oninput = async () => {
                const term = searchInput.value.trim();
                if (term) {
                    tabs.querySelectorAll('button').forEach(b => b.classList.remove('active'));
                    await renderGrid(null, term);
                } else {
                    const activeBtn = tabs.querySelector('button.active');
                    await renderGrid(activeBtn ? activeBtn.title : 'Custom');
                }
            };

            mainLayout.appendChild(tabs);
            contentArea.appendChild(searchContainer);
            contentArea.appendChild(grid);
            mainLayout.appendChild(contentArea);
            picker.appendChild(mainLayout);
            
            document.body.appendChild(picker);
            this.currentPicker = picker;

            // Positioning
            const rect = anchor.getBoundingClientRect();
            let top = rect.top - picker.offsetHeight - 10;
            if (top < 0) top = rect.bottom + 10;
            let left = rect.left;
            if (left + picker.offsetWidth > window.innerWidth) left = window.innerWidth - picker.offsetWidth - 20;
            if (left < 10) left = 10;
            picker.style.top = `${top}px`;
            picker.style.left = `${left}px`;

            await renderGrid('Custom');

            const outsideClick = (e) => {
                if (!picker.contains(e.target) && e.target !== anchor && !anchor.contains(e.target)) {
                    this.hide();
                    document.removeEventListener('click', outsideClick);
                }
            };
            setTimeout(() => document.addEventListener('click', outsideClick), 10);
        },
        hide() {
            if (this.currentPicker) {
                this.currentPicker.remove();
                this.currentPicker = null;
            }
        }
    };

    // Replace old showEmojiPicker and role grid logic
    window.showEmojiPicker = (anchor, callback) => UniversalEmojiPicker.show(anchor, callback, { width: '900px', height: '500px' });

    window.renderEmojiToElement = (code, el) => {
        if (!el) return;
        if (!code) {
            el.innerHTML = "";
            return;
        }
        if (typeof code === "string" && code.startsWith(':') && code.endsWith(':')) {
            const ce = window.CUSTOM_EMOTES_CACHE.find(e => e.code === code);
            if (ce) {
                el.innerHTML = `<img src="${ce.path}" style="width: 32px; height: 32px; object-fit: contain;">`;
                return;
            }
        }
        el.textContent = code;
    };

    // Unified Emoji Picker & Modal Logic
    document.addEventListener("click", (e) => {
        // Emoji Picker Triggers
        const triggers = {
            "role-emoji-select-btn": { target: "edit-role-icon", preview: "selected-role-emoji-preview" },
            "add-autorole-emoji-btn": { target: "add-autorole-icon", preview: "add-autorole-emoji-preview" },
            "edit-autorole-emoji-btn": { target: "edit-autorole-icon", preview: "edit-autorole-emoji-preview" }
        };

        const btn = e.target.closest("button[id]");
        if (btn && triggers[btn.id]) {
            e.preventDefault();
            const config = triggers[btn.id];
            UniversalEmojiPicker.show(btn, (emoji) => {
                const input = document.getElementById(config.target);
                const preview = document.getElementById(config.preview);
                if (input) input.value = emoji;
                window.renderEmojiToElement(emoji, preview);
            }, { width: "900px", height: "500px" });
            return;
        }

        // Chat Emoji Picker
        const chatEmojiBtn = e.target.closest("#chat-emoji-btn");
        if (chatEmojiBtn) {
            e.preventDefault();
            UniversalEmojiPicker.show(chatEmojiBtn, (emoji) => {
                const chatInput = document.getElementById("chat-input");
                if (chatInput) {
                    chatInput.value += emoji;
                    chatInput.focus();
                }
            }, { keepOpen: true, width: "900px", height: "500px" });
            return;
        }

        // Autorole Edit modal filling
        const editAutoroleBtn = e.target.closest(".edit-autorole-btn");
        if (editAutoroleBtn) {
            const id = editAutoroleBtn.dataset.id;
            const icon = editAutoroleBtn.dataset.icon;
            const title = editAutoroleBtn.dataset.title;
            const roleId = editAutoroleBtn.dataset.roleId;

            const idInput = document.getElementById("edit-autorole-id");
            const iconInput = document.getElementById("edit-autorole-icon");
            const titleInput = document.getElementById("edit-autorole-title");
            const roleIdInput = document.getElementById("edit-autorole-role-id");
            const preview = document.getElementById("edit-autorole-emoji-preview");

            if (idInput) idInput.value = id;
            if (iconInput) iconInput.value = icon;
            if (titleInput) titleInput.value = title;
            if (roleIdInput) roleIdInput.value = roleId;

            if (preview) window.renderEmojiToElement(icon, preview);
            return;
        }
    });

    window.loadCustomEmotes();

    const emotesTabBtn = document.getElementById('emotes-tab-btn');
    if (emotesTabBtn) {
        emotesTabBtn.addEventListener('click', () => {
            setupSettingsEmotes();
        });
    }

    // Scroll to bottom
    scrollToBottom(true);

    const currentChannel = window.activeChannelId || new URLSearchParams(window.location.search).get('channel_id') || 1;
    const currentThread = new URLSearchParams(window.location.search).get('thread_id');
    let typingTimeout;

    // Notification Permission
    if ("Notification" in window && Notification.permission === "default") {
        Notification.requestPermission();
    }

    // WebSocket for real-time
    let ws;
    let voiceHandler;

    function connectWS() {
        try {
            ws = new WebSocket('ws://' + window.location.hostname + ':8080');
            
            if (typeof VoiceChannel !== 'undefined') {
                voiceHandler = new VoiceChannel(ws);
            }

            ws.onmessage = (e) => {
                const msg = JSON.parse(e.data);
                
                // Voice signaling
                if (msg.type && msg.type.startsWith('voice_')) {
                    if (voiceHandler) voiceHandler.handleSignaling(msg);
                    return;
                }

                if (msg.type === 'message') {
                    const data = JSON.parse(msg.data);
                    if (data.channel_id == currentChannel) {
                        appendMessage(data);

                        // Desktop Notifications for mentions
                        if (data.content.includes(`@${window.currentUsername}`) && data.user_id != window.currentUserId) {
                            if (Notification.permission === "granted" && !window.isDndMode) {
                                new Notification(`Mention in #${window.currentChannelName}`, {
                                    body: `${data.username}: ${data.content}`,
                                    icon: data.avatar_url || ''
                                });
                            }
                        }
                    }
                } else if (msg.type === 'typing') {
                    if (msg.channel_id == currentChannel && msg.user_id != window.currentUserId) {
                        showTyping(msg.username);
                    }
                } else if (msg.type === 'reaction') {
                    updateReactionUI(msg.message_id, msg.reactions);
                } else if (msg.type === 'message_edit') {
                    const el = document.querySelector(`.message-item[data-id="${msg.message_id}"] .message-text`);
                    if (el) el.innerHTML = msg.content.replace(/\n/g, '<br>');
                } else if (msg.type === 'message_delete') {
                    document.querySelector(`.message-item[data-id="${msg.message_id}"]`)?.remove();
                } else if (msg.type === 'presence') {
                    updatePresenceUI(msg.user_id, msg.status);
                }
            };
            ws.onopen = () => {
                ws.send(JSON.stringify({
                    type: 'presence',
                    user_id: window.currentUserId,
                    status: 'online'
                }));
            };
            ws.onclose = () => setTimeout(connectWS, 3000);
        } catch (e) {
            console.warn('WebSocket connection failed.');
        }
    }
    connectWS();

    // Polling as fallback for real-time
    let lastMessageId = 0;
    const findLastMessageId = () => {
        const items = document.querySelectorAll('.message-item');
        if (items.length > 0) {
            lastMessageId = Math.max(...Array.from(items).map(i => parseInt(i.dataset.id) || 0));
        }
    };
    findLastMessageId();

    setInterval(async () => {
        if (!currentChannel) return;
        try {
            const resp = await fetch(`api_v1_messages.php?channel_id=${currentChannel}&after_id=${lastMessageId}`);
            const data = await resp.json();
            if (data.success && data.messages && data.messages.length > 0) {
                data.messages.forEach(msg => {
                    appendMessage(msg);
                });
            }
        } catch (e) { }
    }, 1000);

    function showTyping(username) {
        if (!typingIndicator) return;
        typingIndicator.textContent = `${username} is typing...`;
        clearTimeout(typingTimeout);
        typingTimeout = setTimeout(() => {
            if (typingIndicator) typingIndicator.textContent = '';
        }, 3000);
    }

    chatInput?.addEventListener('input', () => {
        if (ws && ws.readyState === WebSocket.OPEN) {
            ws.send(JSON.stringify({
                type: 'typing',
                channel_id: currentChannel,
                user_id: window.currentUserId,
                username: window.currentUsername
            }));
        }
    });

    chatForm?.addEventListener('submit', (e) => {
        e.preventDefault();
        const content = chatInput.value.trim();
        const file = fileUpload.files[0];
        if (!content && !file) return;

        chatInput.value = '';
        const formData = new FormData();
        formData.append('content', content);
        formData.append('channel_id', currentChannel);
        if (currentThread) {
            formData.append('thread_id', currentThread);
        }
        
        const progressContainer = document.getElementById('upload-progress-container');
        const progressBar = document.getElementById('upload-progress-bar');
        const progressPercent = document.getElementById('upload-percentage');
        const progressFilename = document.getElementById('upload-filename');

        if (file) {
            formData.append('file', file);
            fileUpload.value = ''; // Clear file input
            
            // Show progress bar
            progressContainer.style.display = 'block';
            progressFilename.textContent = `Uploading: ${file.name}`;
            progressBar.style.width = '0%';
            progressPercent.textContent = '0%';
        }

        const xhr = new XMLHttpRequest();
        xhr.open('POST', 'api_v1_messages.php', true);

        xhr.upload.onprogress = (ev) => {
            if (ev.lengthComputable && file) {
                const percent = Math.round((ev.loaded / ev.total) * 100);
                progressBar.style.width = percent + '%';
                progressPercent.textContent = percent + '%';
            }
        };

        xhr.onload = () => {
            if (xhr.status === 200) {
                const result = JSON.parse(xhr.responseText);
                if (result.success) {
                    appendMessage(result.message);
                    if (ws && ws.readyState === WebSocket.OPEN) {
                        ws.send(JSON.stringify({
                            type: 'message',
                            data: JSON.stringify({
                                ...result.message,
                                channel_id: currentChannel
                            })
                        }));
                    }
                } else {
                    alert(result.error || 'Failed to send message');
                }
            }
            progressContainer.style.display = 'none';
        };

        xhr.onerror = () => {
            console.error('XHR Error');
            progressContainer.style.display = 'none';
            alert('An error occurred during the upload.');
        };

        xhr.send(formData);
    });

    // Handle Reaction Clicks
    document.addEventListener('click', (e) => {
        const badge = e.target.closest('.reaction-badge');
        if (badge) {
            const msgId = badge.parentElement.dataset.messageId;
            const emoji = badge.dataset.emoji;
            toggleReaction(msgId, emoji);
            return;
        }

        const addBtn = e.target.closest('.add-reaction-btn');
        if (addBtn) {
            const msgId = addBtn.parentElement.dataset.messageId;
            showEmojiPicker(addBtn, (emoji) => toggleReaction(msgId, emoji));
            return;
        }
    });

    async function toggleReaction(messageId, emoji) {
        try {
            const resp = await fetch('api_v1_reactions.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ message_id: messageId, emoji: emoji })
            });
            const result = await resp.json();
            if (result.success) {
                if (ws && ws.readyState === WebSocket.OPEN) {
                    ws.send(JSON.stringify({
                        type: 'reaction',
                        message_id: messageId,
                        reactions: result.reactions
                    }));
                }
                updateReactionUI(messageId, result.reactions);
            }
        } catch (e) { console.error(e); }
    }

    function updateReactionUI(messageId, reactions) {
        const container = document.querySelector(`.message-reactions[data-message-id="${messageId}"]`);
        if (!container) return;

        const addBtn = container.querySelector('.add-reaction-btn');
        container.innerHTML = '';
        reactions.forEach(r => {
            const badge = document.createElement('span');
            const userList = r.users.split(',');
            const active = userList.includes(String(window.currentUserId));
            badge.className = `reaction-badge ${active ? 'active' : ''}`;
            badge.dataset.emoji = r.emoji;
            badge.innerHTML = `${r.emoji} <span class="count">${r.count}</span>`;
            container.appendChild(badge);
        });
        container.appendChild(addBtn);
    }

    function updatePresenceUI(userId, status) {
        const memberItem = document.querySelector(`.start-dm-btn[data-user-id="${userId}"] .message-avatar`);
        if (memberItem) {
            let indicator = memberItem.querySelector('.presence-indicator');
            if (!indicator) {
                indicator = document.createElement('div');
                indicator.className = 'presence-indicator';
                memberItem.appendChild(indicator);
            }
            indicator.style.position = 'absolute';
            indicator.style.bottom = '0';
            indicator.style.right = '0';
            indicator.style.width = '10px';
            indicator.style.height = '10px';
            indicator.style.borderRadius = '50%';
            indicator.style.border = '2px solid var(--bg-members)';
            indicator.style.backgroundColor = status === 'online' ? '#23a559' : '#80848e';
        }
    }

    // Voice
    if (voiceHandler) {
        document.querySelectorAll('.voice-item').forEach(item => {
            item.addEventListener('click', () => {
                const cid = item.dataset.channelId;
                if (voiceHandler.currentChannelId == cid) {
                    voiceHandler.leave();
                    item.classList.remove('active');
                } else {
                    voiceHandler.join(cid);
                    document.querySelectorAll('.voice-item').forEach(i => i.classList.remove('active'));
                    item.classList.add('active');
                }
            });
        });
    }

    // Message Actions (Edit/Delete)
    document.addEventListener('click', async (e) => {
        const editBtn = e.target.closest('.action-btn.edit');
        if (editBtn) {
            const msgId = editBtn.dataset.id;
            const msgItem = editBtn.closest('.message-item');
            const textEl = msgItem.querySelector('.message-text');
            const originalContent = textEl.innerText;
            
            const input = document.createElement('input');
            input.type = 'text';
            input.className = 'form-control bg-dark text-white';
            input.value = originalContent;
            
            textEl.innerHTML = '';
            textEl.appendChild(input);
            input.focus();
            
            input.onkeydown = async (ev) => {
                if (ev.key === 'Enter') {
                    const newContent = input.value.trim();
                    if (newContent && newContent !== originalContent) {
                        const resp = await fetch('api_v1_messages.php', {
                            method: 'PUT',
                            headers: { 'Content-Type': 'application/json' },
                            body: JSON.stringify({ id: msgId, content: newContent })
                        });
                        if ((await resp.json()).success) {
                            textEl.innerHTML = newContent.replace(/\n/g, '<br>');
                            ws?.send(JSON.stringify({ type: 'message_edit', message_id: msgId, content: newContent }));
                        }
                    } else {
                        textEl.innerHTML = originalContent.replace(/\n/g, '<br>');
                    }
                } else if (ev.key === 'Escape') {
                    textEl.innerHTML = originalContent.replace(/\n/g, '<br>');
                }
            };
            return;
        }

        const deleteBtn = e.target.closest('.action-btn.delete');
        if (deleteBtn) {
            if (!confirm('Delete this message?')) return;
            const msgId = deleteBtn.dataset.id;
            const resp = await fetch('api_v1_messages.php', {
                method: 'DELETE',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ id: msgId })
            });
            if ((await resp.json()).success) {
                deleteBtn.closest('.message-item').remove();
                ws?.send(JSON.stringify({ type: 'message_delete', message_id: msgId }));
            }
            return;
        }

        const pinBtn = e.target.closest('.action-btn.pin');
        if (pinBtn) {
            const msgId = pinBtn.dataset.id;
            const isPinned = pinBtn.dataset.pinned == '1';
            const action = isPinned ? 'unpin' : 'pin';
            
            const resp = await fetch('api_v1_messages.php', {
                method: 'PUT',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ id: msgId, action: action })
            });
            const result = await resp.json();
            if (result.success) {
                location.reload(); // Simplest way to reflect changes across UI
            }
            return;
        }

        const pinnedMessagesBtn = document.getElementById('pinned-messages-btn');
        if (e.target.closest('#pinned-messages-btn')) {
            const container = document.getElementById('pinned-messages-container');
            container.innerHTML = '<div class="p-3 text-center text-muted">Loading pinned messages...</div>';
            const modal = new bootstrap.Modal(document.getElementById('pinnedMessagesModal'));
            modal.show();

            const resp = await fetch(`api_v1_messages.php?channel_id=${currentChannel}&pinned=1`);
            const data = await resp.json();
            if (data.success && data.messages.length > 0) {
                container.innerHTML = '';
                data.messages.forEach(msg => {
                    const div = document.createElement('div');
                    div.className = 'message-item p-2 border-bottom border-secondary';
                    div.style.backgroundColor = 'transparent';
                    const authorStyle = msg.role_color ? `color: ${msg.role_color};` : '';
                    div.innerHTML = `
                        <div class="d-flex align-items-start">
                            <div class="message-avatar" style="width: 32px; height: 32px; margin-right: 10px; ${msg.avatar_url ? `background-image: url('${msg.avatar_url}');` : ''}"></div>
                            <div style="flex: 1;">
                                <div class="message-author" style="font-size: 0.85em; ${authorStyle}">
                                    ${escapeHTML(msg.username)}
                                    ${renderRoleIconJS(msg.role_icon, '14px')}
                                    <span class="message-time">${msg.time}</span>
                                </div>
                                <div class="message-text" style="font-size: 0.9em;">
                                    ${escapeHTML(msg.content).replace(/\n/g, '<br>')}
                                </div>
                            </div>
                        </div>
                    `;
                    container.appendChild(div);
                });
            } else {
                container.innerHTML = '<div class="p-3 text-center text-muted">No pinned messages in this channel.</div>';
            }
            return;
        }
        
        // Member Menu
        const memberItem = e.target.closest('.member-item');
        if (memberItem) {
            const userId = memberItem.dataset.userId;
            const username = memberItem.dataset.username;
            const avatar = memberItem.dataset.avatar;
            const roleIds = (memberItem.dataset.roleIds || '').split(',').filter(id => id);
            
            // Create or show member menu
            document.querySelector('.member-context-menu')?.remove();
            const menu = document.createElement('div');
            menu.className = 'member-context-menu bg-dark border border-secondary rounded p-2';
            menu.style.position = 'fixed';
            menu.style.zIndex = '1000';
            menu.style.boxShadow = '0 4px 12px rgba(0,0,0,0.5)';
            menu.style.minWidth = '180px';
            
            const rect = memberItem.getBoundingClientRect();
            menu.style.top = `${rect.top}px`;
            menu.style.left = `${rect.left - 190}px`;

            let rolesHtml = '';
            if (roleIds.length > 0) {
                // Deduplicate and filter valid roles from serverRoles
                const uniqueRoleIds = [...new Set(roleIds)];
                const roles = uniqueRoleIds.map(id => serverRoles.find(r => r.id == id)).filter(r => r);
                if (roles.length > 0) {
                    rolesHtml = `
                        <div class="mb-2 p-1">
                            <div class="small text-muted text-uppercase mb-1" style="font-size: 0.6em; font-weight: bold; opacity: 0.8;">Rôles</div>
                            <div class="d-flex flex-wrap gap-1">
                                ${roles.map(r => `
                                    <span class="badge rounded-pill d-flex align-items-center" style="background-color: rgba(0,0,0,0.3); border: 1px solid ${r.color}; font-size: 0.7em; color: ${r.color}; font-weight: 500; padding: 2px 8px;">
                                        ${r.icon_url ? `<img src="${r.icon_url}" style="width: 14px; height: 14px; margin-right: 4px; object-fit: contain;">` : ''}
                                        ${escapeHTML(r.name)}
                                    </span>
                                `).join('')}
                            </div>
                        </div>
                        <div class="border-top border-secondary mb-2 mx-1"></div>
                    `;
                }
            }

            menu.innerHTML = `
                <div class="p-1 d-flex align-items-center mb-1">
                    <div class="message-avatar me-2" style="width: 24px; height: 24px; ${avatar ? `background-image: url('${avatar}');` : ''}"></div>
                    <span class="small fw-bold">${escapeHTML(username)}</span>
                </div>
                <div class="border-top border-secondary mb-2 mx-1"></div>
                ${rolesHtml}
                <button class="btn btn-sm btn-dark w-100 text-start mb-1 member-menu-action" data-action="message">Message</button>
                ${(window.isServerOwner || window.canManageServer) ? `<button class="btn btn-sm btn-dark w-100 text-start member-menu-action" data-action="edit-roles">Éditer son rôle</button>` : ''}
            `;
            
            document.body.appendChild(menu);

            // Close menu on click outside
            const closeMenu = (e) => {
                if (!menu.contains(e.target)) {
                    menu.remove();
                    document.removeEventListener('mousedown', closeMenu);
                }
            };
            document.addEventListener('mousedown', closeMenu);

            menu.querySelectorAll('.member-menu-action').forEach(btn => {
                btn.onclick = async () => {
                    const action = btn.dataset.action;
                    if (action === 'message') {
                        const formData = new FormData();
                        formData.append('user_id', userId);
                        const resp = await fetch('api_v1_dms.php', { method: 'POST', body: formData });
                        const result = await resp.json();
                        if (result.success) {
                            window.location.href = `?server_id=dms&channel_id=${result.channel_id}`;
                        }
                    } else if (action === 'edit-roles') {
                        openEditUserRolesModal(userId, username, avatar);
                    }
                    menu.remove();
                };
            });
        }
    });

    // Global Search
    const searchInput = document.getElementById('global-search');
    const searchType = document.getElementById('search-type');
    const searchResults = document.getElementById('search-results');
    
    searchInput?.addEventListener('input', async () => {
        const q = searchInput.value.trim();
        const type = searchType.value;
        if (q.length < 2) {
            searchResults.style.display = 'none';
            return;
        }
        
        const resp = await fetch(`api_v1_search.php?q=${encodeURIComponent(q)}&type=${type}&channel_id=${currentChannel}`);
        const data = await resp.json();
        
        if (data.success && data.results.length > 0) {
            searchResults.innerHTML = '';
            data.results.forEach(res => {
                const item = document.createElement('div');
                item.className = 'search-result-item d-flex align-items-center gap-2';
                if (type === 'users') {
                    item.innerHTML = `
                        <div class="message-avatar" style="width: 24px; height: 24px; ${res.avatar_url ? `background-image: url('${res.avatar_url}');` : ''}"></div>
                        <div class="flex-grow-1">
                            <div class="search-result-author">${res.username}</div>
                            <div class="small text-muted" style="font-size: 0.7em;">Click to start conversation</div>
                        </div>
                    `;
                    item.onclick = () => {
                        const formData = new FormData();
                        formData.append('user_id', res.id);
                        fetch('api_v1_dms.php', { method: 'POST', body: formData })
                            .then(r => r.json())
                            .then(resDM => {
                                if (resDM.success) window.location.href = `?server_id=dms&channel_id=${resDM.channel_id}`;
                            });
                    };
                } else {
                    item.innerHTML = `
                        <div class="flex-grow-1">
                            <div class="search-result-author">${res.username}</div>
                            <div class="search-result-text">${res.content}</div>
                        </div>
                    `;
                }
                searchResults.appendChild(item);
            });
            searchResults.style.display = 'block';
        } else {
            searchResults.innerHTML = '<div class="p-2 text-muted">No results found</div>';
            searchResults.style.display = 'block';
        }
    });

    // Channel Permissions Management
    const channelPermissionsTabBtn = document.getElementById('channel-permissions-tab-btn');
    const channelPermissionsRolesList = document.getElementById('channel-permissions-roles-list');
    const addPermRoleList = document.getElementById('add-permission-role-list');
    const channelPermissionsSettings = document.getElementById('channel-permissions-settings');
    const noRoleSelectedView = document.getElementById('no-role-selected-view');
    const selectedPermRoleName = document.getElementById('selected-perm-role-name');
    const removeSelectedPermRole = document.getElementById('remove-selected-perm-role');
    const permissionsTogglesContainer = document.getElementById('permissions-toggles-container');

    let currentSelectedOverrideRole = null;
    let channelPermissionsData = [];

    channelPermissionsTabBtn?.addEventListener('click', async () => {
        const channelId = document.getElementById('edit-channel-id').value;
        currentSelectedOverrideRole = null;
        channelPermissionsSettings.classList.add('d-none');
        noRoleSelectedView.classList.remove('d-none');
        await loadChannelPermissions(channelId);
        await loadRolesForPermissions(channelId);
    });

    async function loadChannelPermissions(channelId) {
        channelPermissionsRolesList.innerHTML = '<div class="text-center p-3 text-muted small">Loading...</div>';
        const resp = await fetch(`api_v1_channel_permissions.php?channel_id=${channelId}`);
        const data = await resp.json();
        if (data.success) {
            channelPermissionsData = data.permissions;
            renderRoleOverridesList(channelId);
        }
    }

    async function loadRolesForPermissions(channelId) {
        if (!addPermRoleList) return;
        addPermRoleList.innerHTML = '<li><span class="dropdown-item text-muted">Loading roles...</span></li>';
        
        try {
            const resp = await fetch(`api_v1_roles.php?server_id=${activeServerId}`);
            const data = await resp.json();
            
            if (data.success) {
                addPermRoleList.innerHTML = '';
                
                // Filter out roles already in overrides
                const existingRoleIds = channelPermissionsData.map(p => parseInt(p.role_id));
                const availableRoles = data.roles.filter(role => !existingRoleIds.includes(parseInt(role.id)));
                
                if (availableRoles.length === 0) {
                    addPermRoleList.innerHTML = '<li><span class="dropdown-item disabled text-muted">No more roles to add</span></li>';
                    if (window.canManageServer) {
                        const divider = document.createElement('li');
                        divider.innerHTML = '<hr class="dropdown-divider border-secondary opacity-25">';
                        addPermRoleList.appendChild(divider);
                        const createLink = document.createElement('li');
                        createLink.innerHTML = '<a class="dropdown-item small text-info" href="#" data-bs-toggle="modal" data-bs-target="#serverSettingsModal" style="font-size: 0.8em;"><i class="fa-solid fa-gear me-1"></i> Create roles in Server Settings</a>';
                        addPermRoleList.appendChild(createLink);
                    }
                    return;
                }

                // Add Roles section
                const header = document.createElement('li');
                header.innerHTML = '<h6 class="dropdown-header text-uppercase" style="font-size: 0.65em; color: #949ba4;">Roles</h6>';
                addPermRoleList.appendChild(header);

                availableRoles.forEach(role => {
                    const li = document.createElement('li');
                    li.innerHTML = `<a class="dropdown-item d-flex align-items-center gap-2 py-2" href="#">
                        <div style="width: 14px; height: 14px; border-radius: 50%; background-color: ${role.color || '#99aab5'}; border: 1px solid var(--separator);"></div>
                        <span style="color: var(--text-primary); font-size: 0.9em;">${role.name}</span>
                    </a>`;
                    li.onclick = async (e) => {
                        e.preventDefault();
                        const postResp = await fetch('api_v1_channel_permissions.php', {
                            method: 'POST',
                            headers: { 'Content-Type': 'application/json' },
                            body: JSON.stringify({ channel_id: channelId, role_id: role.id, allow: 0, deny: 0 })
                        });
                        const postData = await postResp.json();
                        if (postData.success) {
                            await loadChannelPermissions(channelId);
                            await loadRolesForPermissions(channelId);
                            selectOverrideRole(role.id, role.name);
                        } else {
                            alert("Error adding permission: " + (postData.error || "Unknown error"));
                        }
                    };
                    addPermRoleList.appendChild(li);
                });
            } else {
                addPermRoleList.innerHTML = `<li><span class="dropdown-item text-danger">Error: ${data.error || 'Failed to load'}</span></li>`;
            }
        } catch (err) {
            addPermRoleList.innerHTML = '<li><span class="dropdown-item text-danger">Network error</span></li>';
            console.error(err);
        }
    }

    function renderRoleOverridesList(channelId) {
        channelPermissionsRolesList.innerHTML = '';
        if (channelPermissionsData.length === 0) {
            channelPermissionsRolesList.innerHTML = '<div class="text-center p-3 small" style="color: var(--text-primary);">No overrides configured for this channel.</div>';
            return;
        }

        // Sort: @everyone always at top, then by name
        const sortedData = [...channelPermissionsData].sort((a, b) => {
            const nameA = (a.role_name || '').toLowerCase();
            const nameB = (b.role_name || '').toLowerCase();
            const isAEveryone = nameA.includes('everyone');
            const isBEveryone = nameB.includes('everyone');
            if (isAEveryone && !isBEveryone) return -1;
            if (!isAEveryone && isBEveryone) return 1;
            return nameA.localeCompare(nameB);
        });

        sortedData.forEach(p => {
            const item = document.createElement('div');
            item.className = `list-group-item list-group-item-action bg-transparent text-white border-0 mb-1 p-2 small d-flex align-items-center ${currentSelectedOverrideRole == p.role_id ? 'active' : ''}`;
            item.style.cursor = 'pointer';
            item.innerHTML = `
                <div style="width: 8px; height: 8px; border-radius: 50%; background-color: ${p.role_color || '#99aab5'}; margin-right: 8px; flex-shrink: 0;"></div>
                <span class="flex-grow-1 text-truncate">${p.role_name || 'Unknown Role'}</span>
            `;
            item.onclick = () => selectOverrideRole(p.role_id, p.role_name || 'Unknown Role');
            channelPermissionsRolesList.appendChild(item);
        });
    }

    function selectOverrideRole(roleId, roleName) {
        currentSelectedOverrideRole = roleId;
        const channelId = document.getElementById('edit-channel-id').value;
        
        // Update list active state
        renderRoleOverridesList(channelId);
        
        selectedPermRoleName.textContent = roleName;
        noRoleSelectedView.classList.add('d-none');
        channelPermissionsSettings.classList.remove('d-none');
        
        // Load existing permissions for this role
        const p = channelPermissionsData.find(perm => perm.role_id == roleId) || { allow_permissions: 0, deny_permissions: 0 };
        
        // Update toggles (for now only bit 1: View Channel)
        updateToggleUI(1, p.allow_permissions, p.deny_permissions);
    }

    function updateToggleUI(bit, allowPerms, denyPerms) {
        const group = document.querySelector(`.perm-tri-state[data-perm-bit="${bit}"]`);
        if (!group) return;
        
        if (allowPerms & bit) {
            group.querySelector('input[value="allow"]').checked = true;
        } else if (denyPerms & bit) {
            group.querySelector('input[value="deny"]').checked = true;
        } else {
            group.querySelector('input[value="neutral"]').checked = true;
        }
    }

    removeSelectedPermRole?.addEventListener('click', async () => {
        if (!currentSelectedOverrideRole) return;
        const channelId = document.getElementById('edit-channel-id').value;
        
        await fetch('api_v1_channel_permissions.php', {
            method: 'DELETE',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ channel_id: channelId, role_id: currentSelectedOverrideRole })
        });
        
        currentSelectedOverrideRole = null;
        channelPermissionsSettings.classList.add('d-none');
        noRoleSelectedView.classList.remove('d-none');
        loadChannelPermissions(channelId);
    });

    permissionsTogglesContainer?.addEventListener('change', async (e) => {
        if (e.target.type === 'radio') {
            const group = e.target.closest('.perm-tri-state');
            const bit = parseInt(group.dataset.permBit);
            const val = e.target.value;
            const channelId = document.getElementById('edit-channel-id').value;
            const roleId = currentSelectedOverrideRole;
            
            let p = channelPermissionsData.find(perm => perm.role_id == roleId);
            if (!p) {
                p = { role_id: roleId, allow_permissions: 0, deny_permissions: 0 };
            }
            
            let allow = parseInt(p.allow_permissions);
            let deny = parseInt(p.deny_permissions);
            
            // Clear current bit
            allow &= ~bit;
            deny &= ~bit;
            
            if (val === 'allow') allow |= bit;
            if (val === 'deny') deny |= bit;
            
            await fetch('api_v1_channel_permissions.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ channel_id: channelId, role_id: roleId, allow, deny })
            });
            
            // Update local data
            p.allow_permissions = allow;
            p.deny_permissions = deny;
        }
    });

    document.addEventListener('click', async (e) => {
        if (!e.target.closest('.search-container')) {
            searchResults.style.display = 'none';
        }

        if (e.target.classList.contains('move-rule-btn')) {
            if (!window.canManageChannels) return;
            const id = e.target.dataset.id;
            const dir = e.target.dataset.dir;
            const resp = await fetch('api_v1_rules.php', {
                method: 'PATCH',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ id, dir })
            });
            if ((await resp.json()).success) location.reload();
        }
    });

        // Roles Management
        const channelSettingsBtns = document.querySelectorAll('.channel-settings-btn');
        channelSettingsBtns.forEach(btn => {
            btn.addEventListener('click', () => {
                const modal = document.getElementById('editChannelModal');
                const channelId = btn.dataset.id;
                const channelType = btn.dataset.type || 'chat';
                const channelName = btn.dataset.name;
                
                modal.querySelector('#edit-channel-id').value = channelId;
                modal.querySelector('#edit-channel-name').value = channelName;
                modal.querySelector('#header-channel-name').textContent = channelName;
                modal.querySelector('#edit-channel-type').value = channelType;

                // Force switch to Overview tab
                const overviewTabBtn = modal.querySelector('[data-bs-target="#edit-channel-general"]');
                if (overviewTabBtn) {
                    bootstrap.Tab.getOrCreateInstance(overviewTabBtn).show();
                }

                modal.querySelector('#edit-channel-files').checked = btn.dataset.files == '1';
                modal.querySelector('#edit-channel-limit').value = btn.dataset.limit || '';
                modal.querySelector('#edit-channel-status').value = btn.dataset.status || '';
                modal.querySelector('#edit-channel-icon').value = btn.dataset.icon || '';
                modal.querySelector('#edit-channel-rules-role').value = btn.dataset.rulesRole || '';
                modal.querySelector('#edit-channel-category-id').value = btn.dataset.category || '';
                modal.querySelector('#delete-channel-id').value = channelId;

                // Check if channel is named "rôle" or "role"
                const isRoleChannel = channelName.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "") === "role";

                // Toggle rules role visibility
                const rulesRoleContainer = document.getElementById('edit-channel-rules-role-container');
                if (rulesRoleContainer) {
                    rulesRoleContainer.style.display = (channelType === 'rules') ? 'block' : 'none';
                }

                // Hide limit, files and clear chat for rules, autorole, and role channels
                const editLimitContainer = document.getElementById('edit-channel-limit-container');
                const editFilesContainer = document.getElementById('edit-channel-files-container');
                const clearChatBtn = document.getElementById('clear-channel-history-btn');
                
                const hideExtra = (channelType === 'rules' || channelType === 'autorole' || isRoleChannel);
                if (editLimitContainer) editLimitContainer.style.display = hideExtra ? 'none' : 'block';
                if (editFilesContainer) editFilesContainer.style.display = hideExtra ? 'none' : 'block';
                if (clearChatBtn) clearChatBtn.style.display = (channelType === 'rules') ? 'none' : 'inline-block';

                // Reset delete zone
                document.getElementById('delete-confirm-zone').style.display = 'none';

                // Show/Hide RSS tab
                const rssTabNav = document.getElementById('rss-tab-nav');
                const statusContainer = document.getElementById('edit-channel-status-container');
                
                if (channelType === 'announcement') {
                    rssTabNav.style.display = 'block';
                } else {
                    rssTabNav.style.display = 'none';
                    // Switch to General tab if we were on RSS
                    const rssTabBtn = document.getElementById('rss-tab-btn');
                    if (rssTabBtn && rssTabBtn.classList.contains('active')) {
                        bootstrap.Tab.getOrCreateInstance(modal.querySelector('[data-bs-target="#edit-channel-general"]')).show();
                    }
                }

                if (channelType === 'voice') {
                    statusContainer.style.display = 'block';
                } else {
                    statusContainer.style.display = 'none';
                }
            });
        });

        document.getElementById('delete-channel-trigger')?.addEventListener('click', () => {
            document.getElementById('delete-confirm-zone').style.display = 'block';
        });

        // RSS Management
        const editChannelType = document.getElementById('edit-channel-type');
        editChannelType?.addEventListener('change', () => {
            const type = editChannelType.value;
            const rssTabNav = document.getElementById('rss-tab-nav');
            const statusContainer = document.getElementById('edit-channel-status-container');
            const channelName = document.getElementById('edit-channel-name').value;
            const isRoleChannel = channelName.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "") === "role";
            
            rssTabNav.style.display = (type === 'announcement') ? 'block' : 'none';
            statusContainer.style.display = (type === 'voice') ? 'block' : 'none';

            // Rules specific visibility
            const rulesRoleContainer = document.getElementById('edit-channel-rules-role-container');
            if (rulesRoleContainer) {
                rulesRoleContainer.style.display = (type === 'rules') ? 'block' : 'none';
            }
            
            const editLimitContainer = document.getElementById('edit-channel-limit-container');
            const editFilesContainer = document.getElementById('edit-channel-files-container');
            const clearChatBtn = document.getElementById('clear-channel-history-btn');
            
            const hideExtra = (type === 'rules' || type === 'autorole' || isRoleChannel);
            if (editLimitContainer) editLimitContainer.style.display = hideExtra ? 'none' : 'block';
            if (editFilesContainer) editFilesContainer.style.display = hideExtra ? 'none' : 'block';
            if (clearChatBtn) clearChatBtn.style.display = (type === 'rules') ? 'none' : 'inline-block';
        });

        // RSS Management
        const rssTabBtn = document.getElementById('rss-tab-btn');
        const rssFeedsList = document.getElementById('rss-feeds-list');
        const addRssBtn = document.getElementById('add-rss-btn');
        const syncRssBtn = document.getElementById('sync-rss-btn');

        rssTabBtn?.addEventListener('click', loadRssFeeds);

        async function loadRssFeeds() {
            const channelId = document.getElementById('edit-channel-id').value;
            rssFeedsList.innerHTML = '<div class="text-center p-3 text-muted small">Loading feeds...</div>';
            try {
                const resp = await fetch(`api_v1_rss.php?channel_id=${channelId}`);
                const data = await resp.json();
                if (data.success) {
                    renderRssFeeds(data.feeds);
                }
            } catch (e) { console.error(e); }
        }

        function renderRssFeeds(feeds) {
            rssFeedsList.innerHTML = '';
            if (feeds.length === 0) {
                rssFeedsList.innerHTML = '<div class="text-center p-3 text-muted small">No RSS feeds configured.</div>';
                return;
            }
            feeds.forEach(feed => {
                const item = document.createElement('div');
                item.className = 'list-group-item bg-transparent text-white border-secondary p-2 mb-1';
                item.innerHTML = `
                    <div class="d-flex justify-content-between align-items-center mb-1">
                        <span class="small text-truncate" style="max-width: 80%;">${feed.url}</span>
                        <button class="btn btn-sm text-danger delete-rss-btn" data-id="${feed.id}">×</button>
                    </div>
                    <div class="small text-muted" style="font-size: 0.7em;">Last fetched: ${feed.last_fetched_at || 'Never'}</div>
                `;
                rssFeedsList.appendChild(item);
            });
        }

        addRssBtn?.addEventListener('click', async () => {
            const channelId = document.getElementById('edit-channel-id').value;
            const url = document.getElementById('new-rss-url').value.trim();
            if (!url) return;

            const formData = new FormData();
            formData.append('action', 'add');
            formData.append('channel_id', channelId);
            formData.append('url', url);

            const resp = await fetch('api_v1_rss.php', { method: 'POST', body: formData });
            if ((await resp.json()).success) {
                document.getElementById('new-rss-url').value = '';
                loadRssFeeds();
            }
        });

        syncRssBtn?.addEventListener('click', async () => {
            const channelId = document.getElementById('edit-channel-id').value;
            syncRssBtn.disabled = true;
            syncRssBtn.textContent = 'Syncing...';
            
            const formData = new FormData();
            formData.append('action', 'sync');
            formData.append('channel_id', channelId);

            try {
                const resp = await fetch('api_v1_rss.php', { method: 'POST', body: formData });
                const result = await resp.json();
                if (result.success) {
                    alert(`Sync complete! Found ${result.new_items} new items.`);
                    loadRssFeeds();
                }
            } catch (e) { console.error(e); }
            
            syncRssBtn.disabled = false;
            syncRssBtn.textContent = 'Sync Now';
        });

        rssFeedsList?.addEventListener('click', async (e) => {
            if (e.target.classList.contains('delete-rss-btn')) {
                const channelId = document.getElementById('edit-channel-id').value;
                const feedId = e.target.dataset.id;
                const formData = new FormData();
                formData.append('action', 'delete');
                formData.append('channel_id', channelId);
                formData.append('feed_id', feedId);

                await fetch('api_v1_rss.php', { method: 'POST', body: formData });
                loadRssFeeds();
            }
        });

    // Clear Channel History
    const clearHistoryBtn = document.getElementById('clear-channel-history-btn');
    clearHistoryBtn?.addEventListener('click', async () => {
        const channelId = document.getElementById('edit-channel-id').value;
        if (!confirm('Voulez-vous vraiment vider tout l\'historique de ce salon ? Cette action est irréversible.')) return;
        
        try {
            const formData = new FormData();
            formData.append('channel_id', channelId);
            const resp = await fetch('api_v1_clear_channel.php', {
                method: 'POST',
                body: formData
            });
            const result = await resp.json();
            if (result.success) {
                location.reload();
            } else {
                alert(result.error || 'Erreur lors du nettoyage de l\'historique');
            }
        } catch (e) { console.error(e); }
    });

    // Roles Management
    const rolesTabBtn = document.getElementById('roles-tab-btn');
    const rolesList = document.getElementById('roles-list');
    const addRoleBtn = document.getElementById('add-role-btn');
    const membersTabBtn = document.getElementById('members-tab-btn');
    const membersList = document.getElementById('server-members-list');
    const activeServerId = window.activeServerId || new URLSearchParams(window.location.search).get('server_id') || 1;

    let serverRoles = [];
    let serverPermissions = [];

    rolesTabBtn?.addEventListener('click', loadRoles);
    membersTabBtn?.addEventListener('click', loadRoles); // Both tabs need roles data

    async function loadRoles() {
        try {
            const channelIdParam = window.activeChannelId ? `&channel_id=${window.activeChannelId}` : '';
            const resp = await fetch(`api_v1_roles.php?server_id=${activeServerId}${channelIdParam}`);
            const data = await resp.json();
            if (data.success) {
                serverRoles = data.roles;
                serverPermissions = data.permissions_list;
                if (rolesList) renderRoles(data.roles);
                if (membersList) renderMembers(data.members);
                // Use filtered members for sidebar, all members for colors
                updateGlobalUI(data.filtered_members || data.members, data.members);
            }
        } catch (e) { console.error(e); }
    }

    function renderRoleIconJS(icon, size = '14px') {
        if (!icon) return '';
        const isUrl = icon.startsWith('http') || icon.startsWith('/');
        if (isUrl) {
            return `<img src="${escapeHTML(icon)}" class="role-icon ms-1" style="width: ${size}; height: ${size}; vertical-align: middle; object-fit: contain;">`;
        } else if (icon.startsWith(':') && icon.endsWith(':')) {
            const ce = (window.CUSTOM_EMOTES_CACHE || []).find(e => e.code === icon);
            if (ce) {
                return `<img src="${ce.path}" class="role-icon ms-1" style="width: ${size}; height: ${size}; vertical-align: middle; object-fit: contain;">`;
            }
            return `<span class="ms-1" style="font-size: ${size}; vertical-align: middle;">${escapeHTML(icon)}</span>`;
        } else {
            return `<span class="ms-1" style="font-size: ${size}; vertical-align: middle;">${escapeHTML(icon)}</span>`;
        }
    }

    function updateGlobalUI(sidebarMembers, allMembers = null) {
        if (!allMembers) allMembers = sidebarMembers;
        // Update members sidebar
        const sidebar = document.querySelector('.members-sidebar');
        if (sidebar) {
            const countEl = sidebar.querySelector('div[style*="text-transform: uppercase"]');
            if (countEl) countEl.textContent = `Members — ${sidebarMembers.length}`;

            // We need to keep the "Members - X" div and replace everything else
            const header = sidebar.firstElementChild;
            sidebar.innerHTML = '';
            sidebar.appendChild(header);

            sidebarMembers.forEach(m => {
                const item = document.createElement('div');
                item.className = 'channel-item member-item';
                item.dataset.userId = m.id;
                item.dataset.username = m.username;
                item.dataset.avatar = m.avatar_url || '';
                item.dataset.roleIds = m.role_ids || '';
                item.style.color = 'var(--text-primary)';
                item.style.marginBottom = '8px';
                item.style.cursor = 'pointer';
                
                const roleIconHtml = renderRoleIconJS(m.role_icon, '14px');
                const avatarBg = m.avatar_url ? `background-image: url('${m.avatar_url}');` : '';
                const statusColor = m.status === 'online' ? '#23a559' : '#80848e';

                item.innerHTML = `
                    <div class="message-avatar" style="width: 32px; height: 32px; background-color: ${statusColor}; position: relative; ${avatarBg}">
                        ${m.status === 'online' ? `<div style="position: absolute; bottom: 0; right: 0; width: 10px; height: 10px; background-color: #23a559; border-radius: 50%; border: 2px solid var(--bg-members);"></div>` : ''}
                    </div>
                    <span style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; ${m.role_color ? `color: ${m.role_color};` : ''}">
                        ${escapeHTML(m.username)}
                        ${roleIconHtml}
                    </span>
                `;
                sidebar.appendChild(item);
            });
        }

        // Update chat colors
        document.querySelectorAll('.message-author').forEach(authorEl => {
            const username = authorEl.childNodes[0].textContent.trim();
            const member = allMembers.find(m => m.username === username);
            if (member) {
                authorEl.style.color = member.role_color || 'inherit';
                // Try to update icon if it exists or add it if it doesn't
                let iconEl = authorEl.querySelector('.role-icon, span.ms-1');
                const newIconHtml = renderRoleIconJS(member.role_icon, '14px');
                
                if (newIconHtml) {
                    if (iconEl) {
                        const temp = document.createElement('div');
                        temp.innerHTML = newIconHtml;
                        iconEl.replaceWith(temp.firstChild);
                    } else {
                        const temp = document.createElement('div');
                        temp.innerHTML = newIconHtml;
                        // Insert after the text node
                        authorEl.insertBefore(temp.firstChild, authorEl.childNodes[1]);
                    }
                } else if (iconEl) {
                    iconEl.remove();
                }
            }
        });
    }

    function renderRoles(roles) {
        rolesList.innerHTML = '';
        if (roles.length === 0) {
            rolesList.innerHTML = '<div class="text-center p-3 text-muted">No roles created yet.</div>';
        }
        roles.forEach(role => {
            const item = document.createElement('div');
            item.className = 'list-group-item bg-transparent text-white border-secondary d-flex justify-content-between align-items-center p-2 mb-1 rounded role-sortable-item';
            item.dataset.id = role.id;
            const roleIconHtml = renderRoleIconJS(role.icon_url, '14px');
            item.innerHTML = `
                <div class="d-flex align-items-center">
                    <div class="role-drag-handle me-3" style="cursor: grab; opacity: 0.5;">
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="8" y1="5" x2="8" y2="5.01"></line><line x1="16" y1="5" x2="16" y2="5.01"></line><line x1="8" y1="12" x2="8" y2="12.01"></line><line x1="16" y1="12" x2="16" y2="12.01"></line><line x1="8" y1="19" x2="8" y2="19.01"></line><line x1="16" y1="19" x2="16" y2="19.01"></line></svg>
                    </div>
                    <div style="width: 14px; height: 14px; border-radius: 50%; background-color: ${role.color}; margin-right: 12px; box-shadow: 0 0 5px ${role.color}88;"></div>
                    <span class="fw-medium">${role.name}</span>
                    ${roleIconHtml}
                </div>
                <div>
                    <button class="btn btn-sm btn-outline-light edit-role-btn-v2" data-id="${role.id}" data-name="${role.name}" data-color="${role.color}" data-perms="${role.permissions}" data-icon="${role.icon_url || ''}">Edit</button>
                    <button class="btn btn-sm btn-outline-danger delete-role-btn" data-id="${role.id}">×</button>
                </div>
            `;
            rolesList.appendChild(item);
        });

        // Initialize Sortable for roles
        if (typeof Sortable !== 'undefined' && rolesList) {
            new Sortable(rolesList, {
                animation: 150,
                handle: '.role-drag-handle',
                ghostClass: 'sortable-ghost',
                onEnd: () => saveRolePositions()
            });
        }
    }

    async function saveRolePositions() {
        const orders = [];
        const items = rolesList.querySelectorAll('.role-sortable-item');
        // Invert the order because we ORDER BY position DESC in SQL
        let position = items.length - 1;
        items.forEach(item => {
            orders.push({
                id: item.dataset.id,
                position: position--
            });
        });

        try {
            await fetch('api_v1_roles.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    action: 'reorder',
                    server_id: activeServerId,
                    orders: orders
                })
            });
        } catch (e) { console.error(e); }
    }

    function renderMembers(members) {
        membersList.innerHTML = '';
        members.forEach(member => {
            const item = document.createElement('div');
            item.className = 'list-group-item bg-transparent text-white border-secondary d-flex justify-content-between align-items-center p-2 mb-2 rounded bg-dark';
            
            const roleIconHtml = renderRoleIconJS(member.role_icon, '14px');

            item.innerHTML = `
                <div class="d-flex align-items-center flex-grow-1">
                    <div class="message-avatar me-2" style="width: 32px; height: 32px; ${member.avatar_url ? `background-image: url('${member.avatar_url}');` : ''}"></div>
                    <div class="flex-grow-1">
                        <div class="fw-bold small" style="color: ${member.role_color || 'inherit'}">
                            ${escapeHTML(member.username)}
                            ${roleIconHtml}
                        </div>
                        <div class="text-muted small">
                            ${member.role_names ? member.role_names.split(',').join(', ') : 'No roles'}
                        </div>
                    </div>
                </div>
                ${(window.isServerOwner || window.canManageServer) ? `
                <button class="btn btn-sm btn-outline-light edit-user-roles-settings-btn" data-id="${member.id}" data-username="${member.username}" data-avatar="${member.avatar_url || ''}">Roles</button>
                ` : ''}
            `;
            membersList.appendChild(item);
        });
    }

    // Add listener for the button in members list tab
    membersList?.addEventListener('click', (e) => {
        const btn = e.target.closest('.edit-user-roles-settings-btn');
        if (btn) {
            openEditUserRolesModal(btn.dataset.id, btn.dataset.username, btn.dataset.avatar);
        }
    });


    // Role Editing Modal Logic
    rolesList?.addEventListener('click', (e) => {
        if (e.target.classList.contains('edit-role-btn-v2')) {
            const role = e.target.dataset;
            document.getElementById('edit-role-id').value = role.id;
            document.getElementById('edit-role-name').value = role.name;
            document.getElementById('edit-role-color').value = role.color;
            document.getElementById('edit-role-icon').value = role.icon;
            document.getElementById('selected-role-emoji-preview').textContent = role.icon || '';
            
            const permsContainer = document.getElementById('role-permissions-checkboxes');
            permsContainer.innerHTML = '';
            const currentPerms = parseInt(role.perms);
            
            serverPermissions.forEach(p => {
                const isChecked = (currentPerms & p.value) === p.value;
                permsContainer.innerHTML += `
                    <div class="form-check mb-1">
                        <input class="form-check-input perm-check" type="checkbox" value="${p.value}" id="perm-${p.value}" ${isChecked ? 'checked' : ''}>
                        <label class="form-check-label text-white small" for="perm-${p.value}">${p.name}</label>
                    </div>
                `;
            });
            
            const modal = new bootstrap.Modal(document.getElementById('roleEditorModal'));
            modal.show();
        }
    });

    document.getElementById('save-role-btn')?.addEventListener('click', async (e) => {
        const btn = e.target;
        const originalText = btn.textContent;
        const id = document.getElementById('edit-role-id').value;
        const name = document.getElementById('edit-role-name').value;
        const color = document.getElementById('edit-role-color').value;
        const icon_url = document.getElementById('edit-role-icon').value;
        
        let permissions = 0;
        document.querySelectorAll('.perm-check:checked').forEach(cb => {
            permissions |= parseInt(cb.value);
        });
        
        try {
            const resp = await fetch('api_v1_roles.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ action: 'update', server_id: activeServerId, id, name, color, icon_url, permissions })
            });
            const data = await resp.json();
            if (data.success) {
                btn.textContent = 'Saved ✅';
                btn.classList.replace('btn-primary', 'btn-success');
                setTimeout(() => {
                    btn.textContent = originalText;
                    btn.classList.replace('btn-success', 'btn-primary');
                }, 2000);
                loadRoles();
            }
        } catch (e) { console.error(e); }
    });

    async function openEditUserRolesModal(userId, username, avatar) {
        const modal = document.getElementById('editUserRolesModal');
        document.getElementById('edit-user-roles-user-id').value = userId;
        document.getElementById('edit-user-roles-username').textContent = username;
        const avatarEl = document.getElementById('edit-user-roles-avatar');
        avatarEl.style.backgroundImage = avatar ? `url('${avatar}')` : 'none';
        
        const list = document.getElementById('user-roles-selection-list');
        list.innerHTML = '<div class="text-center p-3 text-muted">Loading roles...</div>';
        
        const bsModal = new bootstrap.Modal(modal);
        bsModal.show();

        try {
            // We need to fetch roles and the current user's roles
            // We can reuse loadRoles or make a specific call
            const resp = await fetch(`api_v1_roles.php?server_id=${activeServerId}`);
            const data = await resp.json();
            
            if (data.success) {
                const member = data.members.find(m => m.id == userId);
                const assignedRoles = member && member.role_ids ? member.role_ids.split(',') : [];
                
                list.innerHTML = '';
                // Sort roles by position descending for display
                data.roles.sort((a, b) => b.position - a.position).forEach(role => {
                    const isChecked = assignedRoles.includes(role.id.toString());
                    const item = document.createElement('div');
                    item.className = 'list-group-item bg-dark text-white border-secondary p-2 d-flex align-items-center';
                    item.innerHTML = `
                        <input class="form-check-input me-3 user-role-checkbox" type="checkbox" value="${role.id}" id="user-role-${role.id}" ${isChecked ? 'checked' : ''}>
                        <label class="form-check-label flex-grow-1" for="user-role-${role.id}" style="color: ${role.color}; cursor: pointer;">
                            ${role.name}
                        </label>
                    `;
                    list.appendChild(item);
                });
                
                if (data.roles.length === 0) {
                    list.innerHTML = '<div class="text-center p-3 text-muted">No roles defined for this server.</div>';
                }
            }
        } catch (e) { console.error(e); }
    }

    document.getElementById('save-user-roles-btn')?.addEventListener('click', async (e) => {
        const btn = e.target;
        const originalText = btn.textContent;
        const userId = document.getElementById('edit-user-roles-user-id').value;
        const roleIds = Array.from(document.querySelectorAll('.user-role-checkbox:checked')).map(cb => cb.value);
        
        try {
            const resp = await fetch('api_v1_roles.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    action: 'set_user_roles',
                    server_id: activeServerId,
                    user_id: userId,
                    role_ids: roleIds
                })
            });
            const data = await resp.json();
            if (data.success) {
                btn.textContent = 'Saved ✅';
                btn.classList.replace('btn-primary', 'btn-success');
                setTimeout(() => {
                    btn.textContent = originalText;
                    btn.classList.replace('btn-success', 'btn-primary');
                }, 2000);
                loadRoles();
            } else {
                alert(data.error || 'Failed to update roles');
            }
        } catch (e) { console.error(e); }
    });

    addRoleBtn?.addEventListener('click', async () => {
        const name = prompt('Role name:');
        if (!name) return;
        const color = '#99aab5';
        
        try {
            const resp = await fetch('api_v1_roles.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ action: 'create', server_id: activeServerId, name, color, permissions: 0 })
            });
            if ((await resp.json()).success) loadRoles();
        } catch (e) { console.error(e); }
    });

    rolesList?.addEventListener('click', async (e) => {
        if (e.target.classList.contains('delete-role-btn')) {
            if (!confirm('Delete this role?')) return;
            const roleId = e.target.dataset.id;
            const resp = await fetch('api_v1_roles.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ action: 'delete', server_id: activeServerId, id: roleId })
            });
            if ((await resp.json()).success) loadRoles();
        }
    });

    // Webhooks Management
    const webhooksTabBtn = document.getElementById('webhooks-tab-btn');
    const webhooksList = document.getElementById('webhooks-list');
    const addWebhookBtn = document.getElementById('add-webhook-btn');

    webhooksTabBtn?.addEventListener('click', loadWebhooks);

    async function loadWebhooks() {
        webhooksList.innerHTML = '<div class="text-center p-3 text-muted">Loading webhooks...</div>';
        try {
            const resp = await fetch(`api_v1_webhook.php?server_id=${activeServerId}`);
            const data = await resp.json();
            if (data.success) {
                renderWebhooks(data.webhooks);
            }
        } catch (e) { console.error(e); }
    }

    function renderWebhooks(webhooks) {
        webhooksList.innerHTML = '';
        if (webhooks.length === 0) {
            webhooksList.innerHTML = '<div class="text-center p-3 text-muted">No webhooks found.</div>';
            return;
        }
        webhooks.forEach(wh => {
            const item = document.createElement('div');
            item.className = 'list-group-item bg-transparent text-white border-secondary p-2 mb-2';
            const url = `${window.location.origin}/api_v1_webhook.php?token=${wh.token}`;
            item.innerHTML = `
                <div class="d-flex justify-content-between align-items-center mb-1">
                    <span class="fw-bold">${wh.name}</span>
                    <button class="btn btn-sm btn-outline-danger delete-webhook-btn" data-id="${wh.id}">×</button>
                </div>
                <div class="small text-muted mb-2">Channel: #${wh.channel_name}</div>
                <div class="input-group input-group-sm">
                    <input type="text" class="form-control bg-dark text-white border-secondary" value="${url}" readonly>
                    <button class="btn btn-outline-secondary" type="button" onclick="navigator.clipboard.writeText('${url}')">Copy</button>
                </div>
            `;
            webhooksList.appendChild(item);
        });
    }

    addWebhookBtn?.addEventListener('click', async () => {
        const name = prompt('Webhook name:', 'Bot Name');
        if (!name) return;
        
        // Fetch channels for this server to let user pick one
        const respChannels = await fetch(`api_v1_channels.php?server_id=${activeServerId}`);
        const dataChannels = await respChannels.json();
        if (!dataChannels.length) return alert('Create a channel first.');
        
        const channelId = prompt('Enter Channel ID:\n' + dataChannels.map(c => `${c.id}: #${c.name}`).join('\n'));
        if (!channelId) return;

        try {
            const resp = await fetch('api_v1_webhook.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ channel_id: channelId, name: name })
            });
            if ((await resp.json()).success) loadWebhooks();
        } catch (e) { console.error(e); }
    });

    webhooksList?.addEventListener('click', async (e) => {
        if (e.target.classList.contains('delete-webhook-btn')) {
            if (!confirm('Delete this webhook?')) return;
            const whId = e.target.dataset.id;
            const resp = await fetch('api_v1_webhook.php', {
                method: 'DELETE',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ id: whId })
            });
            if ((await resp.json()).success) loadWebhooks();
        }
    });

    // Stats Management
    const statsTabBtn = document.getElementById('stats-tab-btn');
    statsTabBtn?.addEventListener('click', loadStats);

    async function loadStats() {
        try {
            const resp = await fetch(`api_v1_stats.php?server_id=${activeServerId}`);
            const data = await resp.json();
            if (data.success) {
                document.getElementById('stat-members').textContent = data.stats.total_members;
                document.getElementById('stat-messages').textContent = data.stats.total_messages;
                
                const topUsersList = document.getElementById('top-users-list');
                topUsersList.innerHTML = '';
                data.stats.top_users.forEach(user => {
                    const item = document.createElement('div');
                    item.className = 'd-flex justify-content-between align-items-center mb-1 p-2 bg-dark rounded';
                    item.innerHTML = `<span>${user.username}</span><span class="badge bg-primary">${user.message_count} msgs</span>`;
                    topUsersList.appendChild(item);
                });

                const activity = document.getElementById('activity-chart-placeholder');
                activity.innerHTML = '';
                data.stats.history.forEach(day => {
                    const bar = document.createElement('div');
                    bar.className = 'd-flex align-items-center mb-1';
                    const percent = Math.min(100, (day.count / 100) * 100); // Normalize to 100 for visual
                    bar.innerHTML = `
                        <div style="width: 80px;" class="small">${day.date}</div>
                        <div class="flex-grow-1 mx-2" style="height: 10px; background: var(--separator); border-radius: 5px;">
                            <div style="width: ${percent}%; height: 100%; background: var(--blurple); border-radius: 5px;"></div>
                        </div>
                        <div style="width: 30px;" class="small text-end">${day.count}</div>
                    `;
                    activity.appendChild(bar);
                });
                if (data.stats.history.length === 0) {
                    activity.innerHTML = '<div class="text-muted">No activity in the last 7 days.</div>';
                }
            }
        } catch (e) { console.error(e); }
    }

    // Server Settings
    const searchServerIconBtn = document.getElementById('search-server-icon-btn');
    const serverIconResults = document.getElementById('server-icon-search-results');
    const serverIconPreview = document.getElementById('server-icon-preview');
    const serverIconUrlInput = document.getElementById('server-icon-url');

    searchServerIconBtn?.addEventListener('click', async () => {
        const query = prompt('Search for a server icon:', 'abstract');
        if (!query) return;
        
        serverIconResults.innerHTML = '<div class="text-muted small">Searching...</div>';
        try {
            const resp = await fetch(`api/pexels.php?action=search&query=${encodeURIComponent(query)}`);
            const data = await resp.json();
            serverIconResults.innerHTML = '';
            data.forEach(photo => {
                const img = document.createElement('img');
                img.src = photo.url;
                img.className = 'avatar-pick';
                img.style.width = '50px';
                img.style.height = '50px';
                img.onclick = () => {
                    serverIconUrlInput.value = photo.url;
                    serverIconPreview.style.backgroundImage = `url('${photo.url}')`;
                    serverIconResults.innerHTML = '';
                };
                serverIconResults.appendChild(img);
            });
        } catch (e) {
            serverIconResults.innerHTML = '<div class="text-danger small">Error fetching icons</div>';
        }
    });

    // Forum: New Thread
    const newThreadBtn = document.getElementById('new-thread-btn');
    const newThreadModal = document.getElementById('newThreadModal') ? new bootstrap.Modal(document.getElementById('newThreadModal')) : null;
    let selectedTagIds = [];

    newThreadBtn?.addEventListener('click', async () => {
        if (!newThreadModal) return;
        
        // Load tags for this channel
        const tagsList = document.getElementById('new-thread-tags-list');
        tagsList.innerHTML = '<div class="text-muted small">Loading tags...</div>';
        selectedTagIds = [];
        
        try {
            const resp = await fetch(`api_v1_tags.php?channel_id=${currentChannel}`);
            const data = await resp.json();
            tagsList.innerHTML = '';
            if (data.success && data.tags.length > 0) {
                data.tags.forEach(tag => {
                    const span = document.createElement('span');
                    span.className = 'badge rounded-pill p-2 border border-secondary';
                    span.style.cursor = 'pointer';
                    span.style.backgroundColor = 'transparent';
                    span.dataset.id = tag.id;
                    span.dataset.color = tag.color;
                    span.textContent = tag.name;
                    span.onclick = () => {
                        if (selectedTagIds.includes(tag.id)) {
                            selectedTagIds = selectedTagIds.filter(id => id !== tag.id);
                            span.style.backgroundColor = 'transparent';
                        } else {
                            selectedTagIds.push(tag.id);
                            span.style.backgroundColor = tag.color;
                        }
                    };
                    tagsList.appendChild(span);
                });
            } else {
                tagsList.innerHTML = '<div class="text-muted small">No tags available.</div>';
            }
        } catch (e) { console.error(e); }
        
        newThreadModal.show();
    });

    document.getElementById('submit-new-thread-btn')?.addEventListener('click', async () => {
        const title = document.getElementById('new-thread-title').value.trim();
        if (!title) return;
        
        try {
            const formData = new FormData();
            formData.append('channel_id', currentChannel);
            formData.append('title', title);
            formData.append('tag_ids', selectedTagIds.join(','));
            const resp = await fetch('api_v1_threads.php', { method: 'POST', body: formData });
            const result = await resp.json();
            if (result.success) {
                window.location.href = `?server_id=${activeServerId}&channel_id=${currentChannel}&thread_id=${result.thread_id}`;
            } else {
                alert(result.error || 'Failed to create thread');
            }
        } catch (e) { console.error(e); }
    });

    // Forum: Mark as Solution
    document.addEventListener('click', async (e) => {
        const solBtn = e.target.closest('.action-btn.mark-solution');
        if (solBtn) {
            const threadId = solBtn.dataset.threadId;
            const messageId = solBtn.classList.contains('active') ? null : solBtn.dataset.messageId;
            
            try {
                const resp = await fetch('api_v1_threads.php?action=solve', {
                    method: 'PATCH',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ thread_id: threadId, message_id: messageId })
                });
                const result = await resp.json();
                if (result.success) {
                    location.reload();
                } else {
                    alert(result.error || 'Failed to update solution');
                }
            } catch (e) { console.error(e); }
        }
    });

    // Forum: Manage Tags
    const manageTagsBtn = document.getElementById('manage-tags-btn');
    const manageTagsModal = document.getElementById('manageTagsModal') ? new bootstrap.Modal(document.getElementById('manageTagsModal')) : null;

    manageTagsBtn?.addEventListener('click', async () => {
        if (!manageTagsModal) return;
        loadForumAdminTags();
        manageTagsModal.show();
    });

    async function loadForumAdminTags() {
        const list = document.getElementById('forum-tags-admin-list');
        list.innerHTML = '<div class="text-center p-3 text-muted small">Loading tags...</div>';
        try {
            const resp = await fetch(`api_v1_tags.php?channel_id=${currentChannel}`);
            const data = await resp.json();
            list.innerHTML = '';
            if (data.success && data.tags.length > 0) {
                data.tags.forEach(tag => {
                    const div = document.createElement('div');
                    div.className = 'd-flex justify-content-between align-items-center mb-2 p-2 bg-dark rounded';
                    div.innerHTML = `
                        <div class="d-flex align-items-center">
                            <div style="width: 14px; height: 14px; border-radius: 50%; background-color: ${tag.color}; margin-right: 8px;"></div>
                            <span>${tag.name}</span>
                        </div>
                        <button class="btn btn-sm text-danger delete-forum-tag-btn" data-id="${tag.id}">×</button>
                    `;
                    list.appendChild(div);
                });
            } else {
                list.innerHTML = '<div class="text-center p-3 text-muted small">No tags created yet.</div>';
            }
        } catch (e) { console.error(e); }
    }

    document.getElementById('add-forum-tag-btn')?.addEventListener('click', async () => {
        const name = document.getElementById('new-tag-name').value.trim();
        const color = document.getElementById('new-tag-color').value;
        if (!name) return;
        
        try {
            const resp = await fetch('api_v1_tags.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ action: 'create', channel_id: currentChannel, name, color })
            });
            if ((await resp.json()).success) {
                document.getElementById('new-tag-name').value = '';
                loadForumAdminTags();
            }
        } catch (e) { console.error(e); }
    });

    document.getElementById('forum-tags-admin-list')?.addEventListener('click', async (e) => {
        if (e.target.classList.contains('delete-forum-tag-btn')) {
            const tagId = e.target.dataset.id;
            try {
                const resp = await fetch('api_v1_tags.php', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ action: 'delete', channel_id: currentChannel, tag_id: tagId })
                });
                if ((await resp.json()).success) loadForumAdminTags();
            } catch (e) { console.error(e); }
        }
    });

    // Rules: Add Rule
    const addRuleBtn = document.getElementById('add-rule-btn');
    const addRuleForm = document.getElementById('add-rule-form');
    const newRuleContent = document.getElementById('new-rule-content');
    const saveNewRuleBtn = document.getElementById('save-new-rule-btn');
    const cancelNewRuleBtn = document.getElementById('cancel-new-rule-btn');

    addRuleBtn?.addEventListener('click', () => {
        addRuleBtn.style.display = 'none';
        addRuleForm.style.display = 'block';
        newRuleContent.focus();
    });

    cancelNewRuleBtn?.addEventListener('click', () => {
        addRuleBtn.style.display = 'block';
        addRuleForm.style.display = 'none';
        newRuleContent.value = '';
    });

    saveNewRuleBtn?.addEventListener('click', async () => {
        const content = newRuleContent.value.trim();
        if (!content) return;
        
        try {
            const formData = new FormData();
            formData.append('channel_id', currentChannel);
            formData.append('content', content);
            const resp = await fetch('api_v1_rules.php', { method: 'POST', body: formData });
            const result = await resp.json();
            if (result.success) {
                location.reload();
            } else {
                alert(result.error || 'Failed to add rule');
            }
        } catch (e) { console.error(e); }
    });

    const rulesListSortable = document.getElementById('rules-list-sortable');
    if (typeof Sortable !== 'undefined' && rulesListSortable && window.canManageChannels) {
        new Sortable(rulesListSortable, {
            animation: 150,
            ghostClass: 'sortable-ghost',
            onEnd: async () => {
                const order = Array.from(rulesListSortable.querySelectorAll('.rule-item')).map(el => el.dataset.id);
                // Update numbers in UI
                rulesListSortable.querySelectorAll('.rule-item').forEach((item, index) => {
                    const numEl = item.querySelector('.rule-number');
                    if (numEl) numEl.textContent = `${index + 1}.`;
                });
                
                await fetch('api_v1_rules.php', {
                    method: 'PATCH',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ order: order })
                });
            }
        });
    }

    // Rules: Delete/Edit
    document.addEventListener('click', async (e) => {
        if (e.target.classList.contains('delete-rule-btn')) {
            if (!confirm('Delete this rule?')) return;
            const id = e.target.dataset.id;
            const resp = await fetch(`api_v1_rules.php?id=${id}`, { method: 'DELETE' });
            if ((await resp.json()).success) location.reload();
        }
        if (e.target.classList.contains('edit-rule-btn')) {
            const id = e.target.dataset.id;
            const oldContent = e.target.closest('.rule-item').querySelector('.rule-content').innerText;
            const newContent = prompt('Edit Rule:', oldContent);
            if (!newContent || newContent === oldContent) return;
            
            const resp = await fetch('api_v1_rules.php', {
                method: 'PUT',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ id, content: newContent })
            });
            if ((await resp.json()).success) location.reload();
        }
    });

    // Rules Acceptance
    document.getElementById('accept-rules-btn')?.addEventListener('click', async () => {
        const btn = document.getElementById('accept-rules-btn');
        btn.disabled = true;
        btn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span> Traitement...';
        
        try {
            const resp = await fetch('api_v1_accept_rules.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ channel_id: window.activeChannelId })
            });
            const data = await resp.json();
            if (data.success) {
                const container = document.getElementById('rules-acceptance-container');
                container.innerHTML = '<div class="alert alert-success d-inline-block"><i class="fa-solid fa-check-circle me-2"></i> Vous avez accepté les règles.</div>';
                // Reload roles in members list if possible, or just reload page
                setTimeout(() => location.reload(), 1500);
            } else {
                alert(data.error || 'Erreur lors de l\'acceptation');
                btn.disabled = false;
                btn.innerHTML = '<i class="fa-solid fa-check me-2"></i> J\'accepte les règles';
            }
        } catch (e) {
            console.error(e);
            btn.disabled = false;
            btn.innerHTML = '<i class="fa-solid fa-check me-2"></i> J\'accepte les règles';
        }
    });

    document.getElementById('withdraw-rules-btn')?.addEventListener('click', async () => {
        if (!confirm('Êtes-vous sûr de vouloir retirer votre acceptation des règles ? Vous perdrez le rôle associé.')) return;
        
        const btn = document.getElementById('withdraw-rules-btn');
        btn.disabled = true;
        btn.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span> Traitement...';
        
        try {
            const resp = await fetch('api_v1_withdraw_rules.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ channel_id: window.activeChannelId })
            });
            const data = await resp.json();
            if (data.success) {
                location.reload();
            } else {
                alert(data.error || 'Erreur lors du retrait');
                btn.disabled = false;
                btn.innerHTML = '<i class="fa-solid fa-undo me-1"></i> Retirer mon acceptation';
            }
        } catch (e) {
            console.error(e);
            btn.disabled = false;
            btn.innerHTML = '<i class="fa-solid fa-undo me-1"></i> Retirer mon acceptation';
        }
    });

    // Channel Selection Type
    const addChannelBtns = document.querySelectorAll('.add-channel-btn');
    addChannelBtns.forEach(btn => {
        btn.addEventListener('click', () => {
            const type = btn.dataset.type;
            const select = document.getElementById('add-channel-type'); // Corrected ID from index.php
            if (select) {
                select.value = type === 'voice' ? 'voice' : (type || 'chat');
                // Trigger change to update visibility
                select.dispatchEvent(new Event('change'));
            }
        });
    });

    const addChannelTypeSelect = document.getElementById('add-channel-type');
    addChannelTypeSelect?.addEventListener('change', (e) => {
        const type = e.target.value;
        const container = document.getElementById('add-channel-rules-role-container');
        if (container) {
            container.style.display = (type === 'rules') ? 'block' : 'none';
        }
        const limitContainer = document.getElementById('add-channel-limit-container');
        const filesContainer = document.getElementById('add-channel-files-container');
        if (limitContainer) limitContainer.style.display = (type === 'rules' || type === 'autorole') ? 'none' : 'block';
        if (filesContainer) filesContainer.style.display = (type === 'rules' || type === 'autorole') ? 'none' : 'block';
    });

    // User Settings - Avatar Search
    // User Settings - Save logic removed and moved to index.php for reliability

    const avatarSearchBtn = document.getElementById('search-avatar-btn');
    const avatarSearchQuery = document.getElementById('avatar-search-query');
    const avatarResults = document.getElementById('avatar-results');
    const avatarPreview = document.getElementById('settings-avatar-preview');
    const avatarUrlInput = document.getElementById('settings-avatar-url');

    avatarSearchBtn?.addEventListener('click', async () => {
        const q = avatarSearchQuery.value.trim();
        if (!q) return;
        avatarResults.innerHTML = '<div class="text-muted small">Searching...</div>';
        try {
            const resp = await fetch(`api/pexels.php?action=search&query=${encodeURIComponent(q)}`);
            const data = await resp.json();
            avatarResults.innerHTML = '';
            data.forEach(photo => {
                const img = document.createElement('img');
                img.src = photo.url;
                img.className = 'avatar-pick';
                img.style.width = '60px';
                img.style.height = '60px';
                img.style.cursor = 'pointer';
                img.onclick = () => {
                    avatarUrlInput.value = photo.url;
                    avatarPreview.style.backgroundImage = `url('${photo.url}')`;
                };
                avatarResults.appendChild(img);
            });
        } catch (e) { console.error(e); }
    });

    // Theme preview
    document.querySelectorAll('input[name="theme"]').forEach(radio => {
        radio.addEventListener('change', (e) => {
            document.body.setAttribute('data-theme', e.target.value);
        });
    });

    // Toggle members sidebar
    const toggleMembersBtn = document.getElementById('toggle-members-btn');
    const membersSidebar = document.querySelector('.members-sidebar');
    if (toggleMembersBtn && membersSidebar) {
        toggleMembersBtn.addEventListener('click', () => {
            if (window.innerWidth > 992) {
                membersSidebar.classList.toggle('hidden');
            } else {
                membersSidebar.classList.toggle('show');
            }
        });
    }

    // User Settings - Save handled in index.php

    function escapeHTML(str) {
        const div = document.createElement('div');
        div.textContent = str;
        return div.innerHTML;
    }

    function parseCustomEmotes(text) {
        let parsed = escapeHTML(text);
        (window.CUSTOM_EMOTES_CACHE || []).forEach(emote => {
            const imgHtml = `<img src="${emote.path}" alt="${emote.name}" title="${emote.code}" style="width: 24px; height: 24px; vertical-align: middle; object-fit: contain;">`;
            parsed = parsed.split(emote.code).join(imgHtml);
        });
        return parsed;
    }

    function appendMessage(msg) {
        if (!msg || !msg.id) return;
        if (document.querySelector(`.message-item[data-id="${msg.id}"]`)) return;

        // Auto-populate metadata for video platforms if missing
        const dmRegexForMeta = /(?:https?:\/\/)?(?:www\.)?(?:dailymotion\.com\/video\/|dai\.ly\/)([a-zA-Z0-9]+)/;
        const dmMatchForMeta = msg.content.match(dmRegexForMeta);
        if (dmMatchForMeta && !msg.metadata) {
            msg.metadata = {
                title: 'Dailymotion Video',
                url: dmMatchForMeta[0],
                image: `https://www.dailymotion.com/thumbnail/video/${dmMatchForMeta[1]}`,
                site_name: 'Dailymotion'
            };
        }

        const messagesList = document.getElementById('messages-list');
        const div = document.createElement('div');
        div.className = 'message-item';
        div.dataset.id = msg.id;

        if (parseInt(msg.id) > lastMessageId) {
            lastMessageId = parseInt(msg.id);
        }
        const avatarStyle = msg.avatar_url ? `background-image: url('${msg.avatar_url}');` : '';
        
        let attachmentHtml = '';
        if (msg.attachment_url) {
            const ext = msg.attachment_url.split('.').pop().toLowerCase();
            if (['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(ext)) {
                attachmentHtml = `<div class="message-attachment mt-2"><img src="${msg.attachment_url}" class="img-fluid rounded message-img-preview" alt="Attachment" style="max-height: 300px; cursor: pointer;" onclick="window.open(this.src)"></div>`;
            } else {
                attachmentHtml = `<div class="message-attachment mt-2"><a href="${msg.attachment_url}" target="_blank" class="attachment-link d-inline-flex align-items-center p-2 rounded bg-dark text-white text-decoration-none"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="me-2"><path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path><polyline points="13 2 13 9 20 9"></polyline></svg>${msg.attachment_url.split('/').pop()}</a></div>`;
            }
        }

        let embedHtml = '';
        if (msg.metadata) {
            const meta = typeof msg.metadata === 'string' ? JSON.parse(msg.metadata) : msg.metadata;
            embedHtml = `
                <div class="rich-embed mt-2 p-3 rounded" style="background: rgba(0,0,0,0.1); border-left: 4px solid var(--blurple); max-width: 520px;">
                    ${meta.site_name ? `<div class="embed-site-name mb-1" style="font-size: 0.75em; color: var(--text-muted); text-transform: uppercase; font-weight: bold;">${escapeHTML(meta.site_name)}</div>` : ''}
                    ${meta.title ? `<a href="${meta.url}" target="_blank" class="embed-title d-block mb-1 text-decoration-none" style="font-weight: 600; color: #00a8fc;">${escapeHTML(meta.title)}</a>` : ''}
                    ${meta.description ? `<div class="embed-description mb-2" style="font-size: 0.9em; color: var(--text-normal);">${escapeHTML(meta.description)}</div>` : ''}
                    ${meta.image ? `<div class="embed-image"><img src="${meta.image}" class="rounded" style="max-width: 100%; max-height: 300px; object-fit: contain;"></div>` : ''}
                </div>
            `;
        }

        const isMe = msg.user_id == window.currentUserId || msg.username == window.currentUsername;
        const hasManageRights = window.canManageChannels || window.isServerOwner || false;

        const pinHtml = `
            <span class="action-btn pin ${msg.is_pinned ? 'active' : ''}" title="${msg.is_pinned ? 'Unpin' : 'Pin'}" data-id="${msg.id}" data-pinned="${msg.is_pinned ? '1' : '0'}">
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path><circle cx="12" cy="10" r="3"></circle></svg>
            </span>
        `;

        const actionsHtml = (isMe || hasManageRights) ? `
            <div class="message-actions-menu">
                ${pinHtml}
                ${isMe ? `
                    <span class="action-btn edit" title="Edit" data-id="${msg.id}">
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>
                    </span>
                    <span class="action-btn delete" title="Delete" data-id="${msg.id}">
                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"></polyline><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg>
                    </span>
                ` : ''}
            </div>
        ` : '';

        const pinnedBadge = msg.is_pinned ? `
            <span class="pinned-badge ms-2" title="Pinned Message">
                <svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path></svg>
                Pinned
            </span>
        ` : '';

        const mentionRegex = new RegExp(`@${window.currentUsername}\\b`, 'g');
        const mentionHtml = `<span class="mention">@${window.currentUsername}</span>`;
        const contentWithMentions = parseCustomEmotes(msg.content).replace(mentionRegex, mentionHtml);

        div.innerHTML = `
            <div class="message-avatar" style="${avatarStyle}"></div>
            <div class="message-content">
                <div class="message-header">
                    <span class="message-username" style="color: ${msg.role_color || 'inherit'};">
                        ${escapeHTML(msg.username)}
                        ${renderRoleIconJS(msg.role_icon, '14px')}
                    </span>
                    <span class="message-timestamp">${msg.timestamp || 'Just now'}</span>
                    ${pinnedBadge}
                </div>
                <div class="message-text">${contentWithMentions.replace(/\n/g, '<br>')}</div>
                ${attachmentHtml}
                ${embedHtml}
                <div class="message-reactions mt-1" data-message-id="${msg.id}"></div>
            </div>
            ${actionsHtml}
            <div class="message-reaction-picker-anchor"></div>
        `;
        messagesList.appendChild(div);
        scrollToBottom(isMe);

        // Ensure we scroll again when images/videos load
        div.querySelectorAll('img, iframe').forEach(el => {
            el.addEventListener('load', () => scrollToBottom(isMe));
        });
    }

    // Initial load of roles for the server
    loadRoles();

    // Autorole Toggle
    document.addEventListener('click', async (e) => {
        const btn = e.target.closest('.autorole-toggle-btn');
        if (!btn) return;

        const roleId = btn.dataset.roleId;
        
        btn.disabled = true;
        
        try {
            const resp = await fetch('api_v1_autoroles.php', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ action: 'toggle', role_id: roleId })
            });
            const data = await resp.json();
            if (data.success) {
                if (data.added) {
                    btn.classList.remove('btn-outline-secondary');
                    btn.classList.add('btn-primary');
                    btn.style.backgroundColor = 'var(--blurple)';
                    btn.style.border = 'none';
                } else {
                    btn.classList.add('btn-outline-secondary');
                    btn.classList.remove('btn-primary');
                    btn.style.backgroundColor = 'var(--bg-channels)';
                    btn.style.border = '1px solid var(--separator)';
                }
                
                // Refresh sidebar channels and members
                if (typeof loadRoles === 'function') loadRoles();
                
                fetch(window.location.href)
                    .then(resp => resp.text())
                    .then(html => {
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(html, 'text/html');
                        const newSidebar = doc.getElementById('sidebar-channels-list');
                        const currentSidebar = document.getElementById('sidebar-channels-list');
                        if (newSidebar && currentSidebar) {
                            currentSidebar.innerHTML = newSidebar.innerHTML;
                            if (window.restoreCollapsedStates) window.restoreCollapsedStates();
                        }
                    })
                    .catch(err => console.error('Error refreshing sidebar:', err));
            } else {
                alert(data.error || 'Failed to toggle role');
            }
        } catch (e) {
            console.error(e);
        } finally {
            btn.disabled = false;
        }
    });

    // Category Collapsible Logic
    document.addEventListener('click', (e) => {
        const categoryHeader = e.target.closest('.channel-category');
        if (categoryHeader) {
            // Check if we didn't click on a settings button or add button
            if (e.target.closest('.channel-settings-btn') || e.target.closest('.add-channel-btn')) {
                return;
            }
            const wrapper = categoryHeader.closest('.category-wrapper');
            if (wrapper) {
                wrapper.classList.toggle('collapsed');
                // Persist state in localStorage
                const categoryId = wrapper.dataset.id;
                const collapsedStates = JSON.parse(localStorage.getItem('categoryCollapsedStates') || '{}');
                collapsedStates[categoryId] = wrapper.classList.contains('collapsed');
                localStorage.setItem('categoryCollapsedStates', JSON.stringify(collapsedStates));
            }
        }
    });

    // Restore collapsed states
    window.restoreCollapsedStates = () => {
        const collapsedStates = JSON.parse(localStorage.getItem('categoryCollapsedStates') || '{}');
        Object.entries(collapsedStates).forEach(([id, isCollapsed]) => {
            if (isCollapsed) {
                const wrapper = document.querySelector(`.category-wrapper[data-id="${id}"]`);
                if (wrapper) {
                    wrapper.classList.add('collapsed');
                }
            }
        });
    };
    restoreCollapsedStates();

});
