import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react';
import { useQuery, useConvex } from 'convex/react';
import { api } from '../../../../convex/_generated/api';
import Sidebar from '../components/Sidebar';
import ChatArea from '../components/ChatArea';
import VoiceStage from '../components/VoiceStage';
import FloatingStreamPiP from '../components/FloatingStreamPiP';
import { useVoice } from '../contexts/VoiceContext';
import FriendsView from '../components/FriendsView';
import MembersList from '../components/MembersList';
import MobileMembersScreen from '../components/MobileMembersScreen';
import MobileSearchScreen from '../components/MobileSearchScreen';
import ChatHeader from '../components/ChatHeader';
import SearchPanel from '../components/SearchPanel';
import SearchDropdown from '../components/SearchDropdown';
import { useToasts } from '../components/Toast';
import { PresenceProvider } from '../contexts/PresenceContext';
import { getUserPref, setUserPref } from '../utils/userPreferences';
import { usePlatform } from '../platform';
import { useIsMobile } from '../hooks/useIsMobile';
import { useSwipeNavigation } from '../hooks/useSwipeNavigation';
import IncomingCallUI from '../components/IncomingCallUI';
import Avatar from '../components/Avatar';
import callRingSound from '../assets/sounds/default_call_sound.mp3';
import { useSystemBars } from '../hooks/useSystemBars';

const MAX_SEARCH_HISTORY = 10;

