const RoomsApp = (function() {
    let ws = null;
    let currentRoomId = null;
    let currentUserId = null;
    let currentUsername = null;
    let isHost = false;
    let isGuest = false;
    let selectedAnimeData = null;
    let currentLoadedUrl = null;
    let extensionsReady = false;
    let currentAnimeDetails = null;
    let selectedEpisodes = new Set([1]);
    let lastSelectedEp = 1;
    let modalCurrentPage = 1;
    let modalTotalEpisodes = 0;
    const MODAL_EPS_PER_PAGE = 50;
    let currentQueue = [];
    let shouldReconnect = true;

    let configState = {
        extension: null,
        server: null,
        category: 'sub',
        episode: 1
    };

    let activeContext = {
        extension: null,
        server: null,
        category: 'sub',
        episode: 1
    };

    let extensionsStore = {
        list: [],
        settings: {}
    };

    const elements = {
        // Main view & Header
        roomView: document.getElementById('room-view'),
        roomName: document.getElementById('room-name'),
        roomViewers: document.getElementById('room-viewers'),
        selectAnimeBtn: document.getElementById('select-anime-btn'),
        toggleChatBtn: document.getElementById('toggle-chat-btn'),
        copyInviteBtn: document.getElementById('copy-invite-btn'), // NUEVO

        // Host Quick Controls (Header)
        hostControls: document.getElementById('host-controls'),
        roomExtSelect: document.getElementById('room-ext-select'),
        roomServerSelect: document.getElementById('room-server-select'),
        roomSdToggle: document.getElementById('room-sd-toggle'),

        // Info Display
        npInfo: document.getElementById('now-playing-info'),
        npTitle: document.getElementById('np-title'),
        npEpisode: document.getElementById('np-episode'),

        // Player elements
        video: document.getElementById('player'),
        loading: document.getElementById('player-loading'),
        playBtn: document.getElementById('play-pause-btn'),
        timeDisplay: document.getElementById('time-display'),
        progressContainer: document.querySelector('.progress-container'),
        progressPlayed: document.querySelector('.progress-played'),
        progressHandle: document.querySelector('.progress-handle'),
        fullscreenBtn: document.getElementById('fullscreen-btn'),
        subtitlesCanvas: document.getElementById('subtitles-canvas'),

        // Chat
        usersList: document.getElementById('users-list'),
        toggleUsersBtn: document.getElementById('toggle-users-btn'),
        chatMessages: document.getElementById('chat-messages'),
        chatForm: document.getElementById('chat-form'),
        chatInput: document.getElementById('chat-input'),
        roomLayout: document.getElementById('room-layout'),

        // Join Room Modal Elements
        joinRoomModal: document.getElementById('join-room-modal'),
        joinRoomForm: document.getElementById('join-room-form'),
        guestNameInput: document.getElementById('guest-name-input'),
        joinPasswordInput: document.getElementById('join-password-input'),
        passwordGroup: document.getElementById('password-group'),
        cancelJoinBtn: document.getElementById('cancel-join-btn'),
        joinHostInfo: document.getElementById('join-host-info'),
        joinHostAvatar: document.getElementById('join-host-avatar'),
        joinHostText: document.getElementById('join-host-text'),

        // Anime Search Modal
        animeSearchModal: document.getElementById('anime-search-modal'),
        animeSearchInput: document.getElementById('anime-search-input'),
        animeResults: document.getElementById('anime-results'),
        closeSearchBtn: document.getElementById('close-search-modal'),
        animeSearchBtn: document.getElementById('anime-search-btn'),

        // Config Elements (Stream Configuration Modal)
        stepSearch: document.getElementById('step-search'),
        stepConfig: document.getElementById('step-config'),
        backToSearchBtn: document.getElementById('back-to-search'),
        configTitle: document.getElementById('selected-anime-title'),
        configCover: document.getElementById('config-cover'),

        // Selects del Modal (Legacy/Manual)
        selExtension: document.getElementById('sel-extension'),
        selServer: document.getElementById('sel-server'),
        selCategory: document.getElementById('sel-category'),

        // Controles de Configuración
        extContainer: document.getElementById('ext-chips-container'),
        serverContainer: document.getElementById('server-chips-container'),
        modalSdToggle: document.getElementById('modal-sd-toggle'),

        // Episode Controls
        inpEpisode: document.getElementById('inp-episode'),
        epInc: document.getElementById('ep-inc'),
        epDec: document.getElementById('ep-dec'),

        // Launch Actions
        btnLaunch: document.getElementById('btn-launch-stream'),
        configError: document.getElementById('config-error'),
        btnAddQueue: document.getElementById('btn-add-queue'),

        // Toasts & Tabs
        toastContainer: document.getElementById('video-toast-container'),
        tabChatBtn: document.getElementById('tab-chat-btn'),
        tabQueueBtn: document.getElementById('tab-queue-btn'),
        tabContentChat: document.getElementById('tab-content-chat'),
        tabContentQueue: document.getElementById('tab-content-queue'),
        queueList: document.getElementById('queue-list'),
        queueCount: document.getElementById('queue-count'),
    };

    async function init() {
        const params = new URLSearchParams(window.location.search);
        const urlRoomId = params.get('id');
        if (!urlRoomId) {
            window.location.href = '/anime';
            return;
        }

        currentRoomId = urlRoomId;

        if (window.AnimePlayer) {
            window.AnimePlayer.init(null, 'anilist', false, {}, true);
        }

        setupEventListeners();
        await preloadExtensions();

        try {
            const res = await fetch(`/api/rooms/${currentRoomId}`);
            if (!res.ok) throw new Error('Room not found');
            const data = await res.json();
            handleInitialEntry(data.room);
        } catch (e) {
            console.error(e);
            alert("Room not found or deleted");
        }
    }

    function handleInitialEntry(roomInfo) {
        const token = localStorage.getItem('token');
        const passwordGroup = document.getElementById('password-group');
        const guestNameInput = document.getElementById('guest-name-input');

        const hostInfoDiv = document.getElementById('join-host-info');
        const hostAvatar = document.getElementById('join-host-avatar');
        const hostText = document.getElementById('join-host-text');

        if (hostInfoDiv && roomInfo.host) {
            hostInfoDiv.style.display = 'flex';
            hostAvatar.src = roomInfo.host.avatar || '/public/assets/placeholder.png';
            hostText.innerHTML = `<span>${escapeHtml(roomInfo.host.username)}</span> invited you to watch`;
        }

        if (passwordGroup) {
            passwordGroup.style.display = roomInfo.hasPassword ? 'block' : 'none';
            passwordGroup.dataset.required = roomInfo.hasPassword ? 'true' : 'false';
        }

        if (token && guestNameInput) {
            const parentGroup = guestNameInput.closest('.form-group') || guestNameInput;
            parentGroup.style.display = 'none';
        } else if (guestNameInput) {
            const parentGroup = guestNameInput.closest('.form-group') || guestNameInput;
            parentGroup.style.display = 'block';
        }

        window.__roomPublicUrl = roomInfo.publicUrl || null;
        window.__roomExposed = roomInfo.exposed || false;
        if (token) {
            connectToRoom(currentRoomId);
        } else {
            if (elements.joinRoomModal) {
                elements.joinRoomModal.classList.add('show');

                if (roomInfo.hasPassword) {
                    setTimeout(() => {
                        const passInput = document.getElementById('join-password-input');
                        if(passInput) passInput.focus();
                    }, 100);
                } else {
                    setTimeout(() => {
                        if(guestNameInput) guestNameInput.focus();
                    }, 100);
                }
            }
        }
    }

    async function preloadExtensions() {
        const res = await fetch('/api/extensions/anime');
        const data = await res.json();

        extensionsStore.list = data.extensions || [];

        await Promise.all(
            extensionsStore.list.map(async ext => {
                const r = await fetch(`/api/extensions/${ext}/settings`);
                extensionsStore.settings[ext] = await r.json();
            })
        );

        extensionsReady = true;
    }

    function setupEventListeners() {
        const cancelJoinBtn = document.getElementById('cancel-join-btn');
        if (cancelJoinBtn) cancelJoinBtn.onclick = leaveRoom;
        if (elements.joinRoomForm) elements.joinRoomForm.onsubmit = submitJoinForm;

        if (elements.selectAnimeBtn) elements.selectAnimeBtn.onclick = openAnimeSearchModal;
        if (elements.toggleChatBtn) elements.toggleChatBtn.onclick = toggleChat;

        if (elements.roomExtSelect) elements.roomExtSelect.onchange = (e) => {
            onQuickExtensionChange(e, false).then(() => {});
        };        if (elements.roomServerSelect) elements.roomServerSelect.onchange = onQuickServerChange;

        elements.tabChatBtn.onclick = () => switchTab('chat');
        elements.tabQueueBtn.onclick = () => switchTab('queue');

        if (elements.btnAddQueue) {
            elements.btnAddQueue.onclick = () => {
                const canManageQueue = isHost || (window.__userPermissions?.canManageQueue || false);
                if (!canManageQueue) {
                    showSystemToast('You need queue management permission');
                    return;
                }

                if (selectedEpisodes.size === 0) return;

                const sortedEps = Array.from(selectedEpisodes).sort((a, b) => a - b);
                const currentProvider = elements.roomExtSelect ? elements.roomExtSelect.value : 'gogoanime';

                const originalText = elements.btnAddQueue.innerHTML;
                elements.btnAddQueue.disabled = true;
                elements.btnAddQueue.textContent = "Adding...";

                const itemsBatch = sortedEps.map(ep => ({
                    metadata: {
                        id: currentAnimeDetails.id,
                        title: currentAnimeDetails.title.userPreferred || currentAnimeDetails.title.english,
                        episode: ep,
                        image: currentAnimeDetails.coverImage?.large,
                        source: 'anilist',
                        malId: currentAnimeDetails.idMal
                    },
                    video: {
                        animeId: currentAnimeDetails.id,
                        episode: ep,
                        title: currentAnimeDetails.title.userPreferred,
                        extension: currentProvider,
                        server: elements.roomServerSelect?.value || 'gogoanime',
                        category: elements.roomSdToggle?.getAttribute('data-state') || 'sub'
                    }
                }));

                if (ws && ws.readyState === WebSocket.OPEN) {
                    ws.send(JSON.stringify({
                        type: 'queue_add_batch',
                        items: itemsBatch
                    }));
                    closeAnimeSearchModal();
                } else {
                    console.error("WebSocket not connected");
                }

                setTimeout(() => {
                    elements.btnAddQueue.disabled = false;
                    elements.btnAddQueue.innerHTML = originalText;
                }, 500);
            };
        }
        if (elements.roomSdToggle) {
            elements.roomSdToggle.onclick = () => {
                const hasAccess = isHost || (window.__userPermissions?.canManageQueue || false);

                if (!hasAccess) return;
                const currentState = elements.roomSdToggle.getAttribute('data-state');
                const newState = currentState === 'sub' ? 'dub' : 'sub';

                elements.roomSdToggle.setAttribute('data-state', newState);
                elements.roomSdToggle.querySelectorAll('.sd-option').forEach(opt => {
                    opt.classList.toggle('active', opt.dataset.val === newState);
                });

                onQuickServerChange();
            };
        }

        const closeSearchBtn = document.getElementById('close-search-modal');
        const animeSearchBtn = document.getElementById('anime-search-btn');

        if (closeSearchBtn) closeSearchBtn.onclick = closeAnimeSearchModal;
        if (animeSearchBtn) animeSearchBtn.onclick = searchAnime;

        if (elements.animeSearchInput) {
            elements.animeSearchInput.onkeypress = (e) => {
                if (e.key === 'Enter') {
                    e.preventDefault();
                    searchAnime();
                }
            };
        }

        if (elements.backToSearchBtn) {
            elements.backToSearchBtn.onclick = () => {
                elements.stepConfig.style.display = 'none';
                elements.stepSearch.style.display = 'block';
            };
        }
        if (elements.selExtension) elements.selExtension.onchange = handleModalExtensionChange;
        if (elements.btnLaunch) elements.btnLaunch.onclick = () => launchStream(true);

        if (elements.toggleUsersBtn) elements.toggleUsersBtn.onclick = toggleUsersList;

        if (elements.chatForm) elements.chatForm.onsubmit = sendMessage;

        if (elements.animeResults) {
            elements.animeResults.addEventListener('click', handleAnimeResultClick);
        }
    }

    function switchTab(tab) {
        elements.tabChatBtn.classList.toggle('active', tab === 'chat');
        elements.tabQueueBtn.classList.toggle('active', tab === 'queue');
        elements.tabContentChat.style.display = tab === 'chat' ? 'flex' : 'none';
        elements.tabContentQueue.style.display = tab === 'queue' ? 'flex' : 'none';

        if(tab === 'queue') elements.chatForm.style.display = 'none';
        else elements.chatForm.style.display = 'flex';
    }

    // --- QUICK CONTROLS LOGIC (Header) ---

    async function populateQuickControls() {
        const hasAccess = isHost || (window.__userPermissions?.canManageQueue || false);

        if (!hasAccess || !selectedAnimeData) return;
        if (!extensionsReady) return;

        elements.roomExtSelect.innerHTML = '';

        extensionsStore.list.forEach(ext => {
            const opt = document.createElement('option');
            opt.value = ext;
            opt.textContent = ext[0].toUpperCase() + ext.slice(1);
            elements.roomExtSelect.appendChild(opt);
        });

        elements.roomExtSelect.value = selectedAnimeData.source || extensionsStore.list[0];

        await onQuickExtensionChange(null, true);
    }

    async function onQuickExtensionChange(e, silent = false) {
        const hasAccess = isHost || (window.__userPermissions?.canManageQueue || false);
        if (!hasAccess) return;

        const ext = elements.roomExtSelect.value;
        const settings = extensionsStore.settings[ext];

        if (!settings) {
            console.error("Settings not loaded for extension:", ext);
            return;
        }

        elements.roomServerSelect.innerHTML = '';
        const servers = settings.episodeServers?.length
            ? settings.episodeServers
            : ['Default'];

        servers.forEach(srv => {
            const opt = document.createElement('option');
            opt.value = srv;
            opt.textContent = srv;
            elements.roomServerSelect.appendChild(opt);
        });

        const defaultServer = servers[0];
        elements.roomServerSelect.value = defaultServer;

        if (typeof handleDubUI === 'function') {
            handleDubUI(settings, 'header');
        }

        if (typeof activeContext !== 'undefined') {
            activeContext.extension = ext;
            activeContext.server = defaultServer;
        }

        if (!silent) {
            await launchStream(false, false, {
                forceExtension: ext,
                forceServer: defaultServer
            });
        }
    }

    function handleDubUI(settings, context = 'header') {
        const supportsDub = !!settings.supportsDub;

        if (context === 'header') {
            if (!elements.roomSdToggle) return;

            elements.roomSdToggle.style.display = supportsDub ? 'flex' : 'none';

            if (!supportsDub && elements.roomSdToggle.getAttribute('data-state') === 'dub') {
                elements.roomSdToggle.setAttribute('data-state', 'sub');
                elements.roomSdToggle.querySelectorAll('.sd-option').forEach(o => {
                    o.classList.toggle('active', o.dataset.val === 'sub');
                });
            }
        }

        if (context === 'modal') {
            if (!elements.modalSdToggle) return;

            elements.modalSdToggle.style.display = supportsDub ? 'flex' : 'none';

            if (!supportsDub && configState.category === 'dub') {
                configState.category = 'sub';
                updateSDUI();
            }
        }
    }

    function onQuickServerChange() {
        const hasAccess = isHost || (window.__userPermissions?.canManageQueue || false);
        if (!hasAccess) return;

        launchStream(false);
    }

    function handleAnimeResultClick(e) {
        const itemLink = e.target.closest('.search-item, .anime-result-item, a[href*="/anime/"]');

        if (itemLink) {
            e.preventDefault();
            e.stopPropagation();

            let title, img, id;

            const titleEl = itemLink.querySelector('.search-title');
            const imgEl = itemLink.querySelector('.search-poster, img');

            title = titleEl ? titleEl.textContent : (itemLink.textContent.trim() || 'Unknown');
            img = imgEl ? (imgEl.src || imgEl.dataset.src || '/public/assets/placeholder.svg') : '/public/assets/placeholder.svg';

            const href = itemLink.getAttribute('href') || '';
            const hrefParts = href.split('/').filter(p => p);
            id = hrefParts[hrefParts.length - 1] || itemLink.dataset.id;

            if (!id) return;

            selectedAnimeData = {
                id: id,
                title: title,
                image: img,
                source: 'anilist'
            };
            const animeResultObj = {
                id: id,
                title: title,
                cover: img
            };

            showConfigStep();
            onAnimeSelected(animeResultObj);
        }
    }

    function showConfigStep() {
        if (!selectedAnimeData) return;

        elements.configTitle.textContent = selectedAnimeData.title;
        elements.configCover.src = selectedAnimeData.image;
        if(elements.configError) elements.configError.style.display = 'none';

        configState.episode = 1;
        if(elements.inpEpisode) elements.inpEpisode.value = 1;

        if(elements.btnLaunch) elements.btnLaunch.disabled = false;
        if(elements.btnAddQueue) elements.btnAddQueue.disabled = false;

        if (extensionsReady && elements.selExtension) {
            if (elements.selExtension.options.length <= 1) {
                elements.selExtension.innerHTML = '';

                extensionsStore.list.forEach(ext => {
                    const opt = document.createElement('option');
                    opt.value = ext;
                    opt.textContent = ext[0].toUpperCase() + ext.slice(1);
                    elements.selExtension.appendChild(opt);
                });

                let defaultExt = selectedAnimeData.source || 'anilist';
                if (!extensionsStore.list.includes(defaultExt) && extensionsStore.list.length > 0) {
                    defaultExt = extensionsStore.list[0];
                }

                elements.selExtension.value = defaultExt;

                handleModalExtensionChange();
            }
        }

        setupConfigListeners();

        elements.stepSearch.style.display = 'none';
        elements.stepConfig.style.display = 'block';
    }

    function setupConfigListeners() {
       elements.epInc.onclick = () => {
            elements.inpEpisode.value = parseInt(elements.inpEpisode.value || 0) + 1;
        };
        elements.epDec.onclick = () => {
            if(elements.inpEpisode.value > 1) elements.inpEpisode.value = parseInt(elements.inpEpisode.value) - 1;
        };
        if(elements.inpEpisode) elements.inpEpisode.onchange = (e) => configState.episode = e.target.value;

        if(elements.modalSdToggle) {
            elements.modalSdToggle.querySelectorAll('.cat-opt').forEach(opt => {
                opt.onclick = () => {
                    if(opt.classList.contains('disabled')) return;
                    configState.category = opt.dataset.val;
                    updateSDUI();
                    if(configState.extension) loadServersForExtension(configState.extension);
                };
            });
        }
    }

    function updateSDUI() {
        if(!elements.modalSdToggle) return;
        elements.modalSdToggle.querySelectorAll('.cat-opt').forEach(opt => {
            opt.classList.toggle('active', opt.dataset.val === configState.category);
        });
    }

    async function loadServersForExtension(extName) {
        if (!extensionsReady) return;
        elements.serverContainer.innerHTML = '<div class="grid-loader"><div class="spinner" style="width:20px;height:20px;"></div> Loading servers...</div>';
        elements.btnLaunch.disabled = true;
        if(elements.btnAddQueue) elements.btnAddQueue.disabled = true;

        try {
            const settings = extensionsStore.settings[extName];

            handleDubUI(settings, 'modal');

            const servers = settings.episodeServers?.length
                ? settings.episodeServers
                : ['Default'];

            renderServerChips(servers);
        } catch (e) {
            console.error("Error loading settings", e);
            elements.serverContainer.innerHTML = '<div class="grid-loader" style="color:#ff6b6b">Error loading servers</div>';
        }
    }

    function renderServerChips(servers) {
        elements.serverContainer.innerHTML = '';

        servers.forEach(srv => {
            const chip = document.createElement('div');
            chip.className = 'chip';
            chip.textContent = srv;

            chip.onclick = () => {
                document.querySelectorAll('#server-chips-container .chip').forEach(c => c.classList.remove('active'));
                chip.classList.add('active');

                configState.server = srv;
                elements.btnLaunch.disabled = false;
                if(elements.btnAddQueue) elements.btnAddQueue.disabled = false;
            };

            elements.serverContainer.appendChild(chip);
        });
    }

    async function handleModalExtensionChange() {
        const extName = elements.selExtension.value;
        if (!extName) return;

        elements.selServer.innerHTML = '<option>Loading...</option>';
        elements.selServer.disabled = true;

        try {
            const settings = extensionsStore.settings[extName];

            elements.selServer.innerHTML = '';

            if (settings.episodeServers && settings.episodeServers.length > 0) {
                settings.episodeServers.forEach(srv => {
                    const opt = document.createElement('option');
                    opt.value = srv;
                    opt.textContent = srv;
                    elements.selServer.appendChild(opt);
                });
                elements.selServer.disabled = false;
            } else {
                elements.selServer.innerHTML = '<option value="default">Default</option>';
                elements.selServer.disabled = false;
            }

            const dubOption = elements.selCategory.querySelector('option[value="dub"]');
            if (dubOption) {
                dubOption.disabled = !settings.supportsDub;
                if (!settings.supportsDub && elements.selCategory.value === 'dub') {
                    elements.selCategory.value = 'sub';
                }
            }

        } catch (e) {
            console.error("Error loading extension settings", e);
            elements.selServer.innerHTML = '<option>Error loading servers</option>';
        }
    }

    // --- STREAM LAUNCHER (Unified) ---

    async function launchStream(fromModal = false, isQueueAction = false, overrides = {}) {
        if (!selectedAnimeData) return;

        let episodeToPlay = activeContext.episode;
        if (fromModal && elements.inpEpisode) episodeToPlay = elements.inpEpisode.value;

        const ext = overrides.forceExtension ||
            (fromModal ? (configState.extension || elements.selExtension?.value) : null) ||
            activeContext.extension ||
            (elements.roomExtSelect ? elements.roomExtSelect.value : null);

        const server = overrides.forceServer ||
            (fromModal ? (configState.server || elements.selServer?.value) : null) ||
            activeContext.server ||
            (elements.roomServerSelect ? elements.roomServerSelect.value : null);

        const category = elements.roomSdToggle?.getAttribute('data-state') || activeContext.category || 'sub';

        if (!ext || !server) {
            console.warn("Faltan datos (ext o server).", {ext, server});
            if (fromModal && elements.configError) {
                elements.configError.textContent = "Please select an extension and server.";
                elements.configError.style.display = 'block';
            }
            return;
        }

        activeContext = { extension: ext, server, category, episode: episodeToPlay };
        selectedAnimeData.episode = parseInt(episodeToPlay);

        if (fromModal && isQueueAction) {
            elements.btnAddQueue.disabled = true;
            elements.btnAddQueue.textContent = 'Adding...';
        } else if (!isQueueAction) {
            if(typeof showSystemToast === 'function') showSystemToast(`Loading ${ext}...`);
        }

        try {
            const apiUrl = `/api/watch/stream?animeId=${selectedAnimeData.id}&episode=${episodeToPlay}&server=${encodeURIComponent(server)}&category=${category}&ext=${ext}&source=anilist`;
            console.log('Fetching stream:', apiUrl);

            const res = await fetch(apiUrl);
            if (!res.ok) throw new Error(`Error ${res.status}: Failed to fetch stream`);

            const data = await res.json();

            if (data.error) throw new Error(data.error);

            const source = data.videoSources?.find(s => s.type === 'm3u8') || data.videoSources?.[0];

            if (!source) {
                throw new Error(`No sources found on ${ext} for this episode.`);
            }

            let proxyUrl = `/api/proxy?url=${encodeURIComponent(source.url)}`;
            const headers = data.headers || {};
            if (headers['Referer']) proxyUrl += `&referer=${encodeURIComponent(headers['Referer'])}`;

            const subtitles = (source.subtitles || []).map(sub => ({
                label: sub.language,
                srclang: sub.id || sub.language.toLowerCase().slice(0, 2),
                src: `/api/proxy?url=${encodeURIComponent(sub.url)}`
            }));

            const contextPayload = {
                animeId: selectedAnimeData.id,
                episode: episodeToPlay,
                source: selectedAnimeData.source,
                extension: ext,
                server: server,
                category: category
            };

            const videoPayload = {
                videoData: { url: proxyUrl, type: source.type || 'm3u8', headers },
                subtitles: subtitles,
                context: contextPayload,
                malId: selectedAnimeData.malId,
                episode: episodeToPlay
            };

            const metaPayload = {
                title: selectedAnimeData.title,
                episode: episodeToPlay,
                image: selectedAnimeData.image,
                id: selectedAnimeData.id,
                source: ext,
                malId: selectedAnimeData.malId
            };

            if (ws && ws.readyState === WebSocket.OPEN) {
                if (isQueueAction) {
                    ws.send(JSON.stringify({
                        type: 'queue_add',
                        video: videoPayload,
                        metadata: metaPayload
                    }));
                    if(typeof showSystemToast === 'function') showSystemToast("Added to queue!");
                } else {
                    ws.send(JSON.stringify({
                        type: 'video_update',
                        video: { ...videoPayload, currentTime: 0, isPlaying: true },
                        metadata: metaPayload
                    }));

                    loadVideo({ ...videoPayload, currentTime: 0, isPlaying: true });
                    updateHeaderInfo(metaPayload);

                    if(typeof syncControlsUI === 'function') syncControlsUI(contextPayload);
                }
            }

            if (fromModal) closeAnimeSearchModal();

        } catch (err) {
            console.error("Stream Launch Error:", err);

            const errorMsg = err.message || "Error loading stream.";

            if (fromModal) {
                if(elements.configError) {
                    elements.configError.textContent = errorMsg;
                    elements.configError.style.display = 'block';
                }
            } else {
                if(typeof showSystemToast === 'function') {
                    showSystemToast(`Error: ${errorMsg}`);
                } else {
                    alert(errorMsg);
                }
            }
        } finally {
            if (fromModal && isQueueAction) {
                elements.btnAddQueue.disabled = false;
                elements.btnAddQueue.textContent = '+ Add to Queue';
            }
        }
    }

    async function onAnimeSelected(animeResult) {
        const gridContainer = document.getElementById('episodes-grid');
        gridContainer.innerHTML = '<div class="grid-loader"><div class="spinner"></div> Loading info...</div>';

        document.getElementById('step-search').style.display = 'none';
        document.getElementById('step-config').style.display = 'block';

        document.getElementById('config-cover').src = animeResult.cover;
        document.getElementById('selected-anime-title').textContent = animeResult.title;

        selectedEpisodes.clear();
        selectedEpisodes.add(1);
        updateCountBtn();

        try {
            const response = await fetch(`/api/anime/${animeResult.id}?source=anilist`);
            if (!response.ok) throw new Error("Failed to load anime details");

            const data = await response.json();
            currentAnimeDetails = data;

            if (selectedAnimeData) {
                selectedAnimeData.malId = data.idMal;
            }

            modalTotalEpisodes = data.episodes || 12;
            modalCurrentPage = 1;

            renderModalEpisodes();
            setupModalPaginationControls();

        } catch (error) {
            console.error("Error fetching details", error);
            gridContainer.innerHTML = '';
            document.querySelector('.manual-ep-input').style.display = 'block';
            document.getElementById('modal-pagination').style.display = 'none';
        }
    }

    function renderModalEpisodes() {
        const grid = document.getElementById('episodes-grid');
        grid.innerHTML = '';

        const start = (modalCurrentPage - 1) * MODAL_EPS_PER_PAGE + 1;
        const end = Math.min(start + MODAL_EPS_PER_PAGE - 1, modalTotalEpisodes);

        const infoText = document.getElementById('modal-page-info');
        if (infoText) infoText.textContent = `${start} - ${end} of ${modalTotalEpisodes}`;

        for (let i = start; i <= end; i++) {
            const btn = document.createElement('div');
            const isSelected = selectedEpisodes.has(i);
            btn.className = `ep-grid-btn ${isSelected ? 'selected' : ''}`;
            btn.textContent = i;
            btn.dataset.ep = i;

            btn.onclick = (e) => toggleEpisode(i, btn, e.shiftKey);

            grid.appendChild(btn);
        }

        document.getElementById('modal-prev-page').disabled = modalCurrentPage === 1;
        document.getElementById('modal-next-page').disabled = end >= modalTotalEpisodes;

        document.getElementById('modal-pagination').style.display = modalTotalEpisodes > MODAL_EPS_PER_PAGE ? 'flex' : 'none';
        document.querySelector('.manual-ep-input').style.display = 'none';
    }

    function setupModalPaginationControls() {
        document.getElementById('modal-prev-page').onclick = () => {
            if (modalCurrentPage > 1) {
                modalCurrentPage--;
                renderModalEpisodes();
            }
        };

        document.getElementById('modal-next-page').onclick = () => {
            const maxPage = Math.ceil(modalTotalEpisodes / MODAL_EPS_PER_PAGE);
            if (modalCurrentPage < maxPage) {
                modalCurrentPage++;
                renderModalEpisodes();
            }
        };

        document.getElementById('select-all-page').onclick = () => {
            const start = (modalCurrentPage - 1) * MODAL_EPS_PER_PAGE + 1;
            const end = Math.min(start + MODAL_EPS_PER_PAGE - 1, modalTotalEpisodes);
            for(let i=start; i<=end; i++) selectedEpisodes.add(i);
            renderModalEpisodes();
            updateCountBtn();
        };

        document.getElementById('select-none-eps').onclick = () => {
            selectedEpisodes.clear();
            renderModalEpisodes();
            updateCountBtn();
        };
    }

    async function syncControlsUI(context) {
        if (!context || !isHost) return;

        if (context.extension && elements.roomExtSelect.value !== context.extension) {
            elements.roomExtSelect.value = context.extension;
            await onQuickExtensionChange(null, true);
        }

        if (context.server) {
            const options = Array.from(elements.roomServerSelect.options).map(o => o.value);
            if (options.includes(context.server)) {
                elements.roomServerSelect.value = context.server;
            }
        }

        if (context.category) {
            elements.roomSdToggle.setAttribute('data-state', context.category);
            elements.roomSdToggle.querySelectorAll('.sd-option').forEach(opt => {
                opt.classList.toggle('active', opt.dataset.val === context.category);
            });
        }

        activeContext = { ...activeContext, ...context };
    }

    function toggleEpisode(epNum, btnElement, isShift) {
        if (isShift && lastSelectedEp) {
            const start = Math.min(lastSelectedEp, epNum);
            const end = Math.max(lastSelectedEp, epNum);

            for (let i = start; i <= end; i++) {
                selectedEpisodes.add(i);
                const el = document.querySelector(`.ep-grid-btn[data-ep="${i}"]`);
                if (el) el.classList.add('selected');
            }
        } else {
            if (selectedEpisodes.has(epNum)) {
                selectedEpisodes.delete(epNum);
                btnElement.classList.remove('selected');
            } else {
                selectedEpisodes.add(epNum);
                btnElement.classList.add('selected');
            }
        }

        lastSelectedEp = epNum;
        updateCountBtn();
    }

    function updateCountBtn() {
        document.getElementById('sel-count').textContent = selectedEpisodes.size;
    }

    document.getElementById('btn-add-queue').addEventListener('click', () => {
        if (selectedEpisodes.size === 0) return;

        const sortedEps = Array.from(selectedEpisodes).sort((a, b) => a - b);

        const itemsBatch = sortedEps.map(ep => ({
            metadata: {
                id: currentAnimeDetails.id,
                title: currentAnimeDetails.title.userPreferred || currentAnimeDetails.title.english,
                episode: ep,
                image: currentAnimeDetails.coverImage?.large,
                source: 'anilist',
                malId: currentAnimeDetails.idMal
            },
            video: {
                animeId: currentAnimeDetails.id,
                episode: ep,
                title: currentAnimeDetails.title.userPreferred,
                server: document.getElementById('room-server-select').value || 'gogoanime',
                category: 'sub'
            }
        }));

        if (itemsBatch.length === 1) {
            socket.send(JSON.stringify({
                type: 'queue_add',
                metadata: itemsBatch[0].metadata,
                video: itemsBatch[0].video
            }));
        } else {
            socket.send(JSON.stringify({
                type: 'queue_add_batch',
                items: itemsBatch
            }));
        }

        closeModal();
    });
    function connectToRoom(roomId, guestName, password) {
        shouldReconnect = true;
        const token = localStorage.getItem('token');

        const isTunnel = window.location.hostname.includes('trycloudflare.com');

        let wsUrl;

        if (isTunnel) {
            wsUrl = `wss://${window.location.host}/ws/room/${roomId}`;
            console.log('[Tunnel Mode] Using secure WebSocket:', wsUrl);
        } else {
            const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
            wsUrl = `${protocol}//${window.location.host}/ws/room/${roomId}`;
            console.log('[Local Mode] Using WebSocket:', wsUrl);
        }

        const params = new URLSearchParams();
        if (token) params.append('token', token);
        if (guestName) params.append('guestName', guestName);
        if (password) params.append('password', password);

        if (ws) {
            console.log('Closing existing WebSocket...');
            ws.close();
        }

        console.log('Connecting to:', `${wsUrl}?${params.toString()}`);
        ws = new WebSocket(`${wsUrl}?${params.toString()}`);

        ws.onopen = () => {
            console.log('✓ WebSocket Connected');
            if (window.AnimePlayer && typeof window.AnimePlayer.setWebSocket === 'function') {
                window.AnimePlayer.setWebSocket(ws);
            }

            setTimeout(() => {
                if (ws && ws.readyState === WebSocket.OPEN) {
                    console.log('Requesting sync from host...');
                    ws.send(JSON.stringify({ type: 'request_sync' }));
                }
            }, 500);
        };

        ws.onmessage = (e) => handleWebSocketMessage(JSON.parse(e.data));

        ws.onerror = (e) => {
            console.error('✗ WebSocket error:', e);
            showConnectionError('WebSocket connection failed. Check your connection.');
        };

        ws.onclose = (event) => {
            console.log('WebSocket Disconnected:', event.code, event.reason);
            if (!shouldReconnect) return;
            if (window.AnimePlayer && typeof window.AnimePlayer.setWebSocket === 'function') {
                window.AnimePlayer.setWebSocket(null);
            }

            if (event.code !== 1000 && event.code !== 1001) {
                console.log('Attempting reconnection in 3 seconds...');
                showReconnectingToast();
                setTimeout(() => {
                    if (currentRoomId) {
                        console.log('Reconnecting to room...');
                        connectToRoom(currentRoomId, guestName, password);
                    }
                }, 3000);
            }
        };
    }

    function showReconnectingToast() {
        const toast = document.createElement('div');
        toast.id = 'reconnecting-toast';
        toast.className = 'connection-error-toast';
        toast.innerHTML = `
        <div style="display:flex; align-items:center; gap:10px;">
            <div class="spinner" style="width:16px; height:16px; border-width:2px;"></div>
            <span>Reconnecting...</span>
        </div>
    `;
        toast.style.cssText = `
        position: fixed;
        top: 80px;
        left: 50%;
        transform: translateX(-50%);
        background: rgba(251, 191, 36, 0.95);
        color: white;
        padding: 12px 24px;
        border-radius: 8px;
        font-size: 14px;
        font-weight: 500;
        z-index: 10000;
        box-shadow: 0 4px 12px rgba(0,0,0,0.3);
        animation: slideDown 0.3s ease-out;
    `;

        const existing = document.getElementById('reconnecting-toast');
        if (existing) existing.remove();

        document.body.appendChild(toast);
    }

    function showConnectionError(message) {
        const errorDiv = document.createElement('div');
        errorDiv.className = 'connection-error-toast';
        errorDiv.textContent = message;
        errorDiv.style.cssText = `
        position: fixed;
        top: 80px;
        left: 50%;
        transform: translateX(-50%);
        background: rgba(239, 68, 68, 0.95);
        color: white;
        padding: 12px 24px;
        border-radius: 8px;
        font-size: 14px;
        font-weight: 500;
        z-index: 10000;
        box-shadow: 0 4px 12px rgba(0,0,0,0.3);
        animation: slideDown 0.3s ease-out;
    `;

        document.body.appendChild(errorDiv);

        setTimeout(() => {
            errorDiv.style.animation = 'fadeOut 0.3s ease-out';
            setTimeout(() => errorDiv.remove(), 300);
        }, 5000);
    }

    function handleWebSocketMessage(data) {
        switch (data.type) {
            case 'error':
                shouldReconnect = false;
                handleConnectionError(data.message);
                break;

            case 'init':
                const reconnectToast = document.getElementById('reconnecting-toast');
                if (reconnectToast) reconnectToast.remove();
                if (data.room.queue) renderQueue(data.room.queue);
                elements.joinRoomModal.classList.remove('show');
                currentUserId = data.userId;
                currentUsername = data.username;
                isGuest = data.isGuest;

                if (data.room && data.room.users) {
                    const currentUser = data.room.users.find(u => u.id === data.userId);
                    if (currentUser) {
                        window.__userPermissions = currentUser.permissions || {
                            canControl: false,
                            canManageQueue: false
                        };
                    }
                }

                if (data.room.queue) renderQueue(data.room.queue);
                updateRoomUI(data.room);

                if (data.room.currentVideo) {
                    loadVideo(data.room.currentVideo);

                    if (data.room.metadata) {
                        updateHeaderInfo(data.room.metadata);
                    }
                    if (data.room.currentVideo.context) {
                        syncControlsUI(data.room.currentVideo.context);
                    }

                    if (!isHost) {
                        console.log('Video detected on join, requesting sync...');
                        setTimeout(() => {
                            if (ws && ws.readyState === WebSocket.OPEN) {
                                ws.send(JSON.stringify({ type: 'request_sync' }));
                            }
                        }, 1000);
                    }
                }
                break;

            case 'queue_update':
                renderQueue(data.queue);
                break;

            case 'users_update':
                saveRoomData({ users: data.users });
                renderUsersList(data.users);
                break;

            case 'user_joined':
                addSystemMessage(`${data.user.username} joined`);
                updateUsersList();

                if (isHost) {
                    console.log('New user joined, sending sync...');
                    setTimeout(() => sendSync(), 500);
                }
                break;

            case 'user_left':
                addSystemMessage(`${data.user.username} left`);
                updateUsersList();
                break;

            case 'permissions_updated':
                saveRoomData({ users: data.users });

                const updatedUser = data.users.find(u => u.id === currentUserId);
                if (updatedUser) {
                    window.__userPermissions = updatedUser.permissions || {
                        canControl: false,
                        canManageQueue: false
                    };

                    const canManageQueue = isHost || (window.__userPermissions?.canManageQueue || false);
                    if (elements.selectAnimeBtn) {
                        elements.selectAnimeBtn.style.display = canManageQueue ? 'flex' : 'none';
                    }

                    if (currentQueue.length > 0) {
                        renderQueue(currentQueue);
                    }
                }

                if (permissionsModal && permissionsModal.classList.contains('show')) {
                    updatePermissionsList();
                }

                renderUsersList(data.users);
                break;
            case 'chat':
                addChatMessage(data);
                const isChatHidden = elements.roomLayout.classList.contains('chat-hidden');
                if (isChatHidden) {
                    showChatToast(data);
                    if (elements.toggleChatBtn) {
                        elements.toggleChatBtn.classList.add('has-unread');
                    }
                }
                break;

            case 'video_update':
                loadVideo(data.video);

                if (data.metadata) {
                    selectedAnimeData = { ...selectedAnimeData, ...data.metadata };
                    updateHeaderInfo(data.metadata);
                }

                if (data.video.context) {
                    syncControlsUI(data.video.context);
                }

                if (!isHost) {
                    setTimeout(() => {
                        if (ws && ws.readyState === WebSocket.OPEN) {
                            console.log('New video loaded, requesting sync...');
                            ws.send(JSON.stringify({ type: 'request_sync' }));
                        }
                    }, 1500);                }
                break;

            case 'sync':
                console.log('Received sync:', data.currentTime, data.isPlaying ? 'playing' : 'paused');
                syncVideo(data.currentTime, data.isPlaying);
                updatePlayPauseButton(data.isPlaying);
                break;

            case 'play':
                const vP = getVideoElement();
                if(vP) {
                    vP.currentTime = data.currentTime;
                    vP.play().catch(console.error);
                    updatePlayPauseButton(true);
                }
                break;

            case 'pause':
                const vPa = getVideoElement();
                if(vPa) {
                    vPa.currentTime = data.currentTime;
                    vPa.pause();
                    updatePlayPauseButton(false);
                }
                break;

            case 'seek':
                const vS = getVideoElement();
                if(vS) {
                    vS.currentTime = data.currentTime;
                }
                break;

            case 'sync_requested':
                if (isHost) {
                    console.log('Sync requested, sending current state...');
                    sendSync();
                }
                break;
        }
    }

    function renderQueue(queueItems) {
        currentQueue = queueItems;
        if (!elements.queueList) return;

        elements.queueCount.textContent = queueItems.length;

        if (queueItems.length === 0) {
            elements.queueList.innerHTML = '<div class="queue-empty">Queue is empty</div>';
            return;
        }

        const canManageQueue = isHost || (window.__userPermissions && window.__userPermissions.canManageQueue);
        elements.queueList.innerHTML = queueItems.map((item, index) => {
            let actionsHtml = '';

            if (canManageQueue) {
                const isFirst = index === 0;
                const isLast = index === queueItems.length - 1;

                actionsHtml = `
                <div class="q-actions">
                    <button class="q-btn play" onclick="playQueueItem('${item.uid}')" title="Play Now">
                        <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>
                    </button>
                    <div style="display:flex; gap:2px;">
                        ${!isFirst ? `
                        <button class="q-btn" onclick="moveQueueItem('${item.uid}', 'up')" title="Move Up">
                            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 15l-6-6-6 6"/></svg>
                        </button>` : ''}
                        ${!isLast ? `
                        <button class="q-btn" onclick="moveQueueItem('${item.uid}', 'down')" title="Move Down">
                            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 9l6 6 6-6"/></svg>
                        </button>` : ''}
                    </div>
                    <button class="q-btn remove" onclick="removeQueueItem('${item.uid}')" title="Remove">
                        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
                    </button>
                </div>
            `;
            }

            return `
            <div class="queue-item">
                <img src="${item.metadata.image || '/public/assets/placeholder.png'}" class="q-img">
                <div class="q-info">
                    <div class="q-title" title="${escapeHtml(item.metadata.title)}">${escapeHtml(item.metadata.title)}</div>
                    <div class="q-meta">Ep ${item.metadata.episode} • ${escapeHtml(item.addedBy)}</div>
                </div>
                ${actionsHtml}
            </div>
        `;
        }).join('');
    }

    window.playQueueItem = async function(uid) {
        const canManageQueue = isHost || (window.__userPermissions?.canManageQueue || false);
        if (!canManageQueue) {
            showSystemToast('You need queue management permission');
            return;
        }

        const item = currentQueue.find(i => i.uid === uid);
        if (!item) return;

        if(typeof showSystemToast === 'function') showSystemToast("Loading from queue...");

        if (item.videoData && item.videoData.animeId) {
            const v = item.videoData;

            selectedAnimeData = {
                id: v.animeId,
                title: v.title,
                image: item.metadata.image,
                source: 'anilist',
                episode: parseInt(v.episode),
                malId: item.metadata.malId
            };

            activeContext.episode = parseInt(v.episode);
            activeContext.category = v.category || 'sub';

            if (elements.roomSdToggle) {
                elements.roomSdToggle.setAttribute('data-state', activeContext.category);
                elements.roomSdToggle.querySelectorAll('.sd-option').forEach(opt => {
                    opt.classList.toggle('active', opt.dataset.val === activeContext.category);
                });
            }

            try {
                const providerExtension = v.extension || elements.roomExtSelect?.value || 'gogoanime';

                console.log(`Playing from queue with provider: ${providerExtension}`);

                await launchStream(false, false, {
                    forceExtension: providerExtension,
                    forceServer: v.server
                });

                removeQueueItem(uid);

            } catch(e) {
                console.error("Error playing queue item:", e);
                if(typeof showSystemToast === 'function') showSystemToast("Error: " + e.message);
            }

        } else {
            if(ws && ws.readyState === WebSocket.OPEN) {
                ws.send(JSON.stringify({ type: 'queue_play_item', itemUid: uid }));
            }
        }
    };

    window.moveQueueItem = function(uid, direction) {
        const canManageQueue = isHost || (window.__userPermissions?.canManageQueue || false);
        if (!canManageQueue) {
            showSystemToast('You need queue management permission');
            return;
        }

        if(ws && ws.readyState === WebSocket.OPEN) {
            ws.send(JSON.stringify({ type: 'queue_move', itemUid: uid, direction }));
        }
    };


    window.removeQueueItem = function(uid) {
        const canManageQueue = isHost || (window.__userPermissions?.canManageQueue || false);
        if (!canManageQueue) {
            showSystemToast('You need queue management permission');
            return;
        }

        if(ws && ws.readyState === WebSocket.OPEN) {
            ws.send(JSON.stringify({ type: 'queue_remove', itemUid: uid }));
        }
    };

    function updateRoomUI(room) {
        elements.roomName.textContent = room.name;
        elements.roomViewers.textContent = `${room.users.length}`;

        const currentUser = room.users.find(u => u.id === currentUserId);

        if (currentUser) {
            window.__userPermissions = currentUser.permissions || { canControl: false, canManageQueue: false };
        }
        isHost = currentUser?.isHost || false;

        const canManageQueue = isHost || (window.__userPermissions?.canManageQueue || false);

        const canControlPlayer = isHost || (window.__userPermissions?.canControl || false);

        if (elements.selectAnimeBtn) {
            elements.selectAnimeBtn.style.display = canManageQueue ? 'flex' : 'none';
        }

        if (elements.hostControls) {
            elements.hostControls.style.display = canManageQueue ? 'flex' : 'none';
        }

        if (window.AnimePlayer && typeof window.AnimePlayer.setRoomHost === 'function') {
            window.AnimePlayer.setRoomHost(canControlPlayer);
        }

        if (isHost) {
            initGlobalControls();
            initPermissionsUI();
        }
        else if (canManageQueue) {
            initGlobalControls();
        }

        if (canManageQueue && room.metadata) {
            if(!selectedAnimeData) selectedAnimeData = { ...room.metadata, source: 'anilist' };
            populateQuickControls();
        }

        const copyInviteBtn = document.getElementById('copy-invite-btn');

        if (copyInviteBtn) {
            let inviteUrl = null;

            if (window.__roomExposed && window.__roomPublicUrl) {
                inviteUrl = window.__roomPublicUrl;
            } else {
                inviteUrl = `${window.location.origin}/room?id=${room.id}`;
            }

            console.log('Copy button configured with URL:', inviteUrl);

            copyInviteBtn.style.display = 'inline-flex';
            copyInviteBtn.title = window.__roomExposed
                ? 'Copy public invite link (works outside your network)'
                : 'Copy local invite link (only works on your network)';

            copyInviteBtn.onclick = async () => {
                try {
                    console.log('Attempting to copy:', inviteUrl);

                    const success = await copyToClipboard(inviteUrl);

                    if (success) {
                        const originalHTML = copyInviteBtn.innerHTML;
                        copyInviteBtn.innerHTML = `
                        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                            <polyline points="20 6 9 17 4 12"></polyline>
                        </svg>
                    `;
                        copyInviteBtn.style.color = '#4ade80';

                        setTimeout(() => {
                            copyInviteBtn.innerHTML = originalHTML;
                            copyInviteBtn.style.color = '';
                        }, 2000);

                        showCopyToast(window.__roomExposed ? 'Public link copied!' : 'Local link copied!');
                    } else {
                        showManualCopyModal(inviteUrl);
                    }
                } catch (err) {
                    console.error('Failed to copy:', err);
                    showManualCopyModal(inviteUrl);
                }
            };
        }

        if (isHost && room.metadata) {
            if(!selectedAnimeData) selectedAnimeData = { ...room.metadata, source: 'anilist' };
            populateQuickControls();
        }

        renderUsersList(room.users);
        if (room.currentVideo) loadVideo(room.currentVideo);
    }

    function showManualCopyModal(text) {
        const modal = document.createElement('div');
        modal.className = 'modal-overlay show';
        modal.innerHTML = `
            <div class="modal-content" style="max-width: 500px;">
                <h2 class="modal-title">Copy Invite Link</h2>
                <p style="color: #aaa; margin-bottom: 16px;">Select and copy this link:</p>
                <input type="text" readonly value="${text}" 
                       style="width: 100%; padding: 12px; font-family: monospace; font-size: 0.9rem;"
                       onclick="this.select()">
                <div class="form-actions" style="margin-top: 20px;">
                    <button class="btn-confirm" onclick="this.closest('.modal-overlay').remove()">Close</button>
                </div>
            </div>
        `;
        document.body.appendChild(modal);

        // Auto-seleccionar el texto
        setTimeout(() => {
            const input = modal.querySelector('input');
            if (input) input.select();
        }, 100);
    }

    async function copyToClipboard(text) {
        if (navigator.clipboard && window.isSecureContext) {
            try {
                await navigator.clipboard.writeText(text);
                return true;
            } catch (err) {
                console.warn('Clipboard API failed, trying fallback:', err);
            }
        }

        try {
            const textArea = document.createElement("textarea");
            textArea.value = text;
            textArea.style.position = "fixed";
            textArea.style.left = "-999999px";
            textArea.style.top = "-999999px";
            document.body.appendChild(textArea);
            textArea.focus();
            textArea.select();

            const successful = document.execCommand('copy');
            document.body.removeChild(textArea);

            if (successful) return true;
            throw new Error('execCommand failed');
        } catch (err) {
            console.error('All clipboard methods failed:', err);
            return false;
        }
    }

    async function initGlobalControls() {
        const hasAccess = isHost || (window.__userPermissions?.canManageQueue || false);
        if (!hasAccess || !extensionsReady) return;

        if (elements.roomExtSelect.options.length > 1) return;

        elements.roomExtSelect.innerHTML = '';

        extensionsStore.list.forEach(ext => {
            const opt = document.createElement('option');
            opt.value = ext;
            opt.textContent = ext[0].toUpperCase() + ext.slice(1);
            elements.roomExtSelect.appendChild(opt);
        });

        const defaultExt = 'anilist';
        if (extensionsStore.list.includes(defaultExt)) {
            elements.roomExtSelect.value = defaultExt;
        } else {
            elements.roomExtSelect.value = extensionsStore.list[0];
        }

        await onQuickExtensionChange(null, true);
    }

    function showCopyToast(message) {
        const toast = document.createElement('div');
        toast.className = 'copy-toast';
        toast.textContent = message;
        toast.style.cssText = `
        position: fixed;
        bottom: 80px;
        left: 50%;
        transform: translateX(-50%);
        background: rgba(74, 222, 128, 0.95);
        color: white;
        padding: 12px 24px;
        border-radius: 8px;
        font-size: 14px;
        font-weight: 500;
        z-index: 10000;
        box-shadow: 0 4px 12px rgba(0,0,0,0.3);
        animation: slideUp 0.3s ease-out;
    `;

        document.body.appendChild(toast);

        setTimeout(() => {
            toast.style.animation = 'fadeOut 0.3s ease-out';
            setTimeout(() => toast.remove(), 300);
        }, 2000);
    }

    function updateHeaderInfo(meta) {
        if (!meta) return;
        if (elements.npTitle) elements.npTitle.textContent = meta.title;
        if (elements.npEpisode) elements.npEpisode.textContent = `Episode ${meta.episode}`;
        if (elements.npInfo) elements.npInfo.style.opacity = '1';

        if(!selectedAnimeData) {
            selectedAnimeData = { ...meta, source: 'anilist' };
        } else {
            selectedAnimeData.id = meta.id;
            selectedAnimeData.title = meta.title;
            selectedAnimeData.image = meta.image || selectedAnimeData.image;
            selectedAnimeData.episode = parseInt(meta.episode);
        }
    }

    // --- UTILS & HELPERS ---

    function handleConnectionError(message) {
        const msg = message.toLowerCase();
        if (msg.includes('password') || msg.includes('authorized')) {
            const passwordGroup = document.getElementById('password-group');
            const token = localStorage.getItem('token');
            elements.joinRoomModal.classList.add('show');
            if (msg.includes('password')) {
                passwordGroup.style.display = 'block';
                document.getElementById('join-password-input').focus();
            }
            if(!token) document.getElementById('guest-name-input').focus();
        } else {
            alert(message);
        }
    }

    function submitJoinForm(e) {
        e.preventDefault();
        const guestName = document.getElementById('guest-name-input').value.trim();
        const password = document.getElementById('join-password-input').value.trim();
        const passwordGroup = document.getElementById('password-group');

        if (!guestName && !localStorage.getItem('token')) {
            alert("Please enter a name");
            return;
        }

        if (passwordGroup.style.display !== 'none' && !password) {
            alert("This room requires a password");
            return;
        }

        connectToRoom(currentRoomId, guestName, password);
    }


    function toggleChat() {
        if (elements.roomLayout) {
            elements.roomLayout.classList.toggle('chat-hidden');

            if (!elements.roomLayout.classList.contains('chat-hidden')) {
                elements.toggleChatBtn.classList.remove('has-unread');
                if(elements.toastContainer) elements.toastContainer.innerHTML = '';
            }

            setTimeout(() => window.dispatchEvent(new Event('resize')), 350);
        }
    }

    function showChatToast(data) {
        if (!elements.toastContainer) return;

        const toast = document.createElement('div');
        toast.className = 'video-toast';

        const avatarSrc = data.avatar || '/public/assets/placeholder.png';

        toast.innerHTML = `
            <img src="${avatarSrc}" class="toast-avatar" onerror="this.style.display='none'">
            <div class="toast-content">
                <span class="toast-user">${escapeHtml(data.username)}</span>
                <span class="toast-msg">${escapeHtml(data.message)}</span>
            </div>
        `;

        elements.toastContainer.appendChild(toast);

        setTimeout(() => {
            if (toast.parentElement) {
                toast.remove();
            }
        }, 5000);

        while (elements.toastContainer.children.length > 3) {
            elements.toastContainer.removeChild(elements.toastContainer.firstChild);
        }
    }

    function renderUsersList(users) {
        elements.usersList.innerHTML = users.map(user => `
            <div class="user-item">
                <div class="user-avatar">${user.avatar ? `<img src="${user.avatar}">` : user.username[0].toUpperCase()}</div>
                <span class="user-name">${escapeHtml(user.username)}</span>
                ${user.isHost ? '<span class="user-badge">HOST</span>' : ''}
            </div>
        `).join('');
    }

    function updateUsersList() {
        if(ws && ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify({ type: 'request_users' }));
    }

    function toggleUsersList() {
        const isVisible = elements.usersList.style.display !== 'none';
        elements.usersList.style.display = isVisible ? 'none' : 'block';
    }

    function addSystemMessage(text) {
        const div = document.createElement('div');
        div.className = 'chat-message system';
        div.innerHTML = `<div class="message-content">${escapeHtml(text)}</div>`;
        elements.chatMessages.appendChild(div);
        elements.chatMessages.scrollTop = elements.chatMessages.scrollHeight;

        if (elements.roomLayout && elements.roomLayout.classList.contains('chat-hidden')) {
            showSystemToast(text);
        }
    }

    function showSystemToast(text) {
        if (!elements.toastContainer) return;

        const toast = document.createElement('div');
        toast.className = 'video-toast system-toast';
        toast.innerHTML = `<span class="toast-msg">${escapeHtml(text)}</span>`;

        elements.toastContainer.appendChild(toast);

        setTimeout(() => toast.remove(), 4000);
    }

    function addChatMessage(data) {
        const time = new Date(data.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
        const div = document.createElement('div');
        div.className = 'chat-message';

        let avatarHtml;
        if (data.avatar) {
            avatarHtml = `<img src="${data.avatar}" alt="${data.username}" style="width:100%; height:100%; object-fit:cover; border-radius:50%;">`;
        } else {
            avatarHtml = data.username[0].toUpperCase();
        }

        div.innerHTML = `
            <div class="message-avatar">${avatarHtml}</div>
            <div class="message-body">
                <div class="message-header">
                    <span class="message-username">${escapeHtml(data.username)}</span>
                    <span class="message-time">${time}</span>
                </div>
                <div class="message-content">${escapeHtml(data.message)}</div>
            </div>
        `;
        elements.chatMessages.appendChild(div);
        elements.chatMessages.scrollTop = elements.chatMessages.scrollHeight;
    }

    function sendMessage(e) {
        e.preventDefault();
        const message = elements.chatInput.value.trim();
        if (!message) return;
        if(ws && ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify({ type: 'chat', message }));
        elements.chatInput.value = '';
    }

    function loadVideo(videoData) {
        if (!videoData || !videoData.videoData) return;
        const { url, type } = videoData.videoData;

        if (currentLoadedUrl === url) {
            if (videoData.currentTime !== undefined) syncVideo(videoData.currentTime, videoData.isPlaying);
            return;
        }
        currentLoadedUrl = url;

        if (window.AnimePlayer && typeof window.AnimePlayer.loadVideoFromRoom === 'function') {
            if(elements.loading) elements.loading.style.display = 'none';
            window.AnimePlayer.loadVideoFromRoom({
                url: url,
                type: type,
                subtitles: videoData.subtitles,
                malId: videoData.malId,
                episode: videoData.episode
            });
            setTimeout(() => {
                const newVideoElement = document.getElementById('player');
                if (newVideoElement) {
                    elements.video = newVideoElement;
                    attachVideoEventListeners(newVideoElement);
                    updatePlayPauseButton(!newVideoElement.paused);
                }
            }, 500);
        }
    }

    function getVideoElement() {
        if (window.AnimePlayer) return window.AnimePlayer.getVideoElement();
        return document.getElementById('player');
    }

    function syncVideo(currentTime, isPlaying) {
        const video = getVideoElement();
        if (!video) {
            console.warn('Cannot sync: video element not found');
            return;
        }

        const timeDiff = Math.abs(video.currentTime - currentTime);

        console.log('Syncing video:', {
            targetTime: currentTime,
            currentTime: video.currentTime,
            diff: timeDiff.toFixed(2) + 's',
            targetState: isPlaying ? 'playing' : 'paused',
            currentState: video.paused ? 'paused' : 'playing'
        });

        if (timeDiff > 0.5) {
            console.log('Time diff exceeds threshold, seeking to:', currentTime);
            video.currentTime = currentTime;
        }

        if (isPlaying && video.paused) {
            console.log('Starting playback...');
            video.play()
                .then(() => {
                    console.log('✓ Playback started');
                    updatePlayPauseButton(true);
                })
                .catch(err => {
                    console.error('✗ Playback failed:', err);
                    showPlaybackBlockedToast();
                });
        } else if (!isPlaying && !video.paused) {
            console.log('Pausing playback...');
            video.pause();
            updatePlayPauseButton(false);
        }
    }

    function sendSync() {
        const video = getVideoElement();
        if (!video) {
            console.warn('Cannot send sync: video element not found');
            return;
        }

        if (!ws || ws.readyState !== WebSocket.OPEN) {
            console.warn('Cannot send sync: WebSocket not connected');
            return;
        }

        const syncData = {
            type: 'sync',
            currentTime: video.currentTime,
            isPlaying: !video.paused
        };

        console.log('Sending sync:', syncData);
        ws.send(JSON.stringify(syncData));
    }

    function showPlaybackBlockedToast() {
        const toast = document.createElement('div');
        toast.className = 'playback-blocked-toast';
        toast.innerHTML = `
        <div style="display:flex; flex-direction:column; gap:8px; align-items:center;">
            <span>⚠️ Autoplay blocked by browser</span>
            <button onclick="this.parentElement.parentElement.remove(); getVideoElement()?.play();" 
                    style="background:white; color:#1a1a2e; border:none; padding:6px 12px; border-radius:6px; cursor:pointer; font-weight:600;">
                Click to Play
            </button>
        </div>
    `;
        toast.style.cssText = `
        position: fixed;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        background: rgba(251, 191, 36, 0.95);
        color: white;
        padding: 20px 30px;
        border-radius: 12px;
        font-size: 14px;
        font-weight: 500;
        z-index: 10000;
        box-shadow: 0 8px 24px rgba(0,0,0,0.4);
        animation: scaleIn 0.3s ease-out;
    `;

        document.body.appendChild(toast);

        setTimeout(() => {
            if (toast.parentElement) {
                toast.style.animation = 'fadeOut 0.3s ease-out';
                setTimeout(() => toast.remove(), 300);
            }
        }, 10000);
    }

    function updatePlayPauseButton(isPlaying) {
        const playBtn = document.getElementById('play-pause-btn');
        if (!playBtn) return;
        playBtn.innerHTML = isPlaying ?
            `<svg viewBox="0 0 24 24"><path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z"/></svg>` :
            `<svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>`;
    }

    function attachVideoEventListeners(video) {
        if(!video) return;
        video.addEventListener('play', () => updatePlayPauseButton(true));
        video.addEventListener('pause', () => updatePlayPauseButton(false));
        video.addEventListener('timeupdate', () => {
            if(elements.timeDisplay) elements.timeDisplay.textContent = formatTime(video.currentTime) + " / " + formatTime(video.duration);
            if(elements.progressPlayed) elements.progressPlayed.style.width = (video.currentTime/video.duration*100) + "%";
        });
        video.addEventListener('ended', () => {
            if (isHost) {
                console.log('Video ended. Checking queue...');
                setTimeout(() => {
                    playNextInQueue();
                }, 1000);
            }
        });
    }

    async function playNextInQueue() {
        if (currentQueue.length === 0) return;
        const nextItem = currentQueue[0];
        if (nextItem) {
            await window.playQueueItem(nextItem.uid);
        }
    }

    function formatTime(s) {
        if(isNaN(s)) return "0:00";
        const m = Math.floor(s/60), sec = Math.floor(s%60);
        return m + ":" + (sec<10?"0":"") + sec;
    }

    function leaveRoom() {
        if (ws) ws.close();
        if (hlsInstance) hlsInstance.destroy();
    }

    function openAnimeSearchModal() {
        elements.animeSearchModal.classList.add('show');
        elements.stepSearch.style.display = 'block';
        elements.stepConfig.style.display = 'none';
        setTimeout(() => elements.animeSearchInput.focus(), 100);
    }

    function closeAnimeSearchModal() {
        elements.animeSearchModal.classList.remove('show');
    }

    async function searchAnime() {
        const query = elements.animeSearchInput.value.trim();
        if (!query) return;
        elements.animeResults.innerHTML = '<div style="padding:20px;text-align:center;color:#888;">Searching...</div>';
        if (window.SearchManager) {
            await window.SearchManager.search(query, 'anime', elements.animeResults);
        } else {
            elements.animeResults.innerHTML = 'SearchManager not loaded';
        }
    }

    function escapeHtml(text) {
        if (!text) return '';
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }

    let permissionsModal = null;

    function initPermissionsUI() {
        if (!isHost) return;

        if (!permissionsModal) {
            permissionsModal = document.createElement('div');
            permissionsModal.className = 'modal-overlay';
            permissionsModal.id = 'permissions-modal';
            permissionsModal.innerHTML = `
            <div class="modal-content permissions-content">
                <button class="modal-close" onclick="closePermissionsModal()">✕</button>
                <h2 class="modal-title">Manage Permissions</h2>
                
                <div class="permissions-list" id="permissions-list">
                    <!-- Se llenará dinámicamente -->
                </div>

                <div class="banned-ips-section">
                    <h3 class="section-title">Banned IPs</h3>
                    <div id="banned-ips-list" class="banned-list">
                        <p class="empty-state">No banned users</p>
                    </div>
                </div>
            </div>
        `;
            document.body.appendChild(permissionsModal);
        }

        const headerRight = document.querySelector('.header-right');
        if (headerRight && !document.getElementById('permissions-btn')) {
            const permBtn = document.createElement('button');
            permBtn.id = 'permissions-btn';
            permBtn.className = 'btn-icon-glass';
            permBtn.title = 'Manage Permissions';
            permBtn.innerHTML = `
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                <rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
                <path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
            </svg>
        `;
            permBtn.onclick = openPermissionsModal;

            const searchBtn = document.getElementById('select-anime-btn');
            if (searchBtn) {
                headerRight.insertBefore(permBtn, searchBtn);
            } else {
                headerRight.appendChild(permBtn);
            }
        }
    }

    function openPermissionsModal() {
        if (!permissionsModal || !isHost) return;

        updatePermissionsList();
        permissionsModal.classList.add('show');
    }

    window.closePermissionsModal = function() {
        if (permissionsModal) {
            permissionsModal.classList.remove('show');
        }
    };

    function updatePermissionsList() {
        const list = document.getElementById('permissions-list');
        if (!list) return;

        const room = getCurrentRoomData();

        if (!room || !room.users) {
            list.innerHTML = '<p class="empty-state">No active users</p>';
            return;
        }

        list.innerHTML = room.users
            .filter(u => !u.isHost)
            .map(user => createPermissionCard(user))
            .join('');
    }

    function createPermissionCard(user) {
        const perms = user.permissions || { canControl: false, canManageQueue: false };

        return `
        <div class="permission-card">
            <div class="user-info-section">
                <div class="user-avatar-small">
                    ${user.avatar ? `<img src="${user.avatar}">` : user.username[0].toUpperCase()}
                </div>
                <div class="user-details">
                    <span class="user-name-text">${escapeHtml(user.username)}</span>
                    ${user.isGuest ? '<span class="guest-badge">Guest</span>' : ''}
                </div>
            </div>

            <div class="permissions-toggles">
                <label class="perm-toggle" for="perm-ctrl-${user.id}">
                    <input type="checkbox" 
                           id="perm-ctrl-${user.id}"
                           data-user-id="${user.id}" 
                           ${perms.canControl ? 'checked' : ''} 
                           onchange="togglePermission('${user.id}', 'canControl', this.checked)">
                    <span class="perm-label">
                        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                            <polygon points="5 3 19 12 5 21 5 3"></polygon>
                        </svg>
                        Playback Control
                    </span>
                </label>

                <label class="perm-toggle" for="perm-queue-${user.id}">
                    <input type="checkbox" 
                           id="perm-queue-${user.id}"
                           data-user-id="${user.id}" 
                           ${perms.canManageQueue ? 'checked' : ''} 
                           onchange="togglePermission('${user.id}', 'canManageQueue', this.checked)">
                    <span class="perm-label">
                        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                            <line x1="8" y1="6" x2="21" y2="6"></line>
                            <line x1="8" y1="12" x2="21" y2="12"></line>
                            <line x1="8" y1="18" x2="21" y2="18"></line>
                            <line x1="3" y1="6" x2="3.01" y2="6"></line>
                            <line x1="3" y1="12" x2="3.01" y2="12"></line>
                            <line x1="3" y1="18" x2="3.01" y2="18"></line>
                        </svg>
                        Queue Management
                    </span>
                </label>
            </div>

            <button class="ban-btn" onclick="banUser('${user.id}')" title="Ban User">
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                    <circle cx="12" cy="12" r="10"></circle>
                    <line x1="4.93" y1="4.93" x2="19.07" y2="19.07"></line>
                </svg>
                Ban
            </button>
        </div>
        `;
    }

    window.togglePermission = function(userId, permission, value) {
        if (!ws || ws.readyState !== WebSocket.OPEN) return;

        console.log(`Toggling permission ${permission} to ${value} for user ${userId}`);

        const permissions = {};
        permissions[permission] = value;

        ws.send(JSON.stringify({
            type: 'update_permissions',
            targetUserId: userId,
            permissions
        }));

        showSystemToast(`Permission ${value ? 'granted' : 'revoked'}`);
    };

    window.banUser = function(userId) {
        const room = getCurrentRoomData();
        const user = room?.users?.find(u => u.id === userId);

        if (!user) return;

        const confirmed = confirm(`Ban ${user.username} from this room? They won't be able to rejoin.`);
        if (!confirmed) return;

        if (ws && ws.readyState === WebSocket.OPEN) {
            ws.send(JSON.stringify({
                type: 'ban_user',
                targetUserId: userId
            }));
        }

        showSystemToast(`${user.username} has been banned`);
        setTimeout(() => updatePermissionsList(), 500);
    };

    function getCurrentRoomData() {
        return window.__currentRoomData || null;
    }

    function saveRoomData(roomData) {
        window.__currentRoomData = roomData;

        if (roomData.users && currentUserId) {
            const currentUser = roomData.users.find(u => u.id === currentUserId);
            if (currentUser && currentUser.permissions) {
                window.__userPermissions = currentUser.permissions;

                console.log('Permissions updated for current user:', window.__userPermissions);
            }
        }
    }

    const originalHandleMessage = handleWebSocketMessage;
    handleWebSocketMessage = function(data) {
        switch(data.type) {
            case 'permissions_updated':
                saveRoomData({ users: data.users });

                const updatedUser = data.users.find(u => u.id === currentUserId);
                if (updatedUser) {
                    window.__userPermissions = updatedUser.permissions || {
                        canControl: false,
                        canManageQueue: false
                    };

                    console.log('My permissions updated:', window.__userPermissions);

                    const canManageQueue = isHost || (window.__userPermissions?.canManageQueue || false);

                    if (elements.selectAnimeBtn) {
                        elements.selectAnimeBtn.style.display = canManageQueue ? 'flex' : 'none';
                    }

                    if (elements.hostControls) {
                        elements.hostControls.style.display = canManageQueue ? 'flex' : 'none';
                    }

                    if (canManageQueue) {
                        initGlobalControls();
                        populateQuickControls();
                    }

                    if (!canManageQueue && elements.animeSearchModal && elements.animeSearchModal.classList.contains('show')) {
                        closeAnimeSearchModal();
                        showSystemToast("Permissions updated: Access revoked");
                    }

                    if (currentQueue && currentQueue.length > 0) {
                        console.log('Forcing queue re-render due to permission change');
                        renderQueue(currentQueue);
                    }
                }

                if (permissionsModal && permissionsModal.classList.contains('show')) {
                    updatePermissionsList();
                }

                renderUsersList(data.users);
                break;

            case 'banned':
                alert(data.message || 'You have been banned from this room');
                window.location.href = '/anime';
                break;

            case 'users_update':
                saveRoomData({ users: data.users });
                break;

            default:
                originalHandleMessage(data);
        }
    };

    const originalUpdateRoomUI = updateRoomUI;
    updateRoomUI = function(room) {
        originalUpdateRoomUI(room);

        if (isHost) {
            initPermissionsUI();
        }
    };

    return { init };
})();

document.addEventListener('DOMContentLoaded', () => RoomsApp.init());