import { EVENTS, OFFICIAL_LANDING_PAGE_URL } from './shared/constants.js';
import { BLACKLIST_DOMAINS } from './shared/blacklist.js';
import { getAvatarForName, generateUsername, USERNAME_ADJECTIVES, USERNAME_NOUNS } from './shared/names.js';
import { loadLocale, translateDOM, getMessage, getSystemLanguage } from './i18n.js';


const elements = {
    tabs: document.querySelectorAll('.tabs .tab-btn'),
    contents: document.querySelectorAll('.tab-content'),
    copyInvite: document.getElementById('copyInvite'),
    targetTab: document.getElementById('targetTab'),
    forceSyncBtn: document.getElementById('forceSyncBtn'),
    forceSyncMode: document.getElementById('forceSyncMode'),
    peerList: document.getElementById('peerList'),
    logList: document.getElementById('logList'),
    clearLogs: document.getElementById('clearLogs'),
    connDot: document.getElementById('connDot'),
    connText: document.getElementById('connText'),
    serverUrl: document.getElementById('serverUrl'),
    serverOfficial: document.getElementById('serverOfficial'),
    serverCustom: document.getElementById('serverCustom'),
    roomId: document.getElementById('roomId'),
    password: document.getElementById('password'),
    username: document.getElementById('username'),
    joinBtn: document.getElementById('joinBtn'),
    leaveBtn: document.getElementById('leaveBtn'),
    roomInfo: document.getElementById('roomInfo'),
    inviteLink: document.getElementById('inviteLink'),
    filterNoise: document.getElementById('filterNoise'),
    regenId: document.getElementById('regenId'),
    lastActionCard: document.getElementById('lastActionCard'),
    historyList: document.getElementById('historyList'),
    copyLogs: document.getElementById('copyLogs'),
    createRoomBtn: document.getElementById('createRoomBtn'),
    publicRooms: document.getElementById('publicRooms'),
    refreshRooms: document.getElementById('refreshRooms'),
    roomError: document.getElementById('roomError'),
    retryBtn: document.getElementById('retryBtn'),
    sectionJoin: document.getElementById('section-join'),
    sectionActive: document.getElementById('section-active'),
    activeRoomId: document.getElementById('activeRoomId'),
    activeServer: document.getElementById('activeServer'),
    peerListSync: document.getElementById('peerListSync'),
    videoDebug: document.getElementById('videoDebug'),
    playBtn: document.getElementById('playBtn'),
    pauseBtn: document.getElementById('pauseBtn'),
    autoSyncNextEpisode: document.getElementById('autoSyncNextEpisode'),
    episodeLobbyCard: document.getElementById('episodeLobbyCard'),
    lobbyTitle: document.getElementById('lobbyTitle'),
    lobbyPeerStatus: document.getElementById('lobbyPeerStatus'),
    browserNotifications: document.getElementById('browserNotifications'),
    autoCopyInvite: document.getElementById('autoCopyInvite'),
    syncTabCopyInvite: document.getElementById('syncTabCopyInvite'),
    cancelLobbyBtn: document.getElementById('cancelLobbyBtn'),
    langSelector: document.getElementById('langSelector')
};

let localPeerId = null;
let lastPeersJson = null;
let lastKnownPeers = [];
let isDevTabVisible = false;
let reconnectSlowMode = false;
let joinBtnTimeout = null;
let forceSyncResetTimer = null;
let popupIntervals = [];
let populateTabsToken = null;
let errorToken = 0;
let forceSyncDone = false;
let connectionErrorTimer = null;
let pendingConnectionErrorMsg = null;
let roomListRefreshTimer = null;
let roomListRefreshInterval = null;
const ROOM_LIST_REFRESH_COOLDOWN_MS = 11000;

// --- Helpers ---
function clearConnectionErrorTimer() {
    if (connectionErrorTimer) {
        clearTimeout(connectionErrorTimer);
        connectionErrorTimer = null;
    }
    pendingConnectionErrorMsg = null;
}

function setRoomRefreshCooldown() {
    if (roomListRefreshTimer) clearTimeout(roomListRefreshTimer);
    if (roomListRefreshInterval) clearInterval(roomListRefreshInterval);
    const originalLabel = getMessage('BTN_REFRESH');
    const updateLabel = () => {
        const secondsLeft = Math.max(1, Math.ceil((cooldownEndsAt - Date.now()) / 1000));
        elements.refreshRooms.textContent = getMessage('BTN_REFRESH_COOLDOWN', { seconds: secondsLeft });
        elements.refreshRooms.title = getMessage('BTN_REFRESH_COOLDOWN_TOOLTIP', { seconds: secondsLeft });
    };

    const cooldownEndsAt = Date.now() + ROOM_LIST_REFRESH_COOLDOWN_MS;
    elements.refreshRooms.disabled = true;
    updateLabel();

    roomListRefreshInterval = setInterval(updateLabel, 250);
    roomListRefreshTimer = setTimeout(() => {
        elements.refreshRooms.disabled = false;
        elements.refreshRooms.textContent = originalLabel;
        elements.refreshRooms.title = getMessage('BTN_REFRESH_TOOLTIP');
        clearInterval(roomListRefreshInterval);
        roomListRefreshInterval = null;
        roomListRefreshTimer = null;
    }, ROOM_LIST_REFRESH_COOLDOWN_MS);
}

// --- Initialization ---
async function init() {
    // Load per-device settings (local) + synced preferences (sync)
    const [localData, syncData] = await Promise.all([
        chrome.storage.local.get(['serverUrl', 'useCustomServer', 'roomId', 'password', 'username']),
        chrome.storage.sync.get(['filterNoise', 'autoSyncNextEpisode', 'forceSyncMode', 'browserNotifications', 'autoCopyInvite', 'locale'])
    ]);

    // Migrate from sync → local for existing users
    const hadLocalData = !!(localData.username || localData.roomId);
    let syncHadData = false;
    if (!hadLocalData) {
        const oldSync = await chrome.storage.sync.get(['serverUrl', 'useCustomServer', 'roomId', 'password', 'username']);
        syncHadData = !!(oldSync.username || oldSync.roomId);
        if (syncHadData) {
            localData.serverUrl = oldSync.serverUrl;
            localData.useCustomServer = oldSync.useCustomServer;
            localData.roomId = oldSync.roomId;
            localData.password = oldSync.password;
            localData.username = oldSync.username;
        }
    }

    let activeLang = syncData.locale;
    if (!activeLang) {
        activeLang = getSystemLanguage();
        chrome.storage.sync.set({ locale: activeLang });
    }

    await loadLocale(activeLang);
    translateDOM();
    
    if (elements.langSelector) elements.langSelector.value = activeLang;
    
    let username = localData.username;
    if (!username) {
        username = generateUsername();
        await chrome.storage.local.set({ username });
    }
    if (syncHadData) {
        // Persist migrated room data to local (one-time migration)
        await chrome.storage.local.set({
            serverUrl: localData.serverUrl || '',
            useCustomServer: localData.useCustomServer || false,
            roomId: localData.roomId || '',
            password: localData.password || '',
            username
        });
    }
    
    elements.serverUrl.value = localData.serverUrl || '';
    elements.roomId.value = localData.roomId || '';
    elements.password.value = localData.password || '';
    elements.username.value = username;
    if (elements.filterNoise) elements.filterNoise.checked = syncData.filterNoise !== false;
    if (elements.autoSyncNextEpisode) elements.autoSyncNextEpisode.checked = syncData.autoSyncNextEpisode !== false;
    if (elements.forceSyncMode) elements.forceSyncMode.value = syncData.forceSyncMode || 'jump-to-others';
    if (elements.browserNotifications) elements.browserNotifications.checked = syncData.browserNotifications === true;
    if (elements.autoCopyInvite) elements.autoCopyInvite.checked = syncData.autoCopyInvite !== false;
    
    // Set Version Info
    const versionTxt = `v${chrome.runtime.getManifest().version}`;
    const versionEl = document.getElementById('appVersion');
    if (versionEl) versionEl.textContent = versionTxt;
    const popupVerEl = document.getElementById('popupVersion');
    if (popupVerEl) popupVerEl.textContent = versionTxt;

    if (localData.useCustomServer) {
        setServerMode(true);
    } else {
        setServerMode(false);
    }

    toggleUIState(!!localData.roomId);
    updateUI(localData.roomId, localData.password, localData.useCustomServer, localData.serverUrl);
    refreshLogs();
    refreshHistory();

    // Default connection status (localized) before async check
    applyConnectionStatus('disconnected');

    // Initial Status Check
    chrome.runtime.sendMessage({ type: 'GET_STATUS' }, async (res) => {
        if (chrome.runtime.lastError) {
            console.warn('[Popup] Background not responding:', chrome.runtime.lastError.message);
            await populateTabs();
            return;
        }
        if (res) {
            localPeerId = res.peerId;
            reconnectSlowMode = res.reconnectSlowMode || false;
            applyConnectionStatus(res.status);
            updatePeerList(res.peers);
            lastKnownPeers = res.peers || [];
            if (res.lastActionState) updateLastActionUI(res.lastActionState, res.peers);
            
            // Populate Tabs using the background's targetTabId
            await populateTabs(res.peers, res.targetTabId);

            // Render lobby status if active
            if (res.episodeLobby) updateLobbyUI(res.episodeLobby, res.peers);
        } else {
            await populateTabs();
        }
    });

    // Check for invite link on landing page
    checkInviteLink();

    // Initialize public rooms placeholder
    renderEmpty(elements.publicRooms, 'rooms');

    // Debug Info Refresh
    popupIntervals.push(setInterval(refreshDebugInfo, 2000));

    // Show onboarding on first visit
    chrome.storage.sync.get(['onboardingComplete'], (data) => {
        if (!data.onboardingComplete) showOnboarding();
    });
}

// --- UI Logic ---
function toggleUIState(inRoom) {
    if (elements.sectionJoin) elements.sectionJoin.style.display = inRoom ? 'none' : 'block';
    if (elements.sectionActive) elements.sectionActive.style.display = inRoom ? 'block' : 'none';
    if (elements.peerListSync) elements.peerListSync.style.display = inRoom ? 'block' : 'none';
    
    const syncActive = document.getElementById('sync-active');
    const syncInactive = document.getElementById('sync-inactive');
    if (syncActive) syncActive.style.display = inRoom ? 'block' : 'none';
    if (syncInactive) syncInactive.style.display = inRoom ? 'none' : 'block';
}

