import React, { useState, useEffect, useMemo, useRef, useCallback } from 'react';
import ReactDOM from 'react-dom';
import { useQuery } from 'convex/react';
import { api } from '../../../../convex/_generated/api';
import { useOnlineUsers } from '../contexts/PresenceContext';
import { useSearch } from '../contexts/SearchContext';
import { usePlatform } from '../platform';
import { LinkPreview } from './ChatArea';
import { extractUrls } from './MessageItem';
import Avatar from './Avatar';
import {
    formatTime, escapeHtml, linkifyHtml, formatEmojisHtml, getAvatarColor,
    SearchResultImage, SearchResultVideo, SearchResultFile
} from '../utils/searchRendering';

const USER_COLORS = ['#5865F2', '#EBA7CD', '#57F287', '#FEE75C', '#EB459E', '#ED4245'];

function getUserColor(name) {
    let hash = 0;
    for (let i = 0; i < name.length; i++) {
        hash = name.charCodeAt(i) + ((hash << 5) - hash);
    }
    return USER_COLORS[Math.abs(hash) % USER_COLORS.length];
}

const STATUS_COLORS = {
    online: '#3ba55c',
    idle: '#faa61a',
    dnd: '#ed4245',
    invisible: '#747f8d',
    offline: '#747f8d',
};

const BROWSE_TABS = ['Recent', 'Members', 'Channels'];
const SEARCH_TABS = ['Messages', 'Media', 'Links', 'Files'];

function formatTimeAgo(timestamp) {
    if (!timestamp) return '';
    const now = Date.now();
    const diff = now - timestamp;
    const minutes = Math.floor(diff / 60000);
    if (minutes < 1) return 'Active just now';
    if (minutes < 60) return `Active ${minutes}m ago`;
    const hours = Math.floor(minutes / 60);
    if (hours < 24) return `Active ${hours}h ago`;
    const days = Math.floor(hours / 24);
    if (days === 1) return 'Active 1d ago';
    return `Active ${days}d ago`;
}