const Chat = () => {
    const { crypto, settings } = usePlatform();
    const isMobile = useIsMobile();
    const [userId, setUserId] = useState(() => localStorage.getItem('userId'));
    const [username, setUsername] = useState(() => localStorage.getItem('username') || '');
    const [view, setView] = useState(() => {
        const id = localStorage.getItem('userId');
        return id ? getUserPref(id, 'lastView', 'server') : 'server';
    });
    const [activeChannel, setActiveChannel] = useState(null);
    const [channelKeys, setChannelKeys] = useState({});
    const [activeDMChannel, setActiveDMChannel] = useState(null);
    const [showMembers, setShowMembers] = useState(true);
    const [showPinned, setShowPinned] = useState(false);
    const [showMobileMembersScreen, setShowMobileMembersScreen] = useState(false);
    const [showMobileSearchScreen, setShowMobileSearchScreen] = useState(false);

    const { activeView: mobileView, goToChat, goToSidebar, trayRef, trayStyle, isSwiping, swipeBindProps } =
        useSwipeNavigation({
            enabled: isMobile,
            canSwipeToChat: activeChannel !== null || activeDMChannel !== null || view === 'me'
        });

    useSystemBars(mobileView);

    // Jump-to-message state (for search result clicks)
    const [jumpToMessageId, setJumpToMessageId] = useState(null);
    const clearJumpToMessage = useCallback(() => setJumpToMessageId(null), []);

    // Search state
    const [searchQuery, setSearchQuery] = useState('');
    const [showSearchDropdown, setShowSearchDropdown] = useState(false);
    const [showSearchResults, setShowSearchResults] = useState(false);
    const [searchSortOrder, setSearchSortOrder] = useState('newest');
    const [searchHistory, setSearchHistory] = useState(() => {
        const id = localStorage.getItem('userId');
        return id ? getUserPref(id, 'searchHistory', []) : [];
    });
    const searchInputRef = useRef(null);

    const convex = useConvex();
    const { toasts, addToast, removeToast, ToastContainer } = useToasts();
    const prevDmChannelsRef = useRef(null);
    const { toggleMute, connectToVoice, disconnectVoice, activeChannelId: voiceActiveChannelId, voiceStates, room } = useVoice();

    // Keyboard shortcuts
    useEffect(() => {
        const handler = (e) => {
            if (e.ctrlKey && e.key === 'k') {
                e.preventDefault();
                // Focus the search input
                const input = searchInputRef.current?.querySelector('input');
                if (input) {
                    input.focus();
                }
            }
            if (e.ctrlKey && e.shiftKey && e.key === 'M') {
                e.preventDefault();
                toggleMute();
            }
        };
        window.addEventListener('keydown', handler);
        return () => window.removeEventListener('keydown', handler);
    }, [toggleMute]);

    const channels = useQuery(api.channels.list) || [];
    const categories = useQuery(api.categories.list) || [];
    const serverSettings = useQuery(api.serverSettings.get);
    const serverName = serverSettings?.serverName || 'Secure Chat';
    const serverIconUrl = serverSettings?.iconUrl || null;
    const allMembers = useQuery(api.members.listAll) || [];
    const myPermissions = useQuery(
        api.roles.getMyPermissions,
        userId ? { userId } : "skip"
    ) || {};

    const rawChannelKeys = useQuery(
        api.channelKeys.getKeysForUser,
        userId ? { userId } : "skip"
    );

    const dmChannels = useQuery(
        api.dms.listDMs,
        userId ? { userId } : "skip"
    ) || [];

    useEffect(() => {
        if (!rawChannelKeys || rawChannelKeys.length === 0) return;
        const privateKey = sessionStorage.getItem('privateKey');
        if (!privateKey) return;

        async function decryptKeys() {
            const keys = {};
            for (const item of rawChannelKeys) {
                try {
                    const bundleJson = await crypto.privateDecrypt(privateKey, item.encrypted_key_bundle);
                    Object.assign(keys, JSON.parse(bundleJson));
                } catch (e) {
                    console.error(`Failed to decrypt keys for channel ${item.channel_id}`, e);
                }
            }
            setChannelKeys(keys);
        }

        decryptKeys();
    }, [rawChannelKeys]);

    useEffect(() => {
        if (activeChannel || channels.length === 0) return;
        // Try to restore last active channel
        if (userId) {
            const savedChannel = getUserPref(userId, 'lastActiveChannel', null);
            if (savedChannel && channels.some(c => c._id === savedChannel)) {
                setActiveChannel(savedChannel);
                return;
            }
        }
        const firstTextChannel = channels.find(c => c.type === 'text');
        if (firstTextChannel) {
            setActiveChannel(firstTextChannel._id);
        }
    }, [channels, activeChannel, userId]);

    // Persist active channel
    useEffect(() => {
        if (activeChannel && userId) {
            setUserPref(userId, 'lastActiveChannel', activeChannel, settings);
        }
    }, [activeChannel, userId]);

    // Persist view mode
    useEffect(() => {
        if (userId) {
            setUserPref(userId, 'lastView', view, settings);
        }
    }, [view, userId]);

    const openDM = useCallback(async (targetUserId, targetUsername) => {
        const uid = localStorage.getItem('userId');
        if (!uid) return;

        try {
            const { channelId, created } = await convex.mutation(api.dms.openDM, {
                userId: uid,
                targetUserId
            });

            if (created) {
                const keyHex = await crypto.randomBytes(32);

                const allUsers = await convex.query(api.auth.getPublicKeys, {});
                const participants = allUsers.filter(u => u.id === uid || u.id === targetUserId);

                const batchKeys = [];
                for (const u of participants) {
                    if (!u.public_identity_key) continue;
                    try {
                        const payload = JSON.stringify({ [channelId]: keyHex });
                        const encryptedKeyHex = await crypto.publicEncrypt(u.public_identity_key, payload);
                        batchKeys.push({
                            channelId,
                            userId: u.id,
                            encryptedKeyBundle: encryptedKeyHex,
                            keyVersion: 1
                        });
                    } catch (e) {
                        console.error('Failed to encrypt DM key for user', u.id, e);
                    }
                }

                if (batchKeys.length > 0) {
                    await convex.mutation(api.channelKeys.uploadKeys, { keys: batchKeys });
                }
            }

            setActiveDMChannel({ channel_id: channelId, other_username: targetUsername });
            setView('me');
            if (isMobile) goToChat();

        } catch (err) {
            console.error('Error opening DM:', err);
        }
    }, [convex, isMobile, goToChat]);

    const handleSelectChannel = useCallback((channelId) => {
        setActiveChannel(channelId);
        setShowPinned(false);
        if (isMobile) goToChat();
    }, [isMobile, goToChat]);

    const handleMobileBack = useCallback(() => {
        goToSidebar();
    }, [goToSidebar]);

    const activeChannelObj = channels.find(c => c._id === activeChannel);
    const { watchingStreamOf } = useVoice();

    const isDMView = view === 'me' && activeDMChannel;
    const isServerTextChannel = view === 'server' && activeChannel && activeChannelObj?.type !== 'voice';
    const currentChannelId = isDMView ? activeDMChannel.channel_id : activeChannel;
    const effectiveShowMembers = isMobile ? false : showMembers;

    // DM call state
    const dmCallActive = isDMView && activeDMChannel
        ? (voiceStates[activeDMChannel.channel_id]?.length > 0) : false;
    const isInDMCall = isDMView && activeDMChannel
        ? voiceActiveChannelId === activeDMChannel.channel_id : false;
    const [dmCallExpanded, setDmCallExpanded] = useState(false);
    const [dmCallStageHeight, setDmCallStageHeight] = useState(45);
    const [rejectedCallChannelId, setRejectedCallChannelId] = useState(null);
    const ringAudioRef = useRef(null);
    const ringTimeoutRef = useRef(null);

    useEffect(() => {
        if (!isInDMCall) setDmCallExpanded(false);
    }, [isInDMCall]);

    // Global incoming DM call detection — not gated by current view
    const incomingDMCall = useMemo(() => {
        if (!userId) return null;
        for (const dm of dmChannels) {
            const users = voiceStates[dm.channel_id] || [];
            if (users.length > 0 && voiceActiveChannelId !== dm.channel_id) {
                const caller = users.find(u => u.userId !== userId);
                if (caller) {
                    return {
                        channelId: dm.channel_id,
                        otherUsername: dm.other_username,
                        callerUsername: caller.username,
                        callerAvatarUrl: caller.avatarUrl || null,
                    };
                }
            }
        }
        return null;
    }, [dmChannels, voiceStates, voiceActiveChannelId, userId]);

    // Play ringing sound for incoming DM calls (global — works from any view)
    useEffect(() => {
        if (incomingDMCall && incomingDMCall.channelId !== rejectedCallChannelId) {
            const audio = new Audio(callRingSound);
            audio.loop = true;
            audio.volume = 0.5;
            audio.play().catch(() => {});
            ringAudioRef.current = audio;

            ringTimeoutRef.current = setTimeout(() => {
                audio.pause();
                audio.currentTime = 0;
                setRejectedCallChannelId(incomingDMCall.channelId);
            }, 30000);

            return () => {
                audio.pause();
                audio.currentTime = 0;
                ringAudioRef.current = null;
                clearTimeout(ringTimeoutRef.current);
                ringTimeoutRef.current = null;
            };
        }
    }, [incomingDMCall?.channelId, rejectedCallChannelId]);

    // Clear rejected state when the rejected call's channel becomes empty
    useEffect(() => {
        if (rejectedCallChannelId && !(voiceStates[rejectedCallChannelId]?.length > 0)) {
            setRejectedCallChannelId(null);
        }
    }, [rejectedCallChannelId, voiceStates]);

    const handleDmCallResizeStart = useCallback((e) => {
        e.preventDefault();
        const chatContent = e.target.closest('.chat-content');
        if (!chatContent) return;
        const startY = e.clientY;
        const contentRect = chatContent.getBoundingClientRect();
        const startHeight = dmCallStageHeight;

        const onMouseMove = (moveE) => {
            const deltaY = moveE.clientY - startY;
            const deltaPercent = (deltaY / contentRect.height) * 100;
            const newHeight = Math.min(80, Math.max(20, startHeight + deltaPercent));
            setDmCallStageHeight(newHeight);
        };
        const onMouseUp = () => {
            document.removeEventListener('mousemove', onMouseMove);
            document.removeEventListener('mouseup', onMouseUp);
        };
        document.addEventListener('mousemove', onMouseMove);
        document.addEventListener('mouseup', onMouseUp);
    }, [dmCallStageHeight]);

    const handleStartDMCall = useCallback(async () => {
        if (!activeDMChannel) return;
        const dmChannelId = activeDMChannel.channel_id;
        const otherUsername = activeDMChannel.other_username;

        // Already in this DM call
        if (voiceActiveChannelId === dmChannelId) return;

        // Suppress ringing when we leave later — just show the banner
        setRejectedCallChannelId(dmChannelId);

        // If in another voice channel, disconnect first
        if (voiceActiveChannelId) {
            disconnectVoice();
            // Brief delay for cleanup
            await new Promise(r => setTimeout(r, 300));
        }

        // Check if this is a new call (no one currently in it)
        const isNewCall = !voiceStates[dmChannelId]?.length;

        connectToVoice(dmChannelId, otherUsername, userId, true);

        // Send system message for new calls
        if (isNewCall && channelKeys[dmChannelId]) {
            try {
                const systemContent = JSON.stringify({ type: 'system', text: `${username} started a call` });
                const { content: encryptedContent, iv, tag } = await crypto.encryptData(systemContent, channelKeys[dmChannelId]);
                const ciphertext = encryptedContent + tag;
                const signingKey = sessionStorage.getItem('signingKey');
                if (signingKey) {
                    await convex.mutation(api.messages.send, {
                        channelId: dmChannelId,
                        senderId: userId,
                        ciphertext,
                        nonce: iv,
                        signature: await crypto.signMessage(signingKey, ciphertext),
                        keyVersion: 1
                    });
                }
            } catch (e) {
                console.error('Failed to send call system message:', e);
            }
        }
    }, [activeDMChannel, voiceActiveChannelId, disconnectVoice, connectToVoice, userId, username, channelKeys, crypto, convex, voiceStates]);

    // Pending call pattern: open DM then start call once it's active
    const [pendingCallUserId, setPendingCallUserId] = useState(null);

    const handleStartCallWithUser = useCallback(async (targetUserId, targetUsername) => {
        await openDM(targetUserId, targetUsername);
        setPendingCallUserId(targetUserId);
    }, [openDM]);

    useEffect(() => {
        if (!pendingCallUserId || !activeDMChannel) return;
        // Verify the DM channel is for the pending user
        const isCorrectDM = activeDMChannel.other_user_id === pendingCallUserId ||
            activeDMChannel.channel_name?.includes(pendingCallUserId);
        if (!isCorrectDM && activeDMChannel.other_username) {
            // Just proceed - openDM should have set the right channel
        }
        setPendingCallUserId(null);
        // Small delay for key distribution to settle
        const timer = setTimeout(() => {
            handleStartDMCall();
        }, 500);
        return () => clearTimeout(timer);
    }, [pendingCallUserId, activeDMChannel, handleStartDMCall]);

    // PiP: show when watching a stream and NOT currently viewing the voice channel in VoiceStage
    const isViewingDMCallStage = isDMView && isInDMCall;
    const isViewingVoiceStage = (view === 'server' && activeChannelObj?.type === 'voice' && activeChannel === voiceActiveChannelId) || isViewingDMCallStage;
    const showPiP = watchingStreamOf !== null && !isViewingVoiceStage;

    const handleGoBackToStream = useCallback(() => {
        if (voiceActiveChannelId) {
            setActiveChannel(voiceActiveChannelId);
            setView('server');
        }
    }, [voiceActiveChannelId]);

    // Search handlers
    const handleSearchQueryChange = useCallback((val) => {
        setSearchQuery(val);
        if (val === '') {
            setShowSearchResults(false);
        }
        if (!showSearchDropdown && val !== undefined) {
            setShowSearchDropdown(true);
        }
    }, [showSearchDropdown]);

    const handleSearchFocus = useCallback(() => {
        setShowSearchDropdown(true);
    }, []);

    const handleSearchBlur = useCallback(() => {
        // Dropdown close is handled by click-outside in SearchDropdown
    }, []);

    const handleSearchSubmit = useCallback(() => {
        if (!searchQuery.trim()) return;
        setShowSearchDropdown(false);
        setShowSearchResults(true);
        // Save to history
        setSearchHistory(prev => {
            const filtered = prev.filter(h => h !== searchQuery.trim());
            const updated = [searchQuery.trim(), ...filtered].slice(0, MAX_SEARCH_HISTORY);
            if (userId) {
                setUserPref(userId, 'searchHistory', updated, settings);
            }
            return updated;
        });
    }, [searchQuery, userId, settings]);

    const handleSelectFilter = useCallback((prefix, value) => {
        if (value !== null) {
            // Replace the current active prefix with the completed token
            const beforePrefix = searchQuery.replace(/\b(from|in|has|mentions):\S*$/i, '').trimEnd();
            const newQuery = beforePrefix + (beforePrefix ? ' ' : '') + prefix + ':' + value + ' ';
            setSearchQuery(newQuery);
        } else {
            // Just insert the prefix (e.g., clicking "from:" suggestion)
            const newQuery = searchQuery + (searchQuery && !searchQuery.endsWith(' ') ? ' ' : '') + prefix + ':';
            setSearchQuery(newQuery);
        }
        // Re-focus input
        setTimeout(() => {
            const input = searchInputRef.current?.querySelector('input');
            if (input) input.focus();
        }, 0);
    }, [searchQuery]);

    const handleSelectHistoryItem = useCallback((item) => {
        setSearchQuery(item);
        setShowSearchDropdown(false);
        setShowSearchResults(true);
    }, []);

    const handleClearHistory = useCallback(() => {
        setSearchHistory([]);
        if (userId) {
            setUserPref(userId, 'searchHistory', [], settings);
        }
    }, [userId, settings]);

    const handleClearHistoryItem = useCallback((index) => {
        setSearchHistory(prev => {
            const updated = prev.filter((_, i) => i !== index);
            if (userId) {
                setUserPref(userId, 'searchHistory', updated, settings);
            }
            return updated;
        });
    }, [userId, settings]);

    const handleCloseSearchDropdown = useCallback(() => {
        setShowSearchDropdown(false);
    }, []);

    const handleCloseSearchResults = useCallback(() => {
        setShowSearchResults(false);
        setSearchQuery('');
    }, []);

    const handleJumpToMessage = useCallback((channelId, messageId) => {
        // Switch to the correct channel if needed
        const isDM = dmChannels.some(dm => dm.channel_id === channelId);
        if (isDM) {
            const dm = dmChannels.find(d => d.channel_id === channelId);
            if (dm) {
                setActiveDMChannel(dm);
                setView('me');
            }
        } else {
            setActiveChannel(channelId);
            setView('server');
        }
        setShowSearchResults(false);
        setSearchQuery('');
        setJumpToMessageId(messageId);
        if (isMobile) goToChat();
    }, [dmChannels, isMobile, goToChat]);

    // Shared search props for ChatHeader
    const searchProps = {
        searchQuery,
        onSearchQueryChange: handleSearchQueryChange,
        onSearchSubmit: handleSearchSubmit,
        onSearchFocus: handleSearchFocus,
        onSearchBlur: handleSearchBlur,
        searchInputRef,
        searchActive: showSearchDropdown || showSearchResults,
    };

    function renderMainContent() {
        if (view === 'me') {
            if (activeDMChannel) {
                const showIncomingUI = dmCallActive && !isInDMCall && incomingDMCall?.channelId === activeDMChannel?.channel_id && rejectedCallChannelId !== activeDMChannel?.channel_id;
                return (
                    <div className="chat-container">
                        <ChatHeader
                            channelName={activeDMChannel.other_username}
                            channelType="dm"
                            onToggleMembers={() => {}}
                            showMembers={false}
                            onTogglePinned={() => setShowPinned(p => !p)}
                            isMobile={isMobile}
                            onMobileBack={handleMobileBack}
                            onStartCall={handleStartDMCall}
                            isDMCallActive={dmCallActive}
                            {...searchProps}
                        />
                        <div className="chat-content" style={dmCallActive || isInDMCall ? { flexDirection: 'column' } : undefined}>
                            {showIncomingUI && (
                                <IncomingCallUI
                                    callerUsername={incomingDMCall.callerUsername}
                                    callerAvatarUrl={incomingDMCall.callerAvatarUrl}
                                    onJoin={handleStartDMCall}
                                    onReject={() => setRejectedCallChannelId(incomingDMCall.channelId)}
                                />
                            )}
                            {dmCallActive && !isInDMCall && !showIncomingUI && (
                                <div className="dm-call-idle-stage">
                                    <Avatar username={incomingDMCall?.callerUsername || activeDMChannel.other_username} avatarUrl={incomingDMCall?.callerAvatarUrl || null} size={80} />
                                    <div className="dm-call-idle-username">{activeDMChannel.other_displayName || activeDMChannel.other_username}</div>
                                    <div className="dm-call-idle-status">In a call</div>
                                    <button className="dm-call-join-btn" onClick={handleStartDMCall}>Join Call</button>
                                </div>
                            )}
                            {isInDMCall && (
                                <div className="dm-call-stage" style={dmCallExpanded ? { height: '100%', maxHeight: '100%' } : { height: `${dmCallStageHeight}%` }}>
                                    <button
                                        className="dm-call-expand-btn"
                                        onClick={() => setDmCallExpanded(prev => !prev)}
                                        title={dmCallExpanded ? "Show Chat" : "Hide Chat"}
                                    >
                                        <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"
                                             style={{ transform: dmCallExpanded ? 'rotate(180deg)' : undefined, transition: 'transform 0.2s' }}>
                                            <path d="M5.3 9.3a1 1 0 0 1 1.4 0l5.3 5.29 5.3-5.3a1 1 0 1 1 1.4 1.42l-6 6a1 1 0 0 1-1.4 0l-6-6a1 1 0 0 1 0-1.42Z"/>
                                        </svg>
                                    </button>
                                    <VoiceStage room={room} channelId={activeDMChannel.channel_id} voiceStates={voiceStates} channelName={activeDMChannel.other_username} />
                                    {!dmCallExpanded && <div className="dm-call-resize-handle" onMouseDown={handleDmCallResizeStart} />}
                                </div>
                            )}
                            {(!isInDMCall || !dmCallExpanded) && (
                            <div style={{ flex: 1, display: 'flex', overflow: 'hidden' }}>
                                <ChatArea
                                    channelId={activeDMChannel.channel_id}
                                    channelName={activeDMChannel.other_username}
                                    channelType="dm"
                                    channelKey={channelKeys[activeDMChannel.channel_id]}
                                    username={username}
                                    userId={userId}
                                    showMembers={false}
                                    onToggleMembers={() => {}}
                                    onOpenDM={openDM}
                                    showPinned={showPinned}
                                    onTogglePinned={() => setShowPinned(false)}
                                    jumpToMessageId={jumpToMessageId}
                                    onClearJumpToMessage={clearJumpToMessage}
                                />
                                <SearchPanel
                                    visible={showSearchResults}
                                    onClose={handleCloseSearchResults}
                                    channels={channels}
                                    isDM={true}
                                    dmChannelId={activeDMChannel.channel_id}
                                    onJumpToMessage={handleJumpToMessage}
                                    query={searchQuery}
                                    sortOrder={searchSortOrder}
                                    onSortChange={setSearchSortOrder}
                                />
                            </div>
                            )}
                        </div>
                    </div>
                );
            }
            return (
                <>
                    {isMobile && (
                        <div className="chat-header" style={{ position: 'sticky', top: 0, zIndex: 10 }}>
                            <div className="chat-header-left">
                                <button className="mobile-back-btn" onClick={handleMobileBack}>
                                    <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>
                                </button>
                                <span className="chat-header-name">Friends</span>
                            </div>
                        </div>
                    )}
                    <FriendsView onOpenDM={openDM} />
                </>
            );
        }

        if (activeChannel) {
            if (activeChannelObj?.type === 'voice') {
                return (
                    <div className="chat-container">
                        {isMobile && (
                            <div className="chat-header voice-header">
                                <div className="chat-header-left">
                                    <button className="mobile-back-btn" onClick={handleMobileBack}>
                                        <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>
                                    </button>
                                    <svg width="20" height="20" viewBox="0 0 24 24" style={{ color: 'var(--text-muted)', marginRight: 4 }}>
                                        <path fill="currentColor" d="M11.383 3.07904C11.009 2.92504 10.579 3.01004 10.293 3.29604L6.586 7.00304H3C2.45 7.00304 2 7.45304 2 8.00304V16.003C2 16.553 2.45 17.003 3 17.003H6.586L10.293 20.71C10.579 20.996 11.009 21.082 11.383 20.927C11.757 20.772 12 20.407 12 20.003V4.00304C12 3.59904 11.757 3.23404 11.383 3.07904Z" />
                                    </svg>
                                    <span className="chat-header-name">{activeChannelObj?.name}</span>
                                </div>
                            </div>
                        )}
                        <VoiceStage room={room} channelId={activeChannel} voiceStates={voiceStates} channelName={activeChannelObj?.name} />
                    </div>
                );
            }
            return (
                <div className="chat-container">
                    <ChatHeader
                        channelName={activeChannelObj?.name || activeChannel}
                        channelType="text"
                        channelId={activeChannel}
                        channelTopic={activeChannelObj?.topic}
                        onToggleMembers={() => setShowMembers(!showMembers)}
                        showMembers={effectiveShowMembers}
                        onTogglePinned={() => setShowPinned(p => !p)}
                        serverName={serverName}
                        isMobile={isMobile}
                        onMobileBack={handleMobileBack}
                        onOpenMembersScreen={() => setShowMobileMembersScreen(true)}
                        {...searchProps}
                    />
                    <div className="chat-content">
                        <ChatArea
                            channelId={activeChannel}
                            channelName={activeChannelObj?.name || activeChannel}
                            channelType="text"
                            channelKey={channelKeys[activeChannel]}
                            username={username}
                            userId={userId}
                            showMembers={effectiveShowMembers}
                            onToggleMembers={() => setShowMembers(!showMembers)}
                            onOpenDM={openDM}
                            showPinned={showPinned}
                            onTogglePinned={() => setShowPinned(false)}
                            jumpToMessageId={jumpToMessageId}
                            onClearJumpToMessage={clearJumpToMessage}
                        />
                        <MembersList
                            channelId={activeChannel}
                            visible={effectiveShowMembers}
                            onMemberClick={(member) => {}}
                            userId={userId}
                            myPermissions={myPermissions}
                            onOpenDM={openDM}
                            onStartCallWithUser={handleStartCallWithUser}
                        />
                        <SearchPanel
                            visible={showSearchResults}
                            onClose={handleCloseSearchResults}
                            channels={channels}
                            onJumpToMessage={handleJumpToMessage}
                            query={searchQuery}
                            sortOrder={searchSortOrder}
                            onSortChange={setSearchSortOrder}
                        />
                    </div>
                </div>
            );
        }

        return (
            <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#b9bbbe', flexDirection: 'column' }}>
                <h2>Welcome to {serverName}</h2>
                <p>No channels found.</p>
                <p>Click the <b>+</b> in the sidebar to create your first encrypted channel.</p>
            </div>
        );
    }

    const handleSetActiveDMChannel = useCallback((dm) => {
        setActiveDMChannel(dm);
        if (isMobile && dm) goToChat();
    }, [isMobile, goToChat]);

    const handleViewChange = useCallback((newView) => {
        setView(newView);
        if (isMobile) goToSidebar();
    }, [isMobile, goToSidebar]);

    if (!userId) {
        return (
            <div className="app-container">
                <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#b9bbbe' }}>
                    Loading...
                </div>
            </div>
        );
    }

    const sidebarElement = (
        <Sidebar
            channels={channels}
            categories={categories}
            activeChannel={activeChannel}
            onSelectChannel={handleSelectChannel}
            username={username}
            channelKeys={channelKeys}
            view={view}
            onViewChange={handleViewChange}
            onOpenDM={openDM}
            activeDMChannel={activeDMChannel}
            setActiveDMChannel={handleSetActiveDMChannel}
            dmChannels={dmChannels}
            userId={userId}
            serverName={serverName}
            serverIconUrl={serverIconUrl}
            isMobile={isMobile}
            onStartCallWithUser={handleStartCallWithUser}
            onOpenMobileSearch={() => setShowMobileSearchScreen(true)}
        />
    );

    return (
        <PresenceProvider userId={userId}>
            <div className={`app-container${isMobile ? ' is-mobile' : ''}`}>
                {isMobile ? (
                    <div
                        ref={trayRef}
                        {...swipeBindProps}
                        className={`mobile-swipe-tray${isSwiping ? ' is-swiping' : ''}`}
                        style={trayStyle}
                    >
                        <div className="mobile-swipe-panel">
                            {sidebarElement}
                        </div>
                        <div className="mobile-swipe-panel">
                            {renderMainContent()}
                        </div>
                    </div>
                ) : (
                    <>
                        {sidebarElement}
                        {renderMainContent()}
                    </>
                )}
                {showPiP && <FloatingStreamPiP onGoBackToStream={handleGoBackToStream} />}
                {showSearchDropdown && !isMobile && (
                    <SearchDropdown
                        visible={showSearchDropdown}
                        searchText={searchQuery}
                        channels={channels}
                        members={allMembers}
                        searchHistory={searchHistory}
                        onSelectFilter={handleSelectFilter}
                        onSelectHistoryItem={handleSelectHistoryItem}
                        onClearHistory={handleClearHistory}
                        onClearHistoryItem={handleClearHistoryItem}
                        anchorRef={searchInputRef}
                        onClose={handleCloseSearchDropdown}
                    />
                )}
                <ToastContainer />
                {showMobileMembersScreen && isMobile && activeChannel && activeChannelObj?.type !== 'voice' && (
                    <MobileMembersScreen
                        channelId={activeChannel}
                        channelName={activeChannelObj?.name || ''}
                        onClose={() => setShowMobileMembersScreen(false)}
                    />
                )}
                {showMobileSearchScreen && isMobile && (
                    <MobileSearchScreen
                        channels={channels}
                        allMembers={allMembers}
                        serverName={serverName}
                        onClose={() => setShowMobileSearchScreen(false)}
                        onSelectChannel={(channelId) => {
                            handleSelectChannel(channelId);
                            setShowMobileSearchScreen(false);
                        }}
                        onJumpToMessage={(channelId, messageId) => {
                            handleJumpToMessage(channelId, messageId);
                            setShowMobileSearchScreen(false);
                        }}
                    />
                )}
            </div>
        </PresenceProvider>
    );
};

export default Chat;