function updateUI(roomId, password, useCustomServer = false, serverUrl = '') {
    const inRoom = !!roomId;
    toggleUIState(inRoom);
    if (inRoom) {
        let invite = `${OFFICIAL_LANDING_PAGE_URL}/join.html#join:${roomId}:${password}`;
        if (useCustomServer) {
            const encodedUrl = encodeURIComponent(serverUrl || '');
            invite += `:1:${encodedUrl}`;
        }
        elements.inviteLink.value = invite;
        
        if (window.justCreatedRoom) {
            window.justCreatedRoom = false;
            if (elements.autoCopyInvite && elements.autoCopyInvite.checked && elements.copyInvite) {
                elements.copyInvite.click();
            }
        }

        if (elements.activeRoomId) elements.activeRoomId.textContent = roomId;
        if (elements.activeServer) {
            elements.activeServer.textContent = useCustomServer ? (serverUrl || getMessage('LABEL_CUSTOM_SERVER')) : getMessage('ACTIVE_SERVER_OFFICIAL');
            elements.activeServer.title = useCustomServer ? (serverUrl || '') : 'syncserver.koalastuff.net';
        }
    } else {
        updatePeerList([]);
        if (elements.inviteLink) elements.inviteLink.value = '';
        if (elements.activeRoomId) elements.activeRoomId.textContent = '';
        if (elements.activeServer) {
            elements.activeServer.textContent = '';
            elements.activeServer.title = '';
        }
        lastKnownPeers = [];
    }
}

function updateLastActionUI(state, peers) {
    if (!state || !state.action) {
        elements.lastActionCard.replaceChildren();
        const el = document.createElement('div');
        el.style.cssText = 'text-align:center; color: var(--text-muted); font-size: 10px;';
        el.textContent = getMessage('NO_RECENT_COMMANDS');
        elements.lastActionCard.appendChild(el);
        return;
    }

    const safePeers = peers || [];
    const safeAcks = state.acks || [];

    const actionNames = {
        'play': getMessage('BTN_PLAY').replace('▶ ', '').toUpperCase(),
        'pause': getMessage('BTN_PAUSE').replace('⏸ ', '').toUpperCase(),
        'seek': getMessage('NOTIF_SEEK').toUpperCase(),
        'force_sync_prepare': getMessage('BTN_STATE_SYNCING').toUpperCase(),
        'force_sync_execute': getMessage('BTN_STATE_SYNCED').toUpperCase()
    };

    let senderName = state.senderId === 'You' ? (getMessage('LABEL_YOU') || 'YOU') : state.senderId;
    const senderPeer = safePeers.find(p => (p.peerId || p) === state.senderId);
    if (senderPeer && senderPeer.username) senderName = senderPeer.username;

    const ts = state.timestamp ? new Date(state.timestamp) : new Date();
    const timeStr = isNaN(ts.getTime()) ? '--:--' : ts.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });

    elements.lastActionCard.innerHTML = '';

    const header = document.createElement('div');
    header.style.cssText = 'display:flex; justify-content:space-between; margin-bottom:6px; align-items:baseline;';
    
    const actionSpan = document.createElement('span');
    actionSpan.style.cssText = 'font-weight:700; color:var(--accent); font-size:11px;';
    actionSpan.textContent = actionNames[state.action] || state.action.toUpperCase();
    
    const infoSpan = document.createElement('span');
    infoSpan.style.cssText = 'font-size:9px; color:var(--text-muted);';
    infoSpan.textContent = `${senderName} @ ${timeStr}`;
    
    header.appendChild(actionSpan);
    header.appendChild(infoSpan);
    elements.lastActionCard.appendChild(header);

    if (state.targetTime !== undefined && state.action === 'seek') {
        const timeInfo = document.createElement('div');
        timeInfo.style.cssText = 'font-size:9px; color:var(--text-muted); margin-top:4px;';
        timeInfo.textContent = `Target: ${formatTime(state.targetTime)}`;
        elements.lastActionCard.appendChild(timeInfo);
    }

    if (state.targetTime !== undefined && state.action.includes('force_sync')) {
        const timeInfo = document.createElement('div');
        timeInfo.style.cssText = 'font-size:9px; color:var(--text-muted); margin-top:4px;';
        timeInfo.textContent = `Sync to: ${formatTime(state.targetTime)}`;
        elements.lastActionCard.appendChild(timeInfo);
    }

    const grid = document.createElement('div');
    grid.style.cssText = 'display:grid; grid-template-columns: repeat(auto-fill, minmax(36px, 1fr)); gap: 5px;';

    safePeers.forEach(peer => {
        const pId = typeof peer === 'object' ? peer.peerId : peer;
        if (pId === localPeerId) return;
        const pName = (typeof peer === 'object' && peer.username) ? peer.username : pId.substring(0, 4);
        const isAcked = safeAcks.includes(pId) || pId === state.senderId;
        const color = isAcked ? 'var(--success)' : '#475569';
        const icon = isAcked ? '✓' : '...';
        const avatar = getAvatarForName(pName);
        
        const peerItem = document.createElement('div');
        peerItem.title = pName;
        peerItem.style.cssText = `display:flex; flex-direction:column; align-items:center; opacity: ${isAcked ? 1 : 0.6};`;
        
        const dot = document.createElement('div');
        dot.style.cssText = `width:18px; height:18px; border-radius:50%; background:${color}; color:white; display:flex; align-items:center; justify-content:center; font-size:9px; font-weight:bold; margin-bottom:1px;`;
        dot.textContent = icon;
        
        const nameSpan = document.createElement('span');
        nameSpan.style.cssText = 'font-size:7px; color:var(--text-muted); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:36px;';
        nameSpan.textContent = `${avatar} ${pName}`;
        
        peerItem.appendChild(dot);
        peerItem.appendChild(nameSpan);
        grid.appendChild(peerItem);
    });

    elements.lastActionCard.appendChild(grid);
}