const MobileSearchScreen = ({ channels, allMembers, serverName, onClose, onSelectChannel, onJumpToMessage }) => {
    const [activeTab, setActiveTab] = useState('Recent');
    const [visible, setVisible] = useState(false);
    const [searchText, setSearchText] = useState('');
    const { resolveStatus } = useOnlineUsers();
    const { search, isReady } = useSearch() || {};
    const { links } = usePlatform();
    const customEmojis = useQuery(api.customEmojis.list) || [];

    // Search result state
    const [messageResults, setMessageResults] = useState([]);
    const [mediaResults, setMediaResults] = useState([]);
    const [linkResults, setLinkResults] = useState([]);
    const [fileResults, setFileResults] = useState([]);
    const [searching, setSearching] = useState(false);
    const searchTimerRef = useRef(null);

    const channelIds = useMemo(() => channels.map(c => c._id), [channels]);
    const latestTimestampsRaw = useQuery(
        api.readState.getLatestMessageTimestamps,
        channelIds.length > 0 ? { channelIds } : "skip"
    ) || [];
    const latestTimestamps = useMemo(() => {
        const map = {};
        for (const item of latestTimestampsRaw) {
            map[item.channelId] = item.latestTimestamp;
        }
        return map;
    }, [latestTimestampsRaw]);

    const serverChannelIds = useMemo(() => new Set(channels.map(c => c._id)), [channels]);

    const channelMap = useMemo(() => {
        const map = {};
        for (const c of channels) map[c._id] = c.name;
        return map;
    }, [channels]);

    // Determine mode based on search text
    const hasQuery = searchText.trim().length > 0;

    useEffect(() => {
        requestAnimationFrame(() => setVisible(true));
    }, []);

    // Debounced search execution
    useEffect(() => {
        if (searchTimerRef.current) clearTimeout(searchTimerRef.current);

        if (!hasQuery || !search || !isReady) {
            setMessageResults([]);
            setMediaResults([]);
            setLinkResults([]);
            setFileResults([]);
            setSearching(false);
            return;
        }

        setSearching(true);
        searchTimerRef.current = setTimeout(() => {
            const q = searchText.trim();
            const filterToServer = (results) => results.filter(r => serverChannelIds.has(r.channel_id));

            // Messages search
            const msgs = filterToServer(search({ query: q, limit: 50 }));
            msgs.sort((a, b) => b.created_at - a.created_at);
            setMessageResults(msgs);

            // Media search (images + videos, deduped)
            const images = filterToServer(search({ query: q, hasImage: true, limit: 50 }));
            const videos = filterToServer(search({ query: q, hasVideo: true, limit: 50 }));
            const mediaMap = new Map();
            for (const r of [...images, ...videos]) mediaMap.set(r.id, r);
            const media = Array.from(mediaMap.values());
            media.sort((a, b) => b.created_at - a.created_at);
            setMediaResults(media);

            // Links search
            const lnks = filterToServer(search({ query: q, hasLink: true, limit: 50 }));
            lnks.sort((a, b) => b.created_at - a.created_at);
            setLinkResults(lnks);

            // Files search
            const files = filterToServer(search({ query: q, hasFile: true, limit: 50 }));
            files.sort((a, b) => b.created_at - a.created_at);
            setFileResults(files);

            setSearching(false);
        }, 300);

        return () => { if (searchTimerRef.current) clearTimeout(searchTimerRef.current); };
    }, [searchText, hasQuery, search, isReady, serverChannelIds]);

    // Reset to first search tab when entering search mode
    useEffect(() => {
        if (hasQuery) {
            setActiveTab('Messages');
        } else {
            setActiveTab('Recent');
        }
    }, [hasQuery]);

    const handleClose = () => {
        setVisible(false);
        setTimeout(onClose, 250);
    };

    const handleSelectChannel = (channelId) => {
        setVisible(false);
        setTimeout(() => {
            onSelectChannel(channelId);
            onClose();
        }, 250);
    };

    const handleResultClick = useCallback((result) => {
        if (onJumpToMessage) {
            setVisible(false);
            setTimeout(() => {
                onJumpToMessage(result.channel_id, result.id);
            }, 250);
        }
    }, [onJumpToMessage]);

    const query = searchText.toLowerCase().trim();

    // Browse mode data
    const recentChannels = useMemo(() => {
        const textChannels = channels.filter(c => c.type === 'text');
        return textChannels
            .map(c => ({ ...c, lastActivity: latestTimestamps[c._id] || 0 }))
            .sort((a, b) => b.lastActivity - a.lastActivity)
            .filter(c => !query || c.name.toLowerCase().includes(query));
    }, [channels, latestTimestamps, query]);

    const filteredMembers = useMemo(() => {
        if (!query) return allMembers;
        return allMembers.filter(m =>
            m.username.toLowerCase().includes(query) ||
            (m.displayName && m.displayName.toLowerCase().includes(query))
        );
    }, [allMembers, query]);

    const filteredChannels = useMemo(() => {
        if (!query) return channels;
        return channels.filter(c => c.name.toLowerCase().includes(query));
    }, [channels, query]);

    // Group results by channel
    const groupByChannel = useCallback((results) => {
        const grouped = {};
        for (const r of results) {
            const chName = channelMap[r.channel_id] || 'Unknown';
            if (!grouped[chName]) grouped[chName] = [];
            grouped[chName].push(r);
        }
        return grouped;
    }, [channelMap]);

    const renderSearchResult = useCallback((r) => (
        <div
            key={r.id}
            className="mobile-search-result-item"
            onClick={() => handleResultClick(r)}
        >
            <div
                className="mobile-search-result-avatar"
                style={{ backgroundColor: getAvatarColor(r.username) }}
            >
                {r.username?.[0]?.toUpperCase()}
            </div>
            <div className="mobile-search-result-body">
                <div className="mobile-search-result-header">
                    <span className="mobile-search-result-username" style={{ color: getAvatarColor(r.username) }}>
                        {r.username}
                    </span>
                    <span className="mobile-search-result-time">{formatTime(r.created_at)}</span>
                </div>
                {!(r.has_attachment && r.attachment_meta) && (
                    <div
                        className="mobile-search-result-content"
                        dangerouslySetInnerHTML={{ __html: formatEmojisHtml(linkifyHtml(r.snippet || escapeHtml(r.content)), customEmojis) }}
                        onClick={(e) => {
                            if (e.target.tagName === 'A' && e.target.href) {
                                e.preventDefault();
                                e.stopPropagation();
                                links.openExternal(e.target.href);
                            }
                        }}
                    />
                )}
                {r.has_attachment && r.attachment_meta ? (() => {
                    try {
                        const meta = JSON.parse(r.attachment_meta);
                        if (r.attachment_type?.startsWith('image/')) return <SearchResultImage metadata={meta} />;
                        if (r.attachment_type?.startsWith('video/')) return <SearchResultVideo metadata={meta} />;
                        return <SearchResultFile metadata={meta} />;
                    } catch { return <span className="search-result-badge">File</span>; }
                })() : r.has_attachment ? <span className="search-result-badge">File</span> : null}
                {r.has_link && r.content && (() => {
                    const urls = extractUrls(r.content);
                    return urls.map((url, i) => <LinkPreview key={i} url={url} />);
                })()}
            </div>
        </div>
    ), [handleResultClick, customEmojis, links]);

    const renderGroupedResults = useCallback((results) => {
        if (searching) {
            return <div className="mobile-search-empty">Searching...</div>;
        }
        if (!isReady) {
            return <div className="mobile-search-empty">Search database is loading...</div>;
        }
        if (results.length === 0) {
            return (
                <div className="mobile-search-empty">
                    <svg width="32" height="32" viewBox="0 0 24 24" fill="currentColor" style={{ opacity: 0.3, marginBottom: 8 }}>
                        <path d="M21.71 20.29L18 16.61A9 9 0 1016.61 18l3.68 3.68a1 1 0 001.42 0 1 1 0 000-1.39zM11 18a7 7 0 110-14 7 7 0 010 14z"/>
                    </svg>
                    <div>No results found</div>
                </div>
            );
        }
        const grouped = groupByChannel(results);
        return (
            <div className="mobile-search-results">
                {Object.entries(grouped).map(([chName, msgs]) => (
                    <div key={chName} className="mobile-search-channel-group">
                        <div className="mobile-search-channel-group-header">#{chName}</div>
                        {msgs.map(renderSearchResult)}
                    </div>
                ))}
            </div>
        );
    }, [searching, isReady, groupByChannel, renderSearchResult]);

    const renderContent = () => {
        // Search mode
        if (hasQuery) {
            switch (activeTab) {
                case 'Messages': return renderGroupedResults(messageResults);
                case 'Media': return renderGroupedResults(mediaResults);
                case 'Links': return renderGroupedResults(linkResults);
                case 'Files': return renderGroupedResults(fileResults);
                default: return renderGroupedResults(messageResults);
            }
        }

        // Browse mode
        switch (activeTab) {
            case 'Recent':
                return (
                    <div className="mobile-search-section">
                        <div className="mobile-search-section-title">Suggested</div>
                        {recentChannels.length === 0 ? (
                            <div className="mobile-search-empty">No channels found</div>
                        ) : (
                            recentChannels.map(channel => (
                                <button
                                    key={channel._id}
                                    className="mobile-search-channel-item"
                                    onClick={() => handleSelectChannel(channel._id)}
                                >
                                    <span className="mobile-search-channel-hash">#</span>
                                    <div className="mobile-search-channel-info">
                                        <span className="mobile-search-channel-name">{channel.name}</span>
                                        <span className="mobile-search-channel-activity">
                                            {formatTimeAgo(channel.lastActivity)}
                                        </span>
                                    </div>
                                </button>
                            ))
                        )}
                    </div>
                );

            case 'Members':
                return (
                    <div className="mobile-search-section">
                        {filteredMembers.length === 0 ? (
                            <div className="mobile-search-empty">No members found</div>
                        ) : (
                            filteredMembers.map(member => {
                                const effectiveStatus = resolveStatus(member.status, member.id);
                                return (
                                    <div key={member.id} className="mobile-search-member-item">
                                        <div className="member-avatar-wrapper">
                                            {member.avatarUrl ? (
                                                <img
                                                    className="member-avatar"
                                                    src={member.avatarUrl}
                                                    alt={member.username}
                                                    style={{ objectFit: 'cover' }}
                                                />
                                            ) : (
                                                <div
                                                    className="member-avatar"
                                                    style={{ backgroundColor: getUserColor(member.username) }}
                                                >
                                                    {(member.displayName || member.username).substring(0, 1).toUpperCase()}
                                                </div>
                                            )}
                                            <div
                                                className="member-status-dot"
                                                style={{ backgroundColor: STATUS_COLORS[effectiveStatus] || STATUS_COLORS.offline }}
                                            />
                                        </div>
                                        <span className="mobile-search-member-name">
                                            {member.displayName || member.username}
                                        </span>
                                    </div>
                                );
                            })
                        )}
                    </div>
                );

            case 'Channels':
                return (
                    <div className="mobile-search-section">
                        {filteredChannels.length === 0 ? (
                            <div className="mobile-search-empty">No channels found</div>
                        ) : (
                            filteredChannels.map(channel => (
                                <button
                                    key={channel._id}
                                    className="mobile-search-channel-item"
                                    onClick={() => handleSelectChannel(channel._id)}
                                >
                                    <span className="mobile-search-channel-hash">
                                        {channel.type === 'voice' ? (
                                            <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
                                                <path d="M12 3a1 1 0 0 0-1-1h-.06a1 1 0 0 0-.74.32L5.92 7H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h2.92l4.28 4.68a1 1 0 0 0 .74.32H11a1 1 0 0 0 1-1z" />
                                            </svg>
                                        ) : '#'}
                                    </span>
                                    <span className="mobile-search-channel-name">{channel.name}</span>
                                </button>
                            ))
                        )}
                    </div>
                );

            default:
                return (
                    <div className="mobile-search-empty">
                        {activeTab} coming soon
                    </div>
                );
        }
    };

    const currentTabs = hasQuery ? SEARCH_TABS : BROWSE_TABS;
    const getTabLabel = (tab) => {
        if (!hasQuery) return tab;
        switch (tab) {
            case 'Messages': return `Messages${!searching ? ` (${messageResults.length})` : ''}`;
            case 'Media': return `Media${!searching ? ` (${mediaResults.length})` : ''}`;
            case 'Links': return `Links${!searching ? ` (${linkResults.length})` : ''}`;
            case 'Files': return `Files${!searching ? ` (${fileResults.length})` : ''}`;
            default: return tab;
        }
    };

    return ReactDOM.createPortal(
        <div className={`mobile-search-screen${visible ? ' visible' : ''}`}>
            <div className="mobile-search-header">
                <button className="mobile-search-back" onClick={handleClose}>
                    <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>
                <div className="mobile-search-input-wrapper">
                    <svg className="mobile-search-input-icon" width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
                        <path d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z" />
                    </svg>
                    <input
                        className="mobile-search-input"
                        type="text"
                        placeholder="Search"
                        value={searchText}
                        onChange={(e) => setSearchText(e.target.value)}
                        autoFocus
                    />
                    {searchText && (
                        <button className="mobile-search-clear" onClick={() => setSearchText('')}>
                            <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
                                <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z" />
                            </svg>
                        </button>
                    )}
                </div>
            </div>
            <div className="mobile-search-tabs">
                {currentTabs.map(tab => (
                    <button
                        key={tab}
                        className={`mobile-search-tab${activeTab === tab ? ' active' : ''}`}
                        onClick={() => setActiveTab(tab)}
                    >
                        {getTabLabel(tab)}
                    </button>
                ))}
            </div>
            <div className="mobile-search-content">
                {renderContent()}
            </div>
        </div>,
        document.body
    );
};

export default MobileSearchScreen;