function formatTime(seconds) {
    if (seconds === null || seconds === undefined || isNaN(seconds) || seconds < 0) return '--:--';
    const h = Math.floor(seconds / 3600);
    const m = Math.floor((seconds % 3600) / 60);
    const s = Math.floor(seconds % 60);
    if (h > 0) return `${h}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
    return `${m}:${String(s).padStart(2, '0')}`;
}

function getVolumeIcon(volume, muted) {
    if (muted || volume === 0) return '🔇';
    if (volume < 0.33) return '🔈';
    if (volume < 0.66) return '🔉';
    return '🔊';
}

let activePeers = [];
let interpolationInterval = null;

function stopInterpolation() {
    if (interpolationInterval) {
        clearInterval(interpolationInterval);
        interpolationInterval = null;
    }
}

function startInterpolation() {
    if (interpolationInterval) return;
    interpolationInterval = setInterval(() => {
        const timeElements = document.querySelectorAll('.peer-time-display');
        timeElements.forEach(el => {
            const peerId = el.dataset.peerId;
            const peer = activePeers.find(p => p.peerId === peerId);
            if (peer && peer.playbackState === 'playing' && peer.currentTime != null && peer.lastHeartbeat) {
                const elapsed = (Date.now() - peer.lastHeartbeat) / 1000;
                if (elapsed < 45) {
                    el.textContent = formatTime(peer.currentTime + elapsed);
                }
            }
        });
    }, 1000);
}

function renderEmpty(container, type) {
    const states = {
        peers: { icon: '\u{1F465}', title: getMessage('EMPTY_PEERS_TITLE'), hint: getMessage('EMPTY_PEERS_HINT') },
        history: { icon: '\u{1F4CB}', title: getMessage('EMPTY_HISTORY_TITLE'), hint: getMessage('EMPTY_HISTORY_HINT') },
        logs: { icon: '\u{1F4DD}', title: getMessage('EMPTY_LOGS_TITLE'), hint: getMessage('EMPTY_LOGS_HINT') },
        rooms: { icon: '\u{1F50D}', title: getMessage('EMPTY_ROOMS_TITLE'), hint: getMessage('EMPTY_ROOMS_HINT') }
    };
    const state = states[type] || { icon: '', title: '', hint: '' };
    const wrapper = document.createElement('div');
    wrapper.style.cssText = 'text-align:center; padding:16px 8px; color:var(--text-muted);';
    const iconDiv = document.createElement('div');
    iconDiv.style.cssText = 'font-size:24px; margin-bottom:6px;';
    iconDiv.textContent = state.icon;
    const titleDiv = document.createElement('div');
    titleDiv.style.cssText = 'font-size:12px; font-weight:600; margin-bottom:4px;';
    titleDiv.textContent = state.title;
    const hintDiv = document.createElement('div');
    hintDiv.style.cssText = 'font-size:10px; opacity:0.7;';
    hintDiv.textContent = state.hint;
    wrapper.appendChild(iconDiv);
    wrapper.appendChild(titleDiv);
    wrapper.appendChild(hintDiv);
    container.replaceChildren(wrapper);
}

function updatePeerList(peers) {
    if (!peers) return;
    activePeers = peers;
    if (peers.length === 0) {
        stopInterpolation();
    } else if (!interpolationInterval) {
        startInterpolation();
    }
    
    // UI Throttle: Only re-render if the peer state actually changed (excluding time interpolation)
    const stateToHash = peers.map(p => ({
        id: p.peerId,
        user: p.username,
        tab: p.tabTitle,
        media: p.mediaTitle,
        state: p.playbackState,
        vol: p.volume,
        muted: p.muted
    }));
    const currentPeersJson = JSON.stringify(stateToHash);
    if (currentPeersJson === lastPeersJson) return;
    lastPeersJson = currentPeersJson;

    const renderPeers = (container) => {
        container.innerHTML = '';
        if (peers.length === 0) {
            renderEmpty(container, 'peers');
            return;
        }

        peers.forEach(p => {
            const pId = typeof p === 'object' ? p.peerId : p;
            const pUsername = (typeof p === 'object' && p.username) ? p.username : '';
            const pTabTitle = (typeof p === 'object' && p.tabTitle) ? p.tabTitle : '';

            const peerItem = document.createElement('div');
            peerItem.className = 'peer-item';
            peerItem.style.cssText = 'position:relative; display:block; padding: 8px 0; border-bottom: 1px solid rgba(255,255,255,0.05);';

            const header = document.createElement('div');
            header.style.cssText = 'display:flex; justify-content:space-between; align-items:center; padding-right: 24px;';

            const nameSpan = document.createElement('span');
            nameSpan.style.cssText = 'display: inline-flex; align-items: center; max-width: 200px; overflow: hidden; white-space: nowrap;';
            const avatar = getAvatarForName(pUsername || pId);
            if (pUsername) {
                const u = document.createElement('span');
                u.style.cssText = 'font-weight:600; color:white; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 120px; display: inline-block;';
                u.textContent = `${avatar} ${pUsername}`;
                const i = document.createElement('span');
                i.style.cssText = 'font-size:10px; opacity:0.6; font-style:italic; white-space: nowrap; flex-shrink: 0;';
                i.textContent = ` (${pId})`;
                nameSpan.appendChild(u);
                nameSpan.appendChild(i);
            } else {
                nameSpan.style.fontWeight = '600';
                nameSpan.style.cssText = 'white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 170px;';
                nameSpan.textContent = `${avatar} ${pId}`;
            }

            header.appendChild(nameSpan);

            // Volume Icon (Top Right)
            if (p.volume !== undefined && p.volume !== null) {
                const volIcon = document.createElement('div');
                volIcon.style.cssText = 'position:absolute; top:8px; right:0; cursor:help; font-size:14px;';
                volIcon.textContent = getVolumeIcon(p.volume, p.muted);
                volIcon.title = p.muted ? 'Muted' : `Volume: ${Math.round(p.volume * 100)}%`;
                peerItem.appendChild(volIcon);
            }

            if (pId === localPeerId) {
                const you = document.createElement('span');
                you.style.cssText = 'font-size:10px; color:var(--accent); font-weight:bold;';
                you.textContent = getMessage('LABEL_YOU') || 'YOU';
                header.appendChild(you);
            }

            peerItem.appendChild(header);

            // Media Info
            if (p.mediaTitle) {
                const mediaDiv = document.createElement('div');
                mediaDiv.style.cssText = 'font-size:11px; color:var(--star); font-weight: 600; margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 280px;';
                mediaDiv.textContent = `🎬 ${p.mediaTitle}`;
                peerItem.appendChild(mediaDiv);
            }

            // Status Line (Play/Pause + Time)
            const statusLine = document.createElement('div');
            statusLine.style.cssText = 'display:flex; align-items:center; gap:8px; margin-top:4px;';

            if (p.playbackState) {
                const stateIcon = document.createElement('span');
                stateIcon.style.fontSize = '10px';
                if (p.playbackState === 'playing') {
                    stateIcon.textContent = '▶';
                    stateIcon.style.color = 'var(--success)';
                } else {
                    stateIcon.textContent = '⏸';
                    stateIcon.style.color = 'var(--error)';
                }
                statusLine.appendChild(stateIcon);
            }

            if (p.currentTime !== undefined && p.currentTime !== null) {
                const timeSpan = document.createElement('span');
                timeSpan.className = 'peer-time-display';
                timeSpan.dataset.peerId = pId;
                timeSpan.style.cssText = 'font-size:11px; font-family:monospace; color:var(--text-muted);';
                
                let displayTime = p.currentTime;
                if (p.playbackState === 'playing' && p.lastHeartbeat && p.currentTime != null) {
                    const elapsed = (Date.now() - p.lastHeartbeat) / 1000;
                    if (elapsed < 45) {
                        displayTime += elapsed;
                    }
                }
                timeSpan.textContent = formatTime(displayTime);
                statusLine.appendChild(timeSpan);
            }

            if (pTabTitle) {
                const titleDiv = document.createElement('span');
                titleDiv.style.cssText = 'font-size:10px; color:var(--text-muted); opacity: 0.6; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1; text-align: right;';
                titleDiv.textContent = pTabTitle;
                statusLine.appendChild(titleDiv);
            }

            peerItem.appendChild(statusLine);
            container.appendChild(peerItem);
        });
    };

    if (elements.peerList) renderPeers(elements.peerList);
    if (elements.peerListSync) renderPeers(elements.peerListSync);

    // Re-populate tabs to update Star Matching when peers change
    populateTabs(peers);
}

function detectPeerChanges(newPeers) {
    const oldIds = new Set(lastKnownPeers.map(p => p.peerId || p));
    const newIds = new Set(newPeers.map(p => p.peerId || p));

    for (const peer of newPeers) {
        const id = peer.peerId || peer;
        if (!oldIds.has(id)) {
            const name = peer.username || id.substring(0, 4);
            showToast(getMessage('TOAST_PEER_JOINED', { name }), 'success');
        }
    }

    for (const oldPeer of lastKnownPeers) {
        const id = oldPeer.peerId || oldPeer;
        if (!newIds.has(id)) {
            const name = oldPeer.username || id.substring(0, 4);
            showToast(getMessage('TOAST_PEER_LEFT', { name }), 'info');
        }
    }

    lastKnownPeers = newPeers;
}

async function populateTabs(providedPeers = null, providedTargetTabId = null) {
    const token = {};
    populateTabsToken = token;

    const data = await chrome.storage.sync.get(['filterNoise']);
    const isFilterActive = data.filterNoise !== false;
    
    let currentTargetTabId = providedTargetTabId;
    if (currentTargetTabId === null) {
        const status = await new Promise(r => chrome.runtime.sendMessage({ type: 'GET_STATUS' }, r));
        if (chrome.runtime.lastError) {
            if (populateTabsToken !== token) return;
            currentTargetTabId = null;
        } else {
            currentTargetTabId = status?.targetTabId;
        }
    }
 
    let peerIds = providedPeers;
    if (!peerIds) {
        const status = await new Promise(r => chrome.runtime.sendMessage({ type: 'GET_STATUS' }, r));
        if (chrome.runtime.lastError) {
            if (populateTabsToken !== token) return;
            peerIds = [];
        } else {
            peerIds = status?.peers || [];
        }
    }

    let tabs = [];
    try {
        tabs = await chrome.tabs.query({});
    } catch (e) {
        console.warn('[Popup] tabs.query failed:', e.message);
        if (populateTabsToken !== token) return;
    }
    
    if (!elements.targetTab) return;
    if (populateTabsToken !== token) return;
    while (elements.targetTab.options.length > 1) {
        elements.targetTab.remove(1);
    }

    const filteredTabs = tabs.filter(tab => {
        if (!tab.url || tab.url.startsWith('chrome://')) return false;
        if (isFilterActive && tab.id !== parseInt(currentTargetTabId)) {
            const urlStr = tab.url.toLowerCase();
            if (BLACKLIST_DOMAINS.some(d => {
                const domain = d.toLowerCase();
                try {
                    const hostname = new URL(tab.url).hostname.toLowerCase();
                    if (domain.endsWith('.')) return hostname.startsWith(domain) || hostname.includes('.' + domain);
                    if (domain.includes('.')) return hostname === domain || hostname.endsWith('.' + domain);
                } catch {
                    /* ignore invalid URLs */
                }
                return urlStr.includes(domain);
            })) return false;
        }
        return true;
    });

    // Smart Matching Logic — exclude own tabTitle to prevent self-match (computed once)
    const cleanTitle = (rawTitle) => {
        if (!rawTitle) return '';
        return rawTitle
            .replace(/(?:\s*[-\|•]\s*(?:YouTube|Twitch|Jellyfin|Emby|Netflix|Vimeo|Dailymotion).*)$/i, '')
            .replace(/^(?:Netflix|Twitch|YouTube|Emby|Jellyfin)\s*[-\|•]\s*/i, '')
            .trim();
    };

    const peerTitles = peerIds
        .filter(p => (typeof p === 'object' ? p.peerId : p) !== localPeerId)
        .map(p => (typeof p === 'object' ? p.tabTitle : null))
        .filter(t => t && t.length > 3)
        .map(t => cleanTitle(t).toLowerCase())
        .filter(t => t.length > 3);

    filteredTabs.forEach(tab => {
        const option = document.createElement('option');
        option.value = tab.id;
        const rawTitle = (tab.title || 'Loading...');
        const title = cleanTitle(rawTitle).toLowerCase();
        
        const isMatch = title.length > 3 && peerTitles.some(pt => {
            return title.includes(pt) || pt.includes(title);
        });

        let label = rawTitle.substring(0, 45) + (rawTitle.length > 45 ? '...' : '');
        if (isMatch) {
            label = `⭐ MATCH: ${label}`;
            option.style.fontWeight = 'bold';
            option.style.color = 'var(--star)';
        }
        
        if (tab.audible) {
            label = `[🎬] ${label}`;
        }
        
        option.textContent = label;
        option.dataset.originalTitle = tab.title;
        elements.targetTab.appendChild(option);
    });

    // Sort: 1. Current tab first, 2. Matches, 3. Rest alphabetically
    const options = Array.from(elements.targetTab.options);
    const placeholder = options.shift();
    const currentTabId = providedTargetTabId ? parseInt(providedTargetTabId) : null;

    options.sort((a, b) => {
        const aId = parseInt(a.value);
        const bId = parseInt(b.value);

        if (aId === currentTabId) return -1;
        if (bId === currentTabId) return 1;

        const aMatch = a.textContent.includes('⭐');
        const bMatch = b.textContent.includes('⭐');
        if (aMatch && !bMatch) return -1;
        if (!aMatch && bMatch) return 1;

        return a.textContent.localeCompare(b.textContent);
    });
    elements.targetTab.innerHTML = '';
    elements.targetTab.appendChild(placeholder);
    options.forEach(opt => elements.targetTab.appendChild(opt));

    if (currentTargetTabId) {
        elements.targetTab.value = currentTargetTabId;
    } else {
        const matchOpt = options.find(o => o.textContent.includes('⭐ MATCH:'));
        if (matchOpt && elements.targetTab.options.length > 1) {
            elements.targetTab.value = matchOpt.value;
            const tabTitle = matchOpt.dataset.originalTitle || null;
            chrome.runtime.sendMessage({ type: 'SET_TARGET_TAB', tabId: parseInt(matchOpt.value), tabTitle });
        }
    }
}

function applyConnectionStatus(status) {
    const connected = status === 'connected';
    const connecting = status === 'connecting';
    const reconnecting = status === 'reconnecting';

    if (elements.connDot) {
        elements.connDot.className = 'status-dot ' + (connected ? 'status-online' : ((connecting || reconnecting) ? 'status-online' : 'status-offline'));
        
        if (reconnecting) {
            elements.connDot.style.background = '#f59e0b';
            elements.connDot.style.boxShadow = '0 0 8px #f59e0b';
        } else if (connecting) {
            elements.connDot.style.background = '#fbbf24';
            elements.connDot.style.boxShadow = '0 0 8px #fbbf24';
        } else if (!connected) {
            elements.connDot.style.background = '#ef4444';
            elements.connDot.style.boxShadow = 'none';
        } else {
            elements.connDot.style.background = '';
            elements.connDot.style.boxShadow = '';
        }
    }

    if (elements.connText) {
        elements.connText.textContent = connected ? getMessage('STATUS_CONNECTED') : (reconnecting ? getMessage('STATUS_RECONNECTING') : (connecting ? getMessage('STATUS_CONNECTING') : getMessage('STATUS_DISCONNECTED')));
    }
    if (elements.retryBtn) {
        elements.retryBtn.style.display = reconnecting && reconnectSlowMode ? 'block' : 'none';
    }

    if (elements.joinBtn) {
        if (connecting || reconnecting) {
            elements.joinBtn.disabled = !reconnectSlowMode;
            elements.joinBtn.textContent = connecting ? getMessage('BTN_STATE_JOINING') : getMessage('BTN_STATE_RECONNECTING');
        } else {
            elements.joinBtn.disabled = false;
            elements.joinBtn.textContent = getMessage('BTN_JOIN_ROOM');
        }
    }

    if (elements.playBtn) elements.playBtn.textContent = getMessage('BTN_PLAY');
    if (elements.pauseBtn) elements.pauseBtn.textContent = getMessage('BTN_PAUSE');
    if (elements.forceSyncBtn) elements.forceSyncBtn.textContent = getMessage('BTN_SYNC');
}

function updateHistory(history) {
    if (!history || !elements.historyList) return;
    elements.historyList.innerHTML = '';

    if (history.length === 0) {
        renderEmpty(elements.historyList, 'history');
        return;
    }

    history.forEach(item => {
        const time = new Date(item.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
        const actionLabel = item.action.toUpperCase().replace('FORCE_SYNC_', '');
        
        const entry = document.createElement('div');
        entry.style.cssText = 'margin-bottom: 4px; border-bottom: 1px solid rgba(255,255,255,0.05); padding-bottom: 2px;';
        
        const timeSpan = document.createElement('span');
        timeSpan.style.color = '#64748b';
        timeSpan.textContent = `[${time}] `;
        
        const actionBold = document.createElement('b');
        actionBold.textContent = actionLabel;
        
        const textNode1 = document.createTextNode(' by ');
        
        const senderSpan = document.createElement('span');
        if (item.senderId === 'You') {
            senderSpan.style.color = 'var(--accent)';
            senderSpan.textContent = getMessage('LABEL_YOU') || 'You';
        } else {
            senderSpan.textContent = item.senderId;
        }
        
        entry.appendChild(timeSpan);
        entry.appendChild(actionBold);
        entry.appendChild(textNode1);
        entry.appendChild(senderSpan);
        
        elements.historyList.appendChild(entry);
    });
}

function refreshHistory() {
    chrome.runtime.sendMessage({ type: 'GET_HISTORY' }, (res) => {
        if (res) updateHistory(res);
    });
}

function updateRoomList(rooms) {
    if (!elements.publicRooms) return;
    elements.publicRooms.innerHTML = '';

    if (!rooms || rooms.length === 0) {
        renderEmpty(elements.publicRooms, 'rooms');
        return;
    }

    rooms.forEach(r => {
        const item = document.createElement('div');
        item.className = 'room-item';
        item.style.cssText = 'display:flex; justify-content:space-between; align-items:center; padding: 8px; border-bottom: 1px solid rgba(255,255,255,0.05); cursor:pointer;';
        item.dataset.id = r.id;

        const leftSide = document.createElement('div');
        leftSide.style.cssText = 'display:flex; align-items:center; gap: 6px;';

        const idSpan = document.createElement('span');
        idSpan.style.fontWeight = '600';
        idSpan.textContent = r.id;

        leftSide.appendChild(idSpan);

        if (r.hasPassword) {
            const lock = document.createElement('span');
            lock.title = getMessage('LABEL_PASSWORD_PROTECTED');
            lock.textContent = '🔒';
            leftSide.appendChild(lock);
        }

        const peerCount = document.createElement('span');
        peerCount.style.cssText = 'font-size:11px; color:var(--accent)';
        peerCount.textContent = getMessage('LABEL_PEERS_COUNT', { count: parseInt(r.peerCount) });

        item.appendChild(leftSide);
        item.appendChild(peerCount);

        item.addEventListener('click', () => {
            elements.roomId.value = r.id;
            elements.password.value = '';
            elements.password.focus();
        });

        elements.publicRooms.appendChild(item);
    });
}

function checkInviteLink() {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
        const tab = tabs[0];
        if (tab && tab.url && tab.url.startsWith(OFFICIAL_LANDING_PAGE_URL + '/') && tab.url.includes('#join:')) {
            try {
                const rawHash = tab.url.split('#join:')[1];
                if (!rawHash) return;
                const parts = rawHash.split(':');
                if (parts.length >= 2) {
                    const roomId = parts.shift();
                    let useCustomServer = false;
                    let serverUrl = '';

                    const last = parts[parts.length - 1];
                    const secondToLast = parts[parts.length - 2];
                    const decodedLast = decodeURIComponent(last || '');
                    const isCustom = secondToLast === '1' && (decodedLast.startsWith('ws://') || decodedLast.startsWith('wss://'));
                    const isOfficial = secondToLast === '0' && last === '';

                    if (parts.length >= 3 && (isCustom || isOfficial)) {
                        serverUrl = decodeURIComponent(parts.pop());
                        useCustomServer = parts.pop() === '1';
                    }

                    const password = parts.join(':');

                    elements.roomId.value = roomId;
                    elements.password.value = password;
                    
                    if (serverUrl || useCustomServer) {
                        elements.serverUrl.value = serverUrl;
                        setServerMode(useCustomServer);
                        chrome.storage.local.set({ serverUrl, useCustomServer });
                    }

                    elements.joinBtn.style.boxShadow = '0 0 15px var(--accent)';
                    setTimeout(() => elements.joinBtn.style.boxShadow = '', 2000);
                }
            } catch (_e) {
                // Malformed invite link, ignore
            }
        }
    });
}

function setServerMode(custom) {
    elements.serverOfficial.classList.toggle('active', !custom);
    elements.serverCustom.classList.toggle('active', custom);
    elements.serverUrl.style.display = custom ? 'block' : 'none';
    chrome.storage.local.get(['useCustomServer', 'serverUrl'], (data) => {
        if (data.useCustomServer !== custom) {
            chrome.storage.local.set({ useCustomServer: custom });
            if (!custom || data.serverUrl) {
                chrome.runtime.sendMessage({ type: 'RETRY_CONNECT' });
            }
        }
    });
}

elements.serverOfficial.addEventListener('click', () => setServerMode(false));
elements.serverCustom.addEventListener('click', () => setServerMode(true));

elements.filterNoise.addEventListener('change', () => {
    chrome.storage.sync.set({ filterNoise: elements.filterNoise.checked }, () => {
        populateTabs();
    });
});

elements.autoSyncNextEpisode.addEventListener('change', () => {
    chrome.storage.sync.set({ autoSyncNextEpisode: elements.autoSyncNextEpisode.checked });
});

elements.browserNotifications.addEventListener('change', () => {
    chrome.storage.sync.set({ browserNotifications: elements.browserNotifications.checked });
});

if (elements.autoCopyInvite) {
    elements.autoCopyInvite.addEventListener('change', () => {
        chrome.storage.sync.set({ autoCopyInvite: elements.autoCopyInvite.checked });
    });
}

elements.forceSyncMode.addEventListener('change', () => {
    chrome.storage.sync.set({ forceSyncMode: elements.forceSyncMode.value });
});

elements.serverUrl.addEventListener('input', () => {
    chrome.storage.local.set({ serverUrl: elements.serverUrl.value });
});

elements.username.addEventListener('change', () => {
    chrome.storage.local.set({ username: elements.username.value });
});

if (elements.langSelector) {
    elements.langSelector.addEventListener('change', async () => {
        const selectedLang = elements.langSelector.value;
        await chrome.storage.sync.set({ locale: selectedLang });
        await loadLocale(selectedLang);
        translateDOM();
        
        // Re-apply connection and room UI state since translateDOM may overwrite dynamic elements
        chrome.runtime.sendMessage({ type: 'GET_STATUS' }, async (res) => {
            if (chrome.runtime.lastError) return;
            if (res) {
                localPeerId = res.peerId;
                reconnectSlowMode = res.reconnectSlowMode || false;
                applyConnectionStatus(res.status);
                updatePeerList(res.peers);
                lastKnownPeers = res.peers || [];
                if (res.lastActionState) updateLastActionUI(res.lastActionState, res.peers);
                
                const data = await chrome.storage.local.get(['roomId', 'password', 'useCustomServer', 'serverUrl']);
                updateUI(data.roomId, data.password, data.useCustomServer, data.serverUrl);
                
                await populateTabs(res.peers, res.targetTabId);
                if (res.episodeLobby) updateLobbyUI(res.episodeLobby, res.peers);
            } else {
                applyConnectionStatus('disconnected');
                const data = await chrome.storage.local.get(['roomId', 'password', 'useCustomServer', 'serverUrl']);
                updateUI(data.roomId, data.password, data.useCustomServer, data.serverUrl);
                await populateTabs();
            }
        });

        refreshLogs();
        refreshHistory();
    });
}

elements.serverUrl.addEventListener('change', () => {
    let url = elements.serverUrl.value.trim();
    if (url && !url.includes('://')) {
        url = 'ws://' + url;
        elements.serverUrl.value = url;
        chrome.storage.local.set({ serverUrl: url });
    }
    if (elements.serverCustom.classList.contains('active') && url) {
        chrome.runtime.sendMessage({ type: 'RETRY_CONNECT' });
    }
});

elements.tabs.forEach(btn => {
    btn.addEventListener('click', () => {
        elements.tabs.forEach(b => b.classList.remove('active'));
        elements.contents.forEach(c => c.classList.remove('active'));
        btn.classList.add('active');
        
        const targetContent = document.getElementById(btn.dataset.tab);
        targetContent.classList.add('active');
        
        targetContent.classList.remove('tab-active-animate');
        void targetContent.offsetWidth; // Force reflow to restart animation
        targetContent.classList.add('tab-active-animate');
        
        isDevTabVisible = btn.dataset.tab === 'tab-dev';
        if (isDevTabVisible) refreshLogs();
        if (btn.dataset.tab === 'tab-sync') refreshHistory();
    });
});

function showToast(message, type = 'info', duration = 3000) {
    const container = document.getElementById('toast-container');
    if (!container) return;
    const toast = document.createElement('div');
    toast.className = `toast toast-${type}`;
    toast.textContent = message || '';
    toast.style.whiteSpace = 'pre-wrap';

    const delay = Math.max(0, duration - 600);
    toast.style.animation = `toastSlideIn 0.3s ease-out, toastFadeOut 0.3s ease-in ${delay}ms forwards`;

    container.appendChild(toast);
    setTimeout(() => toast.remove(), duration);
}

function showError(msg) {
    if (!elements.roomError) return;
    const currentToken = ++errorToken;
    elements.roomError.textContent = msg;
    elements.roomError.style.display = 'block';
    elements.roomId.style.borderColor = 'var(--error)';
    elements.password.style.borderColor = 'var(--error)';
    
    showToast(msg, 'error', 5000);

    setTimeout(() => {
        if (currentToken !== errorToken) return;
        if (elements.roomError) elements.roomError.style.display = 'none';
        elements.roomId.style.borderColor = '';
        elements.password.style.borderColor = '';
    }, 5000);
}

// --- Action Handlers ---
elements.roomId.addEventListener('input', () => {
    elements.roomId.value = elements.roomId.value.replace(/[^a-zA-Z0-9\-]/g, '');
});

elements.joinBtn.addEventListener('click', async () => {
    clearConnectionErrorTimer();
    if (elements.joinBtn.disabled) return;
    const roomIdInput = elements.roomId.value.trim();
    const isCreating = !roomIdInput;
    
    elements.joinBtn.disabled = true;
    elements.joinBtn.textContent = isCreating ? getMessage('BTN_STATE_CREATING') : getMessage('BTN_STATE_JOINING');
    
    if (joinBtnTimeout) clearTimeout(joinBtnTimeout);
    joinBtnTimeout = setTimeout(() => {
        elements.joinBtn.disabled = false;
        elements.joinBtn.textContent = getMessage('BTN_JOIN_ROOM');
        joinBtnTimeout = null;
        showError(getMessage('ERR_CONN_TIMEOUT'));
    }, 15000);
    
    const serverUrl = elements.serverUrl.value.trim();
    const useCustom = elements.serverCustom.classList.contains('active');

    // Proactive URL Validation
    if (useCustom && !serverUrl) {
        showError(getMessage('ERR_INVALID_SERVER_URL'));
        elements.joinBtn.disabled = false;
        elements.joinBtn.textContent = getMessage('BTN_JOIN_ROOM');
        return;
    }
    if (useCustom && serverUrl) {
        try {
            const urlToCheck = serverUrl.includes('://') ? serverUrl : 'ws://' + serverUrl;
            new URL(urlToCheck);
        } catch (_e) {
            showError(getMessage('ERR_INVALID_SERVER_URL'));
            elements.joinBtn.disabled = false;
            elements.joinBtn.textContent = getMessage('BTN_JOIN_ROOM');
            return;
        }
    }

    const roomId = roomIdInput || generateRoomId();
    let password = elements.password.value;
    if (isCreating && !password) {
        const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        const array = new Uint8Array(6);
        self.crypto.getRandomValues(array);
        password = Array.from(array, byte => chars[byte % chars.length]).join('');
        elements.password.value = password;
        window.justCreatedRoom = true;
    }

    await chrome.storage.local.set({ serverUrl, roomId, password, useCustomServer: useCustom });
    elements.roomId.value = roomId;

    // Tell background to connect
    chrome.runtime.sendMessage({ type: 'CONNECT' });
    
    // UI Feedback: Immediately switch state for better responsiveness
    updateUI(roomId, password, useCustom, serverUrl);
});

elements.leaveBtn.addEventListener('click', async () => {
    clearConnectionErrorTimer();
    chrome.runtime.sendMessage({ type: 'LEAVE_ROOM' });
    await chrome.storage.local.set({ roomId: '', password: '' });
    elements.roomId.value = '';
    elements.password.value = '';
    lastKnownPeers = [];
    updateUI(null, null);
});

function generateRoomId() {
    const adj = USERNAME_ADJECTIVES[Math.floor(Math.random() * USERNAME_ADJECTIVES.length)];
    const noun = USERNAME_NOUNS[Math.floor(Math.random() * USERNAME_NOUNS.length)];
    const num = Math.floor(Math.random() * 99) + 1;
    return `${adj.toUpperCase()}-${noun.toUpperCase()}-${num}`;
}

function handleCreateRoom() {
    const secureGenerateId = (length = 6) => {
        const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        const array = new Uint8Array(length);
        self.crypto.getRandomValues(array);
        return Array.from(array, byte => chars[byte % chars.length]).join('');
    };
    const roomId = generateRoomId();
    const password = secureGenerateId();
    elements.roomId.value = roomId;
    elements.password.value = password;
    window.justCreatedRoom = true;
    
    // Auto-connect
    elements.joinBtn.click();
}

elements.createRoomBtn.addEventListener('click', handleCreateRoom);
const syncTabCreateRoomBtn = document.getElementById('syncTabCreateRoomBtn');
if (syncTabCreateRoomBtn) syncTabCreateRoomBtn.addEventListener('click', () => {
    document.querySelector('.tab-btn[data-tab="tab-room"]').click();
    handleCreateRoom();
});

elements.refreshRooms.addEventListener('click', () => {
    if (elements.refreshRooms.disabled) return;
    setRoomRefreshCooldown();

    elements.publicRooms.replaceChildren();
    const el = document.createElement('div');
    el.style.cssText = 'text-align:center; color: var(--text-muted); font-size: 11px; padding: 10px;';
    el.textContent = getMessage('PUBLIC_ROOMS_REFRESHING_COOLDOWN', { seconds: Math.ceil(ROOM_LIST_REFRESH_COOLDOWN_MS / 1000) });
    elements.publicRooms.appendChild(el);
    chrome.runtime.sendMessage({ type: 'GET_ROOM_LIST' });
});

elements.retryBtn.addEventListener('click', () => {
    chrome.runtime.sendMessage({ type: 'RETRY_CONNECT' });
});

elements.targetTab.addEventListener('change', () => {
    const val = elements.targetTab.value;
    const tabId = val ? parseInt(val) : null;
    const tabTitle = elements.targetTab.options[elements.targetTab.selectedIndex]?.dataset.originalTitle || null;
    chrome.runtime.sendMessage({ type: 'SET_TARGET_TAB', tabId, tabTitle });
});

elements.forceSyncBtn.addEventListener('click', async () => {
    if (elements.forceSyncBtn.disabled) return;
    
    const status = await new Promise(r => chrome.runtime.sendMessage({ type: 'GET_STATUS' }, r));
    if (chrome.runtime.lastError || !status || !status.targetTabId) return;

    const mode = elements.forceSyncMode.value;
    let targetTime = null;

    if (mode === 'jump-to-others') {
        if (!localPeerId) {
            showError(getMessage('ERR_IDENTITY_NOT_LOADED'));
            return;
        }
        const peers = status.peers || [];
        const otherTimes = peers
            .filter(p => typeof p === 'object' && p.peerId !== localPeerId && p.currentTime != null && !isNaN(p.currentTime))
            .map(p => p.currentTime);

        if (otherTimes.length === 0) {
            showError(getMessage('ERR_NO_PEERS_TIME'));
            return;
        }

        otherTimes.sort((a, b) => a - b);
        const mid = Math.floor(otherTimes.length / 2);
        targetTime = otherTimes.length % 2 !== 0 ? otherTimes[mid] : (otherTimes[mid - 1] + otherTimes[mid]) / 2;
    }

    const originalText = elements.forceSyncBtn.textContent;
    elements.forceSyncBtn.disabled = true;
    elements.forceSyncBtn.textContent = mode === 'jump-to-others' ? getMessage('BTN_STATE_SYNCING_GROUP', { time: formatTime(targetTime) }) : getMessage('BTN_STATE_SYNCING');
    forceSyncDone = false;
    const peerCount = (status.peers || []).filter(p => (typeof p === 'object' ? p.peerId : p) !== localPeerId).length;
    const syncTimeoutMs = peerCount === 0 ? 3000 : 12000;
    const forceSyncReset = () => {
        if (!forceSyncDone) {
            elements.forceSyncBtn.disabled = false;
            elements.forceSyncBtn.textContent = originalText;
        }
    };
    forceSyncResetTimer = setTimeout(forceSyncReset, syncTimeoutMs);
    const tabId = parseInt(status.targetTabId);

    const sendForceSync = (time) => {
        chrome.runtime.sendMessage({
            type: 'CONTENT_EVENT',
            action: EVENTS.FORCE_SYNC_PREPARE,
            payload: { targetTime: parseFloat(time) }
        });
    };

    if (mode === 'jump-to-me') {
        chrome.tabs.sendMessage(tabId, { action: 'get_current_time' }, (response) => {
            if (chrome.runtime.lastError || !response || response.currentTime === undefined) {
                chrome.scripting.executeScript({
                    target: { tabId },
                    files: ['content.js']
                }).then(() => {
                    setTimeout(() => {
                        chrome.tabs.sendMessage(tabId, { action: 'get_current_time' }, (retryResponse) => {
                            if (chrome.runtime.lastError) return;
                            if (retryResponse && retryResponse.currentTime !== undefined) {
                                sendForceSync(retryResponse.currentTime);
                            }
                        });
                    }, 500);
                }).catch(() => {
                    showError(getMessage('ERR_NO_VIDEO_TAB'));
                    forceSyncDone = true;
                    elements.forceSyncBtn.disabled = false;
                    elements.forceSyncBtn.textContent = originalText;
                });
                return;
            }
            sendForceSync(response.currentTime);
        });
    } else {
        sendForceSync(targetTime);
    }
});

elements.playBtn.addEventListener('click', () => {
    if (!elements.targetTab.value) {
        showToast(getMessage('ERR_SELECT_VIDEO'), 'warning');
        return;
    }
    elements.playBtn.textContent = getMessage('BTN_STATE_PLAYING');
    elements.playBtn.disabled = true;
    chrome.runtime.sendMessage({
        type: 'CONTENT_EVENT',
        action: EVENTS.PLAY,
        payload: {}
    }, (response) => {
        if (response && response.status === 'ok_solo') {
            elements.playBtn.textContent = getMessage('BTN_PLAY');
            elements.playBtn.disabled = false;
        }
    });
    // Safety reset: restore button after 2.5s in case no peers respond
    setTimeout(() => {
        if (elements.playBtn.disabled) {
            elements.playBtn.textContent = getMessage('BTN_PLAY');
            elements.playBtn.disabled = false;
        }
    }, 2500);
});

elements.pauseBtn.addEventListener('click', () => {
    if (!elements.targetTab.value) {
        showToast(getMessage('ERR_SELECT_VIDEO'), 'warning');
        return;
    }
    elements.pauseBtn.textContent = getMessage('BTN_STATE_PAUSING');
    elements.pauseBtn.disabled = true;
    chrome.runtime.sendMessage({
        type: 'CONTENT_EVENT',
        action: EVENTS.PAUSE,
        payload: {}
    }, (response) => {
        if (response && response.status === 'ok_solo') {
            elements.pauseBtn.textContent = getMessage('BTN_PAUSE');
            elements.pauseBtn.disabled = false;
        }
    });
    // Safety reset: restore button after 2.5s in case no peers respond
    setTimeout(() => {
        if (elements.pauseBtn.disabled) {
            elements.pauseBtn.textContent = getMessage('BTN_PAUSE');
            elements.pauseBtn.disabled = false;
        }
    }, 2500);
});

elements.clearLogs.addEventListener('click', () => {
    chrome.runtime.sendMessage({ type: 'CLEAR_LOGS' }, () => {
        elements.logList.innerHTML = '';
    });
});

elements.copyInvite.addEventListener('click', () => {
    navigator.clipboard.writeText(elements.inviteLink.value).then(() => {
        const original = elements.copyInvite.textContent;
        elements.copyInvite.textContent = '✓';
        elements.copyInvite.style.background = 'var(--success)';
        elements.copyInvite.style.color = 'white';
        showToast(getMessage('TOAST_INVITE_COPIED'), 'success', 2000);
        setTimeout(() => {
            elements.copyInvite.textContent = original;
            elements.copyInvite.style.background = '';
            elements.copyInvite.style.color = '';
        }, 2000);
    }).catch(() => {
        showToast(getMessage('TOAST_COPY_FAILED'), 'error');
    });
});

if (elements.syncTabCopyInvite) {
    elements.syncTabCopyInvite.addEventListener('click', () => {
        navigator.clipboard.writeText(elements.inviteLink.value).then(() => {
            const original = elements.syncTabCopyInvite.textContent;
            elements.syncTabCopyInvite.textContent = '✓';
            elements.syncTabCopyInvite.style.color = 'var(--success)';
            showToast(getMessage('TOAST_INVITE_COPIED'), 'success', 2000);
            setTimeout(() => {
                elements.syncTabCopyInvite.textContent = original;
                elements.syncTabCopyInvite.style.color = '';
            }, 2000);
        });
    });
}

if (elements.cancelLobbyBtn) {
    elements.cancelLobbyBtn.addEventListener('click', () => {
        chrome.runtime.sendMessage({ type: 'CANCEL_EPISODE_LOBBY' }, (response) => {
            if (response && response.status === 'ok') {
                showToast(getMessage('TOAST_LOBBY_SKIPPED'), 'info');
                if (elements.episodeLobbyCard) {
                    elements.episodeLobbyCard.style.display = 'none';
                }
            } else {
                showToast(getMessage('TOAST_LOBBY_SKIP_FAILED'), 'error');
            }
        });
    });
}

// --- Logs & Status ---
async function refreshLogs() {
    chrome.runtime.sendMessage({ type: 'GET_LOGS' }, (logs) => {
        if (elements.logList) {
            if (!logs || logs.length === 0) {
                renderEmpty(elements.logList, 'logs');
                return;
            }
            elements.logList.innerHTML = '';
            logs.forEach(log => {
                const entry = document.createElement('div');
                entry.className = `log-entry log-${log.type}`;
                const timeStr = log.timestamp?.split('T')?.[1]?.split('.')[0] || '?';
                entry.textContent = `[${timeStr}] ${log.message}`;
                elements.logList.appendChild(entry);
            });
        }
    });
}

chrome.runtime.onMessage.addListener((msg) => {
    if (!msg) return;
    if (msg.type === 'LOG_UPDATE') {
        refreshLogs();
        if (msg.log && msg.log.type === 'error') {
            const errMsg = msg.log.message || '';
            const isConnErr = typeof errMsg === 'string' && (
                errMsg.toLowerCase().includes('connection') ||
                errMsg.toLowerCase().includes('websocket')
            );
            if (isConnErr) {
                pendingConnectionErrorMsg = msg.log.message;
                if (!connectionErrorTimer) {
                    connectionErrorTimer = setTimeout(() => {
                        if (pendingConnectionErrorMsg) {
                            showError(pendingConnectionErrorMsg);
                        }
                        connectionErrorTimer = null;
                        pendingConnectionErrorMsg = null;
                    }, 5000);
                }
            } else {
                showError(msg.log.message);
            }
        }
    } else if (msg.type === 'ACTION_UPDATE') {
        const state = msg.state;
        if (state && state.senderId && state.senderId !== 'You') {
            const actionNames = {
                'play': getMessage('NOTIF_PLAY'),
                'pause': getMessage('NOTIF_PAUSE'),
                'seek': getMessage('NOTIF_SEEK'),
                'force_sync_prepare': getMessage('NOTIF_FORCE_PREPARE'),
                'force_sync_execute': getMessage('NOTIF_FORCE_EXECUTE')
            };
            const action = actionNames[state.action] || state.action;
            let displayName = state.senderId;
            const peer = lastKnownPeers.find(p => (p.peerId || p) === state.senderId);
            if (peer && peer.username) displayName = peer.username;
            showToast(getMessage('TOAST_PEER_ACTION', { name: displayName, action }), 'info', 2000);
        }

        if (state && (state.action === 'play' || state.action === 'pause')) {
            const btn = state.action === 'play' ? elements.playBtn : elements.pauseBtn;
            if (btn && btn.disabled) {
                chrome.runtime.sendMessage({ type: 'GET_STATUS' }, (res) => {
                    const peerCount = res && res.peers ? res.peers.length : 1;
                    if (state.acks && state.acks.length >= peerCount) {
                        btn.textContent = getMessage('BTN_STATE_SYNCED');
                        setTimeout(() => {
                            btn.disabled = false;
                            btn.textContent = state.action === 'play' ? getMessage('BTN_PLAY') : getMessage('BTN_PAUSE');
                        }, 2000);
                    }
                });
            }
        }

        if (state && state.action === 'force_sync_execute') {
            forceSyncDone = true;
            if (forceSyncResetTimer) {
                clearTimeout(forceSyncResetTimer);
                forceSyncResetTimer = null;
            }
            if (elements.forceSyncBtn) {
                elements.forceSyncBtn.disabled = false;
                elements.forceSyncBtn.textContent = getMessage('BTN_STATE_SYNCED');
                setTimeout(() => {
                    elements.forceSyncBtn.textContent = getMessage('BTN_SYNC');
                }, 2000);
            }
        }
        chrome.runtime.sendMessage({ type: 'GET_STATUS' }, (res) => {
            if (res && res.peers) updateLastActionUI(msg.state, res.peers);
        });
    } else if (msg.type === 'PEER_UPDATE') {
        updatePeerList(msg.peers);
        if (msg.peers) detectPeerChanges(msg.peers);
    } else if (msg.type === 'CONNECTION_STATUS') {
        if (msg.status === 'connected') {
            clearConnectionErrorTimer();
        }
        if (msg.status !== 'reconnecting') {
            applyConnectionStatus(msg.status);
            reconnectSlowMode = false;
        }
        if (msg.status === 'connected') {
            chrome.runtime.sendMessage({ type: 'GET_STATUS' }, (res) => {
                if (res && res.peers) updatePeerList(res.peers);
                if (res && res.lastActionState) updateLastActionUI(res.lastActionState, res.peers);
            });
        }
        if (msg.status === 'disconnected') {
            elements.joinBtn.disabled = false;
            elements.joinBtn.textContent = getMessage('BTN_JOIN_ROOM');
        }
        if (msg.status === 'reconnecting') {
            chrome.runtime.sendMessage({ type: 'GET_STATUS' }, (res) => {
                if (chrome.runtime.lastError) return;
                if (res && res.reconnectSlowMode !== undefined) reconnectSlowMode = res.reconnectSlowMode;
                applyConnectionStatus(msg.status);
                if (res && res.reconnectAttempts !== undefined) {
                    if (elements.connText) {
                        elements.connText.textContent = `Reconnecting... (${res.reconnectAttempts})`;
                    }
                }
            });
        }
    } else if (msg.type === 'HISTORY_UPDATE') {
        updateHistory(msg.history);
    } else if (msg.type === 'ROOM_LIST') {
        updateRoomList(msg.rooms);
    } else if (msg.type === 'JOIN_STATUS') {
        if (joinBtnTimeout) {
            clearTimeout(joinBtnTimeout);
            joinBtnTimeout = null;
        }
        elements.joinBtn.disabled = false;
        elements.joinBtn.textContent = getMessage('BTN_JOIN_ROOM');

        if (msg.success) {
            // Final confirmation of join from background
            chrome.storage.local.get(['roomId', 'password', 'useCustomServer', 'serverUrl'], (data) => {
                updateUI(data.roomId, data.password, data.useCustomServer, data.serverUrl);
            });
        } else {
            // Join failed: reset UI state
            updateUI(null, null);
        }
    } else if (msg.type === 'LOBBY_UPDATE') {
        // Episode lobby state changed
        chrome.runtime.sendMessage({ type: 'GET_STATUS' }, (res) => {
            if (res && res.peers) {
                updateLobbyUI(msg.lobby, res.peers);
            } else {
                updateLobbyUI(msg.lobby, []);
            }
        });
    }
});

elements.copyLogs.addEventListener('click', () => {
    const utcNow = new Date().toISOString().replace('T', ' ').slice(0, 19) + ' UTC';
    const userAgent = String(navigator.userAgent || '');

    const safe = (val, fb) => (val != null ? val : fb);

    Promise.all([
        new Promise(resolve => chrome.runtime.sendMessage({ type: 'GET_STATUS' }, resolve)),
        new Promise(resolve => chrome.runtime.sendMessage({ type: 'GET_LOGS' }, resolve)),
        new Promise(resolve => chrome.runtime.sendMessage({ type: 'GET_HISTORY' }, resolve))
    ]).then(([status, logs, history]) => {
        status = status || {};
        logs = logs || [];
        history = history || [];

        const videoPromise = (status && status.targetTabId)
            ? new Promise(resolve => chrome.runtime.sendMessage({ type: 'GET_VIDEO_STATE', tabId: status.targetTabId }, resolve))
            : Promise.resolve(null);

        videoPromise.then(rawVideo => {
        const vs = rawVideo || {};
        const lines = [];

        // ── Header ──
        const verStr = safe(status.version, '?');
        lines.push('# KoalaSync Debug Report');
        lines.push(`> **v${verStr}** | ${utcNow}`);
        lines.push('');

        // ── System ──
        lines.push('## System');
        lines.push(`- **Protocol:** ${safe(status.protocolVersion, '?')}`);
        lines.push(`- **Peer ID:** \`${safe(status.peerId, '?')}\``);
        lines.push(`- **User Agent:** ${userAgent}`);
        lines.push('');

        // ── Tab ──
        if (rawVideo) {
            lines.push('## Tab');
            if (vs.pageTitle) lines.push(`- **Title:** ${vs.pageTitle}`);
            if (vs.url) lines.push(`- **URL:** ${vs.url}`);
            if (vs.platform) lines.push(`- **Platform:** ${safe(vs.platform, '?')}`);
            lines.push(`- **Video Count:** ${safe(vs.videoCount, 0)} | **Shadow DOM:** ${vs.inShadowDom ? 'YES' : 'NO'}`);
            lines.push('');

            // Multi-video overview
            const videos = Array.isArray(vs.allVideos) ? vs.allVideos : [];
            if (videos.length > 1) {
                lines.push('### All Videos on Page');
                lines.push('');
                lines.push('| # | Resolution | Muted | Paused | Ready | Duration | Selected |');
                lines.push('|---|------------|-------|--------|-------|----------|----------|');
                const rl = ['HAVE_NOTHING', 'HAVE_METADATA', 'HAVE_CURRENT_DATA', 'HAVE_FUTURE_DATA', 'HAVE_ENOUGH_DATA'];
                for (const v of videos) {
                    if (!v) continue;
                    const sel = v.selected ? ' **\u2190 TARGET**' : '';
                    const dim = `${safe(v.width, '?')}x${safe(v.height, '?')}`;
                    const rs = (v.readyState != null && v.readyState >= 0 && v.readyState <= 4) ? rl[v.readyState] : '?';
                    lines.push(`| ${safe(v.index, '?')} | ${dim} | ${safe(v.muted, '?')} | ${safe(v.paused, '?')} | ${rs} | ${safe(v.duration, 0)}s |${sel} |`);
                }
                lines.push('');
            }
        }

        // ── Connection ──
        lines.push('## Connection');
        const st = safe(status.status, 'disconnected');
        const emoji = st === 'connected' ? '\uD83D\uDFE2'
            : st === 'connecting' ? '\uD83D\uDFE1'
            : st === 'reconnecting' ? '\uD83D\uDFE0'
            : '\uD83D\uDD34';
        lines.push(`- **Status:** ${emoji} ${st}`);
        lines.push(`- **Server:** \`${safe(status.serverUrl, '?')}\``);
        if (status.roomId) {
            lines.push(`- **Room:** \`${status.roomId}\``);
            const peers = Array.isArray(status.peers) ? status.peers : [];
            const peerNames = peers.map(p => (p && (p.username || p.peerId)) || '?').join(', ');
            lines.push(`- **Peers (${peers.length}):** ${peers.length > 0 ? peerNames : 'none'}`);
        } else {
            lines.push('- **Room:** none');
        }
        if (safe(status.reconnectAttempts, 0) > 0) lines.push(`- **Reconnect Attempts:** ${status.reconnectAttempts}`);
        lines.push('');

        // ── Video ──
        lines.push('## Video');
        if (!rawVideo) {
            lines.push('- *No tab selected / communication failed*');
        } else if (!vs.found) {
            lines.push('- **Found:** \u274C NO VIDEO ELEMENT');
            if (vs.videoCount != null) lines.push(`- **Video Tags:** ${vs.videoCount}`);
            if (vs.inShadowDom != null) lines.push(`- **Shadow DOM:** ${vs.inShadowDom ? 'YES (checked)' : 'NO'}`);
            if (vs.metadata) {
                if (vs.metadata.title) lines.push(`- **MediaSession Title:** "${vs.metadata.title}"`);
                if (vs.metadata.artist) lines.push(`- **MediaSession Artist:** "${vs.metadata.artist}"`);
                if (vs.metadata.album) lines.push(`- **MediaSession Album:** "${vs.metadata.album}"`);
            }
        } else {
            const timeStr = (typeof vs.currentTime === 'number' ? vs.currentTime.toFixed(2) : '?') + 's / ' +
                (typeof vs.duration === 'number' ? vs.duration.toFixed(2) : '?') + 's';
            const readyLabel = safe(vs.readyStateLabel, '?');
            const readyOk = safe(vs.readyState, -1) >= 3;
            const netLabel = safe(vs.networkStateLabel, '?');
            const dimOk = safe(vs.videoWidth, 0) > 0 && safe(vs.videoHeight, 0) > 0;

            lines.push(`- **State:** ${vs.paused ? 'PAUSED' : 'PLAYING'}`);
            lines.push(`- **Time:** ${timeStr}`);
            lines.push(`- **ReadyState:** ${readyOk ? '\u2705' : '\u26A0\uFE0F'} ${safe(vs.readyState, '?')} (${readyLabel})`);
            lines.push(`- **Network:** ${safe(vs.networkState, '?')} (${netLabel})`);
            lines.push(`- **Buffered:** ${safe(vs.buffered, '?')}`);
            lines.push(`- **Dimensions:** ${safe(vs.videoWidth, '?')}x${safe(vs.videoHeight, '?')}${dimOk ? '' : ' \u26A0\uFE0F 0x0'}`);
            lines.push(`- **Muted:** ${safe(vs.muted, '?')} | **Volume:** ${safe(vs.volume, '?')} | **Speed:** ${safe(vs.playbackRate, '?')}x`);
            lines.push(`- **Seeking:** ${safe(vs.seeking, '?')} | **Ended:** ${safe(vs.ended, '?')} | **Loop:** ${safe(vs.loop, '?')}`);
            if (vs.error && vs.error.code != null) {
                lines.push(`- **Error:** code=${vs.error.code}, msg="${safe(vs.error.message, 'none')}"`);
            }
            lines.push(`- **ID:** \`${safe(vs.id, '')}\` | **Class:** \`${safe(vs.className, '')}\``);
            lines.push(`- **Source:** \`${safe(vs.currentSrc, safe(vs.src, 'none'))}\``);
            if (vs.metadata) {
                if (vs.metadata.title) lines.push(`- **MediaSession Title:** "${vs.metadata.title}"`);
                if (vs.metadata.artist) lines.push(`- **MediaSession Artist:** "${vs.metadata.artist}"`);
                if (vs.metadata.album) lines.push(`- **MediaSession Album:** "${vs.metadata.album}"`);
            }
            if (vs.dataAttributes) {
                const keys = Object.keys(vs.dataAttributes);
                if (keys.length > 0) {
                    lines.push('- **Data Attributes:**');
                    for (const k of keys) lines.push(`  - \`${k}\` = "${safe(vs.dataAttributes[k], '')}"`);
                }
            }
        }
        lines.push('');

        // ── Action History (last 20) ──
        lines.push('## Action History (last 20)');
        if (history && history.length > 0) {
            const recent = history.slice(0, 20).reverse();
            lines.push('```');
            for (const h of recent) {
                if (!h) continue;
                const ts = safe(h.timestamp, '');
                const evt = safe(h.action, '?');
                const from = h.senderId ? ` (${h.senderId})` : (h.peerId ? ` (${h.peerId})` : '');
                const extra = h.detail ? ` \u2192 ${h.detail}` : '';
                lines.push(`[${ts}] ${evt}${from}${extra}`);
            }
            lines.push('```');
        } else {
            lines.push('*No history entries*');
        }
        lines.push('');

        // ── Logs (last 50) ──
        lines.push('## Logs (last 50)');
        if (logs && logs.length > 0) {
            const recent = logs.slice(0, 50).reverse();
            lines.push('```');
            for (const l of recent) {
                if (!l) continue;
                lines.push(`[${safe(l.timestamp, '')}] [${safe(l.type, '?')}] ${safe(l.message, '')}`);
            }
            lines.push('```');
        } else {
            lines.push('*No log entries*');
        }

        const text = lines.join('\n');
        navigator.clipboard.writeText(text).then(() => {
            const original = elements.copyLogs.textContent;
            elements.copyLogs.textContent = getMessage('TOAST_LOGS_COPIED');
            setTimeout(() => { elements.copyLogs.textContent = original; }, 2000);

            // Construct rich multiline toast summary
            const verStr = safe(status.version, '?');
            const logsCount = logs.length;
            const historyCount = history.length;
            const peersCount = Array.isArray(status.peers) ? status.peers.length : 0;

            let summary = `📋 Debug Report Copied!\n`;
            summary += `• Version: v${verStr}\n`;
            summary += `• System Logs: ${logsCount} entries\n`;
            summary += `• Sync Actions: ${historyCount} captured\n`;
            if (status.roomId) {
                summary += `• Peers in Room: ${peersCount}\n`;
            }
            if (rawVideo && vs.found) {
                const stateStr = vs.paused === true ? 'Paused' : (vs.paused === false ? 'Playing' : 'Unknown');
                const timeStr = typeof vs.currentTime === 'number' ? `${Math.round(vs.currentTime)}s` : '?';
                summary += `• Video: ${stateStr} at ${timeStr}\n`;
            }
            summary += `Paste it in markdown to view!`;

            showToast(summary, 'success', 5000);
        }).catch(() => {
            showToast(getMessage('TOAST_COPY_FAILED'), 'error');
        });
    });
    });
});

function refreshDebugInfo() {
    // Only refresh if Dev tab is visible
    const devTab = document.getElementById('tab-dev');
    if (!devTab || devTab.style.display === 'none') return;

    chrome.runtime.sendMessage({ type: 'GET_STATUS' }, (res) => {
        if (!res || !res.targetTabId) {
            if (elements.videoDebug) elements.videoDebug.textContent = getMessage('DEBUG_NO_TAB');
            return;
        }

        // Request direct state from the content script via background
        chrome.runtime.sendMessage({ type: 'GET_VIDEO_STATE', tabId: res.targetTabId }, (state) => {
            if (!state || (!state.found && state.error)) {
                if (elements.videoDebug) elements.videoDebug.textContent = getMessage('DEBUG_COMM_FAIL');
                return;
            }

            if (elements.videoDebug) {
                elements.videoDebug.innerHTML = '';

                const addField = (label, value, color = null) => {
                    const row = document.createElement('div');
                    row.style.marginBottom = '4px';
                    if (color) row.style.color = color;

                    const b = document.createElement('b');
                    b.textContent = `${label}: `;
                    b.style.color = 'var(--text-muted)';

                    const span = document.createElement('span');
                    span.textContent = value;
                    span.style.wordBreak = 'break-all';

                    row.appendChild(b);
                    row.appendChild(span);
                    elements.videoDebug.appendChild(row);
                };

                const addSection = (title) => {
                    const div = document.createElement('div');
                    div.style.cssText = 'margin: 8px 0 4px 0; border-bottom: 1px solid #334155; padding-bottom: 2px; color: var(--accent); font-weight: bold; font-size: 10px; text-transform: uppercase;';
                    div.textContent = title;
                    elements.videoDebug.appendChild(div);
                };

                if (!state.found) {
                    // No video found — show diagnostic info
                    addSection('Video Detection');
                    const notFound = document.createElement('div');
                    notFound.style.cssText = 'color: #ef4444; font-weight: 700; margin-bottom: 8px;';
                    notFound.textContent = 'NO VIDEO ELEMENT FOUND';
                    elements.videoDebug.appendChild(notFound);

                    addField('Platform', state.platform || '?', 'var(--accent)');
                    addField('Page Title', state.pageTitle || '?');
                    addField('URL', state.url || '?');
                    addField('Video Tags', String(state.videoCount || 0));
                    addField('Shadow DOM', state.inShadowDom ? 'YES (checked)' : 'NO');

                    if (state.metadata) {
                        addSection('Media Session API');
                        addField('Title', state.metadata.title || 'n/a');
                        addField('Artist', state.metadata.artist || 'n/a');
                        addField('Album', state.metadata.album || 'n/a');
                    }

                    const hint = document.createElement('div');
                    hint.style.cssText = 'margin-top: 12px; padding: 8px; background: rgba(251,191,36,0.1); border-left: 3px solid #fbbf24; border-radius: 4px; font-size: 10px; color: var(--text-muted);';
                    hint.textContent = 'Is a video currently playing? The extension only detects <video> elements. Ensure media is actively loaded on the page.';
                    elements.videoDebug.appendChild(hint);
                    return;
                }

                // Video found — full debug
                addSection('Playback');
                addField('State', state.paused ? 'PAUSED' : 'PLAYING', state.paused ? 'var(--text-muted)' : '#22c55e');
                addField('Time', `${state.currentTime.toFixed(2)}s / ${(state.duration || 0).toFixed(2)}s`);
                addField('ReadyState', `${state.readyState} (${state.readyStateLabel || '?'})`,
                    state.readyState >= 3 ? '#22c55e' : '#fbbf24');
                addField('Network', `${state.networkState} (${state.networkStateLabel || '?'})`,
                    state.networkState === 1 ? '#22c55e' : state.networkState === 3 ? '#ef4444' : 'var(--text-muted)');
                addField('Buffered', state.buffered || '?');

                addSection('Properties');
                addField('Seeking', String(state.seeking));
                addField('Ended', String(state.ended));
                addField('Loop', String(state.loop));
                addField('Muted', String(state.muted));
                addField('Volume', String(state.volume));
                addField('Speed', `${state.playbackRate}x`);

                addSection('Dimensions');
                const dimsOk = state.videoWidth > 0 && state.videoHeight > 0;
                addField('Resolution', `${state.videoWidth}x${state.videoHeight}`, dimsOk ? '#22c55e' : '#ef4444');
                if (!dimsOk) {
                    const dimHint = document.createElement('div');
                    dimHint.style.cssText = 'color: #fbbf24; font-size: 9px; margin: 2px 0 6px 12px;';
                    dimHint.textContent = '0x0 = video element hidden or not yet loaded';
                    elements.videoDebug.appendChild(dimHint);
                }

                if (state.error) {
                    addSection('Media Error');
                    addField('Code', String(state.error.code), '#ef4444');
                    addField('Message', state.error.message || '?', '#ef4444');
                }

                addSection('Detection');
                addField('Platform', state.platform || '?', 'var(--accent)');
                addField('Video Count', String(state.videoCount || 0));
                addField('Shadow DOM', state.inShadowDom ? 'YES' : 'NO');

                addSection('Identification');
                addField('URL', state.url);
                addField('ID', state.id);
                addField('CLASS', state.className);

                addSection('Media Source');
                addField('CurrentSrc', state.currentSrc);
                addField('Src', state.src);

                if (state.metadata) {
                    addSection('Media Session API');
                    addField('Title', state.metadata.title || 'n/a');
                    addField('Artist', state.metadata.artist || 'n/a');
                    addField('Album', state.metadata.album || 'n/a');
                }

                if (state.dataAttributes && Object.keys(state.dataAttributes).length > 0) {
                    addSection('Data Attributes');
                    for (const [key, val] of Object.entries(state.dataAttributes)) {
                        addField(key.replace('data-', '').toUpperCase(), val);
                    }
                }
            }
        });
    });
}

init();
popupIntervals.push(setInterval(() => {
    if (isDevTabVisible) refreshLogs();
}, 5000));

window.addEventListener('unload', () => {
    stopInterpolation();
    popupIntervals.forEach(clearInterval);
    popupIntervals = [];
    if (joinBtnTimeout) {
        clearTimeout(joinBtnTimeout);
        joinBtnTimeout = null;
    }
    if (forceSyncResetTimer) {
        clearTimeout(forceSyncResetTimer);
        forceSyncResetTimer = null;
    }
    if (roomListRefreshTimer) {
        clearTimeout(roomListRefreshTimer);
        roomListRefreshTimer = null;
    }
    if (roomListRefreshInterval) {
        clearInterval(roomListRefreshInterval);
        roomListRefreshInterval = null;
    }
});

// --- Episode Lobby UI ---
function updateLobbyUI(lobby, peers) {
    if (!elements.episodeLobbyCard) return;

    if (!lobby) {
        elements.episodeLobbyCard.style.display = 'none';
        return;
    }

    elements.episodeLobbyCard.style.display = 'block';
    elements.lobbyTitle.textContent = getMessage('LOBBY_WAITING_FOR', { title: lobby.expectedTitle });

    // Build peer readiness list
    const readySet = new Set(lobby.readyPeers || []);
    const peerLines = [];

    if (peers && peers.length > 0) {
        peers.forEach(p => {
            const pId = typeof p === 'object' ? p.peerId : p;
            const pName = (typeof p === 'object' && p.username) ? p.username : pId;
            const avatar = getAvatarForName(pName);
            const isReady = readySet.has(pId);
            const icon = isReady ? '\u2705' : '\u23f3';
            const label = isReady ? getMessage('LABEL_LOBBY_PEER_READY') : getMessage('LABEL_LOBBY_PEER_LOADING');
            peerLines.push(`${icon} ${avatar} ${pName} \u2014 ${label}`);
        });
    }

    if (peerLines.length > 0 && elements.lobbyPeerStatus) {
        elements.lobbyPeerStatus.textContent = peerLines.join(' | ');
    } else if (elements.lobbyPeerStatus) {
        elements.lobbyPeerStatus.textContent = getMessage('LOBBY_WAITING_PEERS');
    }

    // Show elapsed time
    if (lobby.createdAt && elements.lobbyPeerStatus) {
        const elapsed = Math.floor((Date.now() - lobby.createdAt) / 1000);
        elements.lobbyPeerStatus.textContent += ` (${elapsed}s)`;
    }
}

// --- Onboarding Tour ---
const onboardingSteps = [
    { icon: '👋', get title() { return getMessage('ONBOARDING_1_TITLE'); }, get text() { return getMessage('ONBOARDING_1_TEXT'); }, targetTab: 'tab-room' },
    { icon: '🏠', get title() { return getMessage('ONBOARDING_2_TITLE'); }, get text() { return getMessage('ONBOARDING_2_TEXT'); }, targetTab: 'tab-room' },
    { icon: '🎬', get title() { return getMessage('ONBOARDING_3_TITLE'); }, get text() { return getMessage('ONBOARDING_3_TEXT'); }, targetTab: 'tab-sync' },
    { icon: '⚙️', get title() { return getMessage('ONBOARDING_4_TITLE'); }, get text() { return getMessage('ONBOARDING_4_TEXT'); }, targetTab: 'tab-settings' },
    { icon: '🎉', get title() { return getMessage('ONBOARDING_5_TITLE'); }, get text() { return getMessage('ONBOARDING_5_TEXT'); }, targetTab: 'tab-room' }
];

let onboardingStep = 0;

function showOnboarding() {
    const overlay = document.getElementById('onboarding-overlay');
    if (!overlay) return;
    document.body.style.minHeight = '400px';
    overlay.style.display = 'flex';
    renderOnboardingStep();
}

function renderOnboardingStep() {
    const step = onboardingSteps[onboardingStep];
    const icon = document.getElementById('onboarding-icon');
    const title = document.getElementById('onboarding-title');
    const text = document.getElementById('onboarding-text');
    const nextBtn = document.getElementById('onboarding-next');
    const dots = document.getElementById('onboarding-dots');
    if (!icon || !title || !text || !nextBtn || !dots) return;

    icon.textContent = step.icon;
    title.textContent = step.title;
    text.textContent = step.text;

    if (step.targetTab) {
        const tabBtn = document.querySelector(`.tab-btn[data-tab="${step.targetTab}"]`);
        if (tabBtn) tabBtn.click();
        
        const syncActive = document.getElementById('sync-active');
        const syncInactive = document.getElementById('sync-inactive');
        if (step.targetTab === 'tab-sync') {
            if (syncActive) syncActive.style.display = 'block';
            if (syncInactive) syncInactive.style.display = 'none';
        } else {
            // Restore actual lock state when on other tabs so we don't leave it unlocked
            const inRoom = elements.sectionActive && elements.sectionActive.style.display === 'block';
            if (syncActive) syncActive.style.display = inRoom ? 'block' : 'none';
            if (syncInactive) syncInactive.style.display = inRoom ? 'none' : 'block';
        }
    }

    dots.replaceChildren();
    onboardingSteps.forEach((_, i) => {
        const dot = document.createElement('div');
        dot.style.cssText = `width:8px; height:8px; border-radius:50%; background:${i === onboardingStep ? 'var(--accent)' : '#475569'};`;
        dots.appendChild(dot);
    });

    nextBtn.textContent = onboardingStep === onboardingSteps.length - 1 ? (getMessage('ONBOARDING_DONE') !== 'ONBOARDING_DONE' ? getMessage('ONBOARDING_DONE') : 'Done!') : getMessage('BTN_ONBOARDING_NEXT');
}

function completeOnboarding() {
    const overlay = document.getElementById('onboarding-overlay');
    if (overlay) overlay.style.display = 'none';
    document.body.style.minHeight = '';
    chrome.storage.sync.set({ onboardingComplete: true });
    
    const inRoom = elements.sectionActive && elements.sectionActive.style.display === 'block';
    toggleUIState(inRoom);
}

document.getElementById('onboarding-next')?.addEventListener('click', () => {
    onboardingStep++;
    if (onboardingStep >= onboardingSteps.length) {
        completeOnboarding();
    } else {
        renderOnboardingStep();
    }
});

document.getElementById('onboarding-skip')?.addEventListener('click', completeOnboarding);

document.getElementById('onboarding-overlay')?.addEventListener('click', (e) => {
    if (e.target.id === 'onboarding-overlay') completeOnboarding();
});
