import { useState, useRef, useEffect, memo } from 'react';
import { createPortal } from 'react-dom';
import { motion, AnimatePresence } from 'framer-motion';
import {
  Check,
  CheckCheck,
  Play,
  Pause,
  Download,
  FileText,
  Copy,
  Pencil,
  Trash2,
  Reply,
  Smile,
  MoreHorizontal,
  X,
  Volume2,
  Pin,
  Clock,
  Forward,
  Phone,
  Video,
  PhoneMissed,
  PhoneIncoming,
  PhoneOutgoing,
  BarChart2,
  Music,
} from 'lucide-react';
import { useAuthStore } from '../../../auth/application/authStore';
import { useChatStore } from '../../application/chatStore';
import { getSocket } from '../../../../core/infrastructure/socket';
import { useLang } from '../../../../core/infrastructure/i18n';
import { extractWaveform, getMediaUrl, generateAvatarColor, getInitials } from '../../../../core/utils/utils';
import { AUDIO_EXTENSIONS, type Message, type MediaItem, type Reaction, type ChatMember } from '../../../../core/domain/types';
import ImageLightbox from '../../../../core/presentation/components/ui/ImageLightbox';
import LinkPreview from './LinkPreview';
import Avatar from '../../../../core/presentation/components/ui/Avatar';

interface MessageBubbleProps {
  message: Message;
  isMine: boolean;
  showAvatar: boolean;
  onViewProfile?: (userId: string) => void;
  selectionMode?: boolean;
  isSelected?: boolean;
  onToggleSelect?: (id: string) => void;
  onStartSelectionMode?: (id: string) => void;
  onForward?: (id: string) => void;
}

function MessageBubble({
  message,
  isMine,
  showAvatar,
  onViewProfile,
  selectionMode,
  isSelected,
  onToggleSelect,
  onStartSelectionMode,
  onForward
}: MessageBubbleProps) {
  const { user } = useAuthStore();
  const { setReplyTo, setEditingMessage, pinnedMessages, chats } = useChatStore();
  const { t, lang } = useLang();
  const [showContext, setShowContext] = useState(false);
  const [contextPos, setContextPos] = useState({ x: 0, y: 0 });
  const [deleteMenuMode, setDeleteMenuMode] = useState(false);
  const [lightboxData, setLightboxData] = useState<{ index: number } | null>(null);
  const activeChatId = useChatStore(s => s.activeChat);
  const activeChat = useChatStore(s => s.chats.find(c => c.id === activeChatId));
  const isFavorites = activeChat?.type === 'favorites';
  const [isPlaying, setIsPlaying] = useState(false);
  const [audioProgress, setAudioProgress] = useState(0);
  const [audioDuration, setAudioDuration] = useState(0);
  const [waveformBars, setWaveformBars] = useState<number[] | null>(null);
  const audioRef = useRef<HTMLAudioElement>(null);
  const bubbleRef = useRef<HTMLDivElement>(null);
  const [quotedText, setQuotedText] = useState<string | null>(null);

  // Прочитано
  // Для своих сообщений: проверено, есть ли в readBy другие пользователи (получатели)
  // Для чужих сообщений: проверено, есть ли в readBy текущий пользователь
  const isRead = isMine
    ? message.readBy?.some((r) => r.userId !== user?.id)  // Кто-то кроме меня прочитал
    : message.readBy?.some((r) => r.userId === user?.id); // Я прочитал

  const timeStr = new Date(message.createdAt).toLocaleTimeString(lang === 'ru' ? 'ru-RU' : 'en-US', {
    hour: '2-digit',
    minute: '2-digit',
  });

  const handleContextMenu = (e: React.MouseEvent) => {
    e.preventDefault();
    e.stopPropagation();
    if (selectionMode) {
      onToggleSelect?.(message.id);
      return;
    }
    const rect = bubbleRef.current?.getBoundingClientRect();
    if (!rect) return;

    const selection = window.getSelection();
    const text = selection?.toString().trim();
    if (text && bubbleRef.current?.contains(selection?.anchorNode || null)) {
      setQuotedText(text);
    } else {
      setQuotedText(null);
    }

    const menuWidth = 208;
    const menuHeight = 350;
    let x = e.clientX;
    let y = e.clientY;

    if (x + menuWidth > window.innerWidth) x = window.innerWidth - menuWidth - 8;
    if (y + menuHeight > window.innerHeight) y = window.innerHeight - menuHeight - 8;

    setContextPos({ x, y });
    setShowContext(true);
  };

  const handleCopy = () => {
    if (message.content) {
      navigator.clipboard.writeText(message.content);
    }
    setShowContext(false);
  };

  const handleReply = () => {
    setReplyTo({ ...message, quote: quotedText });
    setShowContext(false);
    setQuotedText(null);
  };

  const handleEdit = () => {
    setEditingMessage(message);
    setShowContext(false);
  };

  const handleDeleteForAll = () => {
    const socket = getSocket();
    if (socket) {
      socket.emit('delete_messages', {
        messageIds: [message.id],
        chatId: message.chatId,
        deleteForAll: true,
      });
    }
    setShowContext(false);
    setDeleteMenuMode(false);
  };

  const handleDeleteForMe = () => {
    const socket = getSocket();
    if (socket) {
      socket.emit('delete_messages', {
        messageIds: [message.id],
        chatId: message.chatId,
        deleteForAll: false,
      });
    }
    useChatStore.getState().hideMessages([message.id], message.chatId);
    setShowContext(false);
    setDeleteMenuMode(false);
  };

  const chatForDelete = chats.find(c => c.id === message.chatId);
  const otherMember = chatForDelete?.members.find(m => m.user.id !== user?.id);
  const otherMemberName = chatForDelete?.type === 'personal'
    ? otherMember?.user.displayName || otherMember?.user.userName || otherMember?.user.username || ''
    : '';

  const isPinned = (pinnedMessages[message.chatId] || []).some(m => m.id === message.id);

  const handlePin = () => {
    const socket = getSocket();
    if (socket) {
      if (isPinned) {
        socket.emit('unpin_message', { messageId: message.id, chatId: message.chatId });
      } else {
        socket.emit('pin_message', { messageId: message.id, chatId: message.chatId });
      }
    }
    setShowContext(false);
  };

  const handleReaction = (emoji: string) => {
    const socket = getSocket();
    if (socket) {
      const existingReaction = message.reactions?.find(
        (r) => r.userId === user?.id && r.emoji === emoji
      );
      console.log('[Reaction] handleReaction:', {
        emoji,
        messageId: message.id,
        chatId: message.chatId,
        existingReaction: !!existingReaction,
        userId: user?.id
      });
      if (existingReaction) {
        console.log('[Reaction] Emitting remove_reaction');
        socket.emit('remove_reaction', { messageId: message.id, chatId: message.chatId, emoji });
      } else {
        console.log('[Reaction] Emitting add_reaction');
        socket.emit('add_reaction', { messageId: message.id, chatId: message.chatId, emoji });
      }
    } else {
      console.warn('[Reaction] Socket not available');
    }
    setShowContext(false);
  };

  const toggleAudio = () => {
    const audio = audioRef.current;
    if (!audio) return;

    if (isPlaying) {
      audio.pause();
      setIsPlaying(false);
    } else {
      if (audio.readyState < 2) {
        audio.load();
      }
      audio.play().then(() => {
        setIsPlaying(true);
      }).catch((err) => {
        console.error('Audio play error:', err);
        audio.load();
        audio.play().then(() => setIsPlaying(true)).catch(console.error);
      });
    }
  };

  useEffect(() => {
    const audio = audioRef.current;
    if (!audio) return;

    const onTimeUpdate = () => {
      if (audio.duration) {
        setAudioProgress((audio.currentTime / audio.duration) * 100);
      }
    };

    const onLoadedMetadata = () => {
      setAudioDuration(audio.duration);
    };

    const onEnded = () => {
      setIsPlaying(false);
      setAudioProgress(0);
    };

    audio.addEventListener('timeupdate', onTimeUpdate);
    audio.addEventListener('loadedmetadata', onLoadedMetadata);
    audio.addEventListener('ended', onEnded);

    return () => {
      audio.removeEventListener('timeupdate', onTimeUpdate);
      audio.removeEventListener('loadedmetadata', onLoadedMetadata);
      audio.removeEventListener('ended', onEnded);
    };
  }, []);

  useEffect(() => {
    const voiceUrl = message.media?.find((m) => m.type === 'voice')?.url;
    if (!voiceUrl) return;
    extractWaveform(voiceUrl, 28).then(setWaveformBars);
  }, [message.media]);

  const formatDuration = (sec: number) => {
    if (!sec || isNaN(sec) || !isFinite(sec)) return '0:00';
    const m = Math.floor(sec / 60);
    const s = Math.floor(sec % 60);
    return `${m}:${s.toString().padStart(2, '0')}`;
  };

  const contextMenuRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!showContext) return;
    const hideMenu = (e: MouseEvent) => {
      if (contextMenuRef.current?.contains(e.target as Node)) {
        return;
      }
      setShowContext(false);
      setDeleteMenuMode(false);
    };
    window.addEventListener('click', hideMenu, true);
    window.addEventListener('contextmenu', hideMenu, true);
    return () => {
      window.removeEventListener('click', hideMenu, true);
      window.removeEventListener('contextmenu', hideMenu, true);
    };
  }, [showContext]);

  if (message.isDeleted || message.isDeletedForUser) {
    return null;
  }

  if (message.type === 'call') {
    const isMissed = message.callStatus === 'missed' || message.callStatus === 'declined' || message.callStatus === 'cancelled';
    const statusText = isMissed
      ? (message.callStatus === 'missed' ? t('missedCall') : message.callStatus === 'declined' ? t('declinedCall') : t('cancelledCall'))
      : t('completedCall');

    const StatusIcon = isMissed ? PhoneMissed : (isMine ? PhoneOutgoing : PhoneIncoming);
    const CallIcon = message.callType === 'video' ? Video : StatusIcon;

    return (
      <div className={`flex ${isMine ? 'justify-end' : 'justify-start'} mb-3 px-4 group scroll-mt-20`} data-message-id={message.id}>
        <div
          onContextMenu={handleContextMenu}
          className={`group/call relative flex items-center gap-3.5 px-4 py-3 rounded-[1.25rem] border backdrop-blur-sm transition-all duration-300 cursor-default select-none
            ${isMine
              ? 'bg-primary/10 border-primary/20 hover:bg-primary/20 shadow-[0_4px_12px_rgba(48,150,229,0.08)]'
              : 'bg-surface-variant/10 border-white/5 hover:bg-surface-variant/15 shadow-[0_4px_12px_rgba(0,0,0,0.15)]'}`}>

          <div className={`w-11 h-11 rounded-2xl flex items-center justify-center shrink-0 shadow-inner group-hover/call:scale-105 transition-transform duration-500
             ${isMissed ? 'bg-red-500/15 text-red-400' : 'bg-emerald-500/15 text-emerald-400'}`}>
            <CallIcon size={22} strokeWidth={2.5} className={isMissed && message.callStatus === 'missed' ? 'animate-wiggle' : ''} />
          </div>

          <div className="flex-1 min-w-0 pr-4">
            <h4 className="text-[15px] font-bold text-white tracking-tight leading-tight mb-0.5 truncate">
              {message.callType === 'video' ? t('videoCall') : t('audioCall')}
            </h4>
            <div className="flex items-center gap-1.5 opacity-80">
              <span className={`text-[13px] font-medium ${isMissed ? 'text-red-400' : 'text-zinc-400'}`}>
                {statusText} {message.duration && message.duration > 0 ? `• ${formatDuration(message.duration)}` : ''}
              </span>
            </div>
          </div>

          <div className="flex flex-col items-end justify-between self-stretch pt-0.5">
            <div className="text-[10px] font-bold tracking-tight text-white/30 tabular-nums uppercase flex items-center gap-1">
              {isPinned && <Pin size={10} className="rotate-45 text-primary fill-primary/20" />}
              {timeStr}
            </div>
            {isMine && (
              <div className="opacity-60 flex gap-0.5">
                {isRead ? <CheckCheck size={12} className="text-primary" /> : <Check size={12} className="text-zinc-500" />}
              </div>
            )}
          </div>

          <div className="absolute inset-0 rounded-[1.25rem] bg-white/[0.03] opacity-0 group-hover/call:opacity-100 transition-opacity pointer-events-none" />
        </div>
      </div>
    );
  }

  const media = message.media || [];

  const isMediaGif = (m: MediaItem) => {
    if (m.type === 'gif') return true;
    if (m.url?.toLowerCase().includes('klipy') || m.url?.toLowerCase().endsWith('.gif')) return true;
    if (m.filename?.toLowerCase().includes('gif') || m.filename?.toLowerCase().endsWith('.mp4') || m.filename?.toLowerCase().endsWith('.gif')) return true;
    if (m.type === 'image' && m.url?.toLowerCase().endsWith('.mp4')) return true;
    return false;
  };

  const isAudioFile = (m: MediaItem) => m.type === 'audio' || AUDIO_EXTENSIONS.some(ext => m.filename?.toLowerCase().endsWith(ext));

  const hasImage = media.some((m) => m.type === 'image' || isMediaGif(m));
  const hasVoice = message.type === 'voice' || media.some((m) => m.type === 'voice');
  const hasAudio = !hasVoice && (message.type === 'audio' || media.some(isAudioFile));
  const hasVideo = media.some((m) => m.type === 'video' && !isMediaGif(m));
  const hasFile = media.some((m) => m.type !== 'image' && m.type !== 'voice' && m.type !== 'video' && !isAudioFile(m) && !isMediaGif(m));

  const reactionGroups: Record<string, { count: number; users: string[]; isMine: boolean; avatars: { url?: string | null, initials: string, colorClass?: string }[] }> = {};
  (message.reactions || []).forEach((r) => {
    if (!reactionGroups[r.emoji]) {
      reactionGroups[r.emoji] = { count: 0, users: [], isMine: false, avatars: [] };
    }
    reactionGroups[r.emoji].count++;
    const displayName = r.user?.displayName || r.user?.userName || r.user?.username || '?';
    reactionGroups[r.emoji].users.push(displayName);
    if (reactionGroups[r.emoji].avatars.length < 3) {
      reactionGroups[r.emoji].avatars.push({
        url: r.user?.avatar,
        initials: getInitials(displayName),
        colorClass: 'from-primary/80 to-primary-container'
      });
    }
    if (r.userId === user?.id) reactionGroups[r.emoji].isMine = true;
  });

  const senderName = message.sender?.displayName || message.sender?.userName || message.sender?.username || '';
  const senderAvatar = message.sender?.avatarUrl || message.sender?.avatar;

  const firstUrlMatch = message.content?.match(/https?:\/\/[^\s]+/);
  const firstUrl = firstUrlMatch ? firstUrlMatch[0] : null;

  const renderFormattedText = (text: string) => {
    if (!text) return text;
    const parts = text.split(/(\*\*[\s\S]*?\*\*|\*[\s\S]*?\*|_[\s\S]*?_|~[\s\S]*?~|`[\s\S]*?`|@\w+|https?:\/\/[^\s]+)/g);

    return parts.map((part, i) => {
      if (part.match(/^https?:\/\/[^\s]+$/)) {
        return (
          <a
            key={i}
            href={part}
            target="_blank"
            rel="noopener noreferrer"
            className="text-white underline decoration-white/30 underline-offset-2 hover:decoration-white transition-all"
            onClick={(e) => e.stopPropagation()}
          >
            {part}
          </a>
        );
      }
      if (part.startsWith('**') && part.endsWith('**')) return <strong key={i} className="font-bold">{part.slice(2, -2)}</strong>;
      if (part.startsWith('_') && part.endsWith('_')) return <em key={i} className="italic">{part.slice(1, -1)}</em>;
      if (part.startsWith('*') && part.endsWith('*')) return <em key={i} className="italic">{part.slice(1, -1)}</em>;
      if (part.startsWith('~') && part.endsWith('~')) return <del key={i} className="line-through opacity-80">{part.slice(1, -1)}</del>;
      if (part.startsWith('`') && part.endsWith('`')) {
        return <code key={i} className="font-mono text-[13px] bg-black/20 px-1 py-0.5 rounded-[0.35rem]">{part.slice(1, -1)}</code>;
      }
      if (part.startsWith('@') && part.length > 1) {
        const mentionUsername = part.slice(1);
        return (
          <span
            key={i}
            className="font-semibold text-sky-300 cursor-pointer hover:underline"
            onClick={(e) => {
              e.stopPropagation();
              const chat = chats.find(c => c.id === message.chatId);
              const members = chat?.members || [];
              const found = members.find((m) => m.user?.username === mentionUsername);
              if (found) {
                onViewProfile?.(found.user.id);
              }
            }}
          >{part}</span>
        );
      }
      return <span key={i}>{part}</span>;
    });
  };

  return (
    <>
      <div
        ref={bubbleRef}
        className={`flex ${isMine ? 'justify-end' : 'justify-start'} group mb-0.5 relative transition-colors duration-200 ${selectionMode ? 'px-4 -mx-4 cursor-pointer hover:bg-white/5 rounded-xl' : ''
          } ${isSelected ? 'bg-knot-500/10 hover:bg-knot-500/20' : ''}`}
        onClick={() => {
          if (selectionMode) onToggleSelect?.(message.id);
        }}
        onContextMenu={handleContextMenu}
      >
        {selectionMode && (
          <div className="absolute left-1 top-1/2 -translate-y-1/2 w-5 h-5 rounded-full border border-white/30 flex items-center justify-center transition-colors">
            {isSelected && <div className="w-5 h-5 rounded-full bg-knot-500 flex items-center justify-center">
              <Check size={12} className="text-white" />
            </div>}
          </div>
        )}

        {!isMine && (
          <div className="w-8 flex-shrink-0 mr-2 self-end">
            {showAvatar ? (
              <button onClick={() => onViewProfile?.(message.senderId)}>
                {senderAvatar ? (
                  <img src={senderAvatar} alt="" className="w-8 h-8 rounded-lg object-cover" />
                ) : (
                  <div className="w-8 h-8 rounded-lg bg-linear-to-br from-primary/80 to-primary flex items-center justify-center text-on-primary text-xs font-black shadow-inner">
                    {getInitials(senderName)}
                  </div>
                )}
              </button>
            ) : null}
          </div>
        )}

        <div className={`max-[500px]:max-w-[85%] max-w-[75%] lg:max-w-[65%] min-w-0 ${isMine ? 'items-end' : 'items-start'} flex flex-col`}>
          {!isMine && showAvatar && (
            <button
              className="text-xs font-medium text-knot-400 ml-3 mb-0.5 hover:underline"
              onClick={() => onViewProfile?.(message.senderId)}
            >
              {senderName}
            </button>
          )}

          {(() => {
            const hasReactions = Object.keys(reactionGroups).length > 0;
            const needsFrame = !!message.content || !!message.forwardedFrom || !!message.replyTo || hasVoice || hasAudio || hasFile || !!message.storyId;

            return (
              <div
                id={`msg-${message.id}`}
                onContextMenu={handleContextMenu}
                onDoubleClick={handleReply}
                title={t('reply') ? `${t('reply')} (Double Click)` : 'Double click to reply'}
                className={`cursor-pointer max-w-full min-w-[60px] transition-all duration-500 overflow-hidden ${!needsFrame
                  ? 'p-0 shadow-none border-none bg-transparent'
                  : isMine
                    ? 'bubble-sent px-4 py-3 hover:brightness-110'
                    : 'bubble-received px-4 py-3 hover:brightness-110'
                  }`}
              >

                {/* Reply */}
                {message.replyTo && (
                  <div
                    className={`mb-2 pl-3 py-2 cursor-pointer transition-all -mx-1 px-2 rounded-xl ${isMine ? 'bg-[#1a1a1a] border-l-[3px] border-l-primary hover:bg-[#202020]' : 'bg-white/5 border-l-[3px] border-l-primary hover:bg-white/10'
                      }`}
                    onClick={(e) => {
                      e.stopPropagation();
                      const el = document.getElementById(`msg-${message.replyToId}`);
                      if (el) {
                        el.scrollIntoView({ behavior: 'smooth', block: 'center' });
                        el.classList.add('highlight-message');
                        setTimeout(() => el.classList.remove('highlight-message'), 5000);
                      }
                    }}
                  >
                    <p className={`text-[12px] font-black uppercase tracking-wider mb-0.5 truncate ${isMine ? 'text-primary' : 'text-primary'}`}>
                      {message.replyTo.sender?.displayName || message.replyTo.sender?.userName || message.replyTo.sender?.username || ''}
                    </p>
                    <div className="flex items-center gap-1.5">
                      {message.replyTo.isDeleted ? (
                        <p className="text-[13px] text-zinc-500 italic truncate">{t('messageDeleted')}</p>
                      ) : (
                        <>
                          {message.replyTo.media && message.replyTo.media.length > 0 && !message.quote && (() => {
                            const m = message.replyTo.media[0];
                            const isMp4 = m.type === 'image' && m.url?.toLowerCase().endsWith('.mp4');
                            return (
                              <div className="w-8 h-8 rounded bg-black/20 overflow-hidden flex-shrink-0 relative">
                                {m.type === 'image' ? (
                                  isMp4 ? (
                                    <video src={getMediaUrl(m.url)} className="w-full h-full object-cover" muted playsInline />
                                  ) : (
                                    <img src={getMediaUrl(m.url)} className="w-full h-full object-cover" alt="" />
                                  )
                                ) : m.type === 'video' ? (
                                  <>
                                    <video src={getMediaUrl(m.url)} className="w-full h-full object-cover" muted playsInline />
                                    <div className="absolute inset-0 flex items-center justify-center bg-black/40"><Play size={10} className="text-white" /></div>
                                  </>
                                ) : (
                                  <div className="w-full h-full flex items-center justify-center"><FileText size={10} className="text-white/50" /></div>
                                )}
                              </div>
                            );
                          })()}
                          <p className={`text-[13px] line-clamp-1 break-words italic ${isMine ? 'text-zinc-200' : 'text-zinc-400'}`}>
                            {message.quote || message.replyTo.content || (message.replyTo.media && message.replyTo.media.length > 0 ? (() => {
                              const m = message.replyTo.media[0];
                              if (m.type === 'image' && m.url?.toLowerCase().endsWith('.mp4')) return 'GIF';
                              if (m.type === 'image') return t('photo');
                              if (m.type === 'video') return t('video');
                              if (m.type === 'voice') return t('voice');
                              return t('media');
                            })() : '')}
                          </p>
                        </>
                      )}
                    </div>
                  </div>
                )}

                {/* Story Reply Quote */}
                {message.storyId && (
                  <div
                    className={`mb-1.5 pl-2.5 py-0.5 border-l-[3px] transition-colors -mx-1 px-1 rounded-sm ${isMine ? 'border-l-white/80 hover:bg-white/10' : 'border-l-knot-500 hover:bg-knot-500/10'
                      }`}
                  >
                    <p className={`text-[11px] font-bold uppercase tracking-wider mb-1 ${isMine ? 'text-white/80' : 'text-knot-500/80'}`}>
                      {t('story')}
                    </p>
                    <div className="flex items-center gap-2">
                      {message.storyMediaUrl && (
                        <div className="w-8 h-8 rounded bg-black/20 overflow-hidden flex-shrink-0">
                          {message.storyMediaType === 'video' ? (
                            <div className="w-full h-full relative">
                              <video src={getMediaUrl(message.storyMediaUrl)} className="w-full h-full object-cover" />
                              <div className="absolute inset-0 flex items-center justify-center bg-black/20"><Play size={10} className="text-white fill-white" /></div>
                            </div>
                          ) : message.storyMediaType === 'image' ? (
                            <img src={getMediaUrl(message.storyMediaUrl)} className="w-full h-full object-cover" alt="" />
                          ) : (
                            <div className="w-full h-full flex items-center justify-center bg-knot-500/20"><FileText size={10} className="text-knot-400" /></div>
                          )}
                        </div>
                      )}
                      <p className={`text-[13px] line-clamp-2 break-words whitespace-pre-wrap ${isMine ? 'text-[#0a0a0a]/70' : 'text-zinc-600 dark:text-zinc-300'}`}>
                        {message.quote}
                      </p>
                    </div>
                  </div>
                )}
                {/* Рендер пересланного сообщения */}
                {message.forwardedFrom && (
                  <div
                    className="mb-1 text-[13.5px] cursor-pointer hover:bg-white/5 transition-colors -mx-1 px-1 rounded-sm"
                    onClick={() => onViewProfile?.(message.forwardedFromId!)}
                  >
                    <div className={`font-medium ${isMine ? 'text-white/90' : 'text-knot-500'}`}>
                      {(t('forwardedFrom' as any) === 'forwardedFrom' ? 'Переслано от' : t('forwardedFrom' as any))} <span className="font-semibold">{message.forwardedFrom.displayName || message.forwardedFrom.userName || message.forwardedFrom.username || ''}</span>
                    </div>
                  </div>
                )}

                {/* Изображения и Видео (Галерея) */}
                {(hasImage || hasVideo) && (() => {
                  const galleryMedia = media.filter(m => m.type === 'image' || m.type === 'video' || isMediaGif(m));
                  const isSingleGif = galleryMedia.length === 1 && isMediaGif(galleryMedia[0]);
                  const hasReactions = Object.keys(reactionGroups).length > 0;

                  return (
                    <div className={`
                ${needsFrame ? `-mx-[14px] ${message.forwardedFrom || message.replyTo || message.storyId ? 'mt-2' : '-mt-[8px]'} ${message.content ? 'mb-2' : hasReactions ? 'mb-1' : '-mb-[8px]'}` : ''}
                ${isSingleGif ? 'max-w-[260px]' : ''}
                overflow-hidden relative rounded-[1.25rem]
              `}>
                      <div className={`grid gap-[2px] ${galleryMedia.length > 1 ? 'w-[80vw] sm:w-[380px] md:w-[450px]' : 'w-full'} ${galleryMedia.length === 1 ? 'grid-cols-1' : 'grid-cols-6'
                        }`}>
                        {galleryMedia.map((m, idx) => {
                          const gif = isMediaGif(m);

                          let cellClass = '';
                          const count = galleryMedia.length;

                          if (count === 1) {
                            cellClass = isSingleGif ? 'max-h-[260px] aspect-auto' : 'max-h-[350px] sm:max-h-[450px] md:max-h-[500px] h-auto aspect-auto';
                          } else if (count === 2) {
                            cellClass = 'col-span-3 aspect-square';
                          } else if (count === 3) {
                            cellClass = idx === 0 ? 'col-span-6 aspect-[2/1] max-h-[300px]' : 'col-span-3 aspect-square';
                          } else if (count === 4) {
                            cellClass = 'col-span-3 aspect-square';
                          } else if (count === 5) {
                            cellClass = idx < 2 ? 'col-span-3 aspect-square' : 'col-span-2 aspect-square';
                          } else if (count === 6) {
                            cellClass = idx === 0 ? 'col-span-6 aspect-[2/1] max-h-[300px]' : idx < 3 ? 'col-span-3 aspect-[4/3]' : 'col-span-2 aspect-square';
                          } else {
                            // 7+
                            cellClass = 'col-span-2 aspect-square';
                          }

                          return (
                            <div
                              key={m.id}
                              className={`relative cursor-pointer group/video overflow-hidden transition-all hover:brightness-90 bg-zinc-900 ${cellClass}`}
                              onClick={() => setLightboxData({ index: idx })}
                            >
                              {gif ? (
                                (m.url?.toLowerCase().endsWith('.gif') || m.filename?.toLowerCase().endsWith('.gif')) ? (
                                  <img
                                    src={getMediaUrl(m.url)}
                                    alt=""
                                    className={`w-full h-full object-cover ${galleryMedia.length === 1 ? 'relative h-auto' : 'absolute inset-0'}`}
                                  />
                                ) : (
                                  <video
                                    src={getMediaUrl(m.url)}
                                    autoPlay loop muted playsInline preload="metadata"
                                    className={`w-full h-full object-cover min-h-[150px] min-w-[200px] bg-zinc-900 shadow-inner rounded-[1.25rem] ${galleryMedia.length === 1 ? 'relative h-auto' : 'absolute inset-0'}`}
                                  />
                                )
                              ) : m.type === 'video' ? (
                                <>
                                  {m.thumbnail ? (
                                    <img src={getMediaUrl(m.thumbnail)} className={`w-full h-full object-cover ${galleryMedia.length === 1 ? 'relative h-auto' : 'absolute inset-0'}`} alt="" />
                                  ) : (
                                    <video
                                      src={getMediaUrl(m.url)}
                                      preload="metadata"
                                      className={`w-full h-full object-cover bg-zinc-900 ${galleryMedia.length === 1 ? 'relative h-auto min-h-[160px]' : 'absolute inset-0'}`}
                                    />
                                  )}
                                  <div className={`absolute inset-0 flex items-center justify-center bg-black/20 group-hover/video:bg-black/40 transition-colors`}>
                                    <Play size={galleryMedia.length > 1 ? 24 : 48} className="text-white opacity-80" />
                                  </div>
                                </>
                              ) : (
                                <img
                                  src={getMediaUrl(m.url)}
                                  alt=""
                                  className={`w-full h-full object-cover ${galleryMedia.length === 1 ? 'relative h-auto' : 'absolute inset-0'}`}
                                />
                              )}
                            </div>
                          );
                        })}
                      </div>

                      {!message.content && (
                        <div className="absolute bottom-1.5 right-1.5 z-10 pointer-events-none flex justify-end">
                          <span className="text-[10px] font-bold text-on-surface-variant/40 bg-surface-container-highest/40 px-2 py-0.5 rounded-full flex items-center gap-1 backdrop-blur-md pointer-events-auto">
                            {isPinned && <Pin size={10} className="rotate-45 text-primary fill-primary/40" />}
                            {timeStr}
                            {isMine && !message.scheduledAt && (
                              <span className={`material-symbols-outlined text-[14px] ${isRead ? 'text-primary fill-1' : 'text-on-surface-variant/40'}`} style={{ fontVariationSettings: `'FILL' ${isRead ? 1 : 0}` }}>
                                {isRead ? 'done_all' : 'done'}
                              </span>
                            )}
                          </span>
                        </div>
                      )}
                    </div>
                  );
                })()}

                {/* Голосовое - Optimized Kinetic Layout */}
                {hasVoice && (
                  <div className="flex items-center gap-3 min-w-[200px] py-0.5">
                    <audio
                      ref={audioRef}
                      src={media.find((m) => m.type === 'voice')?.url}
                      preload="auto"
                    />
                    <button
                      onClick={toggleAudio}
                      className={`w-9 h-9 rounded-full flex items-center justify-center flex-shrink-0 ${isMine ? 'bg-white text-primary' : 'bg-primary text-white'} shadow-sm transition-all active:scale-95`}
                    >
                      {isPlaying ? (
                        <Pause size={16} fill="currentColor" />
                      ) : (
                        <Play size={16} fill="currentColor" className="ml-0.5" />
                      )}
                    </button>
                    <div className="flex-1 min-w-0">
                      <div
                        className="flex items-center gap-[2px] h-6 cursor-pointer"
                        onClick={(e) => {
                          const audio = audioRef.current;
                          if (!audio || !audio.duration) return;
                          const rect = e.currentTarget.getBoundingClientRect();
                          const pct = (e.clientX - rect.left) / rect.width;
                          audio.currentTime = pct * audio.duration;
                          setAudioProgress(pct * 100);
                          if (!isPlaying) toggleAudio();
                        }}
                      >
                        {(waveformBars || Array(28).fill(0.5)).map((val, i) => {
                          const barHeight = Math.max(10, val * 85);
                          const progress = audioProgress / 100;
                          const barProgress = i / 28;
                          const isActive = barProgress < progress;
                          return (
                            <div
                              key={i}
                              className={`flex-1 rounded-full transition-all duration-200 ${isActive
                                ? isMine ? 'bg-[#000000] opacity-70' : 'bg-primary'
                                : isMine ? 'bg-[#000000] opacity-20' : 'bg-white/30'
                                }`}
                              style={{ height: `${barHeight}%` }}
                            />
                          );
                        })}
                      </div>
                      <div className="flex justify-end mt-0.5">
                        <span className={`text-[10px] font-bold tabular-nums ${isMine ? 'text-[#0a0a0a]/60' : 'text-white/60'}`}>
                          {isPlaying
                            ? formatDuration(audioRef.current?.currentTime || 0)
                            : formatDuration(audioDuration || message.media?.find((m) => m.type === 'voice')?.duration || 0)}
                        </span>
                      </div>
                    </div>
                  </div>
                )}

                {/* Аудио (mp3 файлы) */}
                {hasAudio && (() => {
                  const audioMedia = media.find(isAudioFile);
                  const formatSize = (bytes?: number | null) => {
                    if (!bytes) return "";
                    if (bytes < 1024) return bytes + " B";
                    if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB";
                    if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(1) + " MB";
                    return (bytes / (1024 * 1024 * 1024)).toFixed(1) + " GB";
                  };

                  return (
                    <div className="min-w-[220px]">
                      {audioMedia?.filename && (
                        <div className="flex items-center gap-2 mb-2 min-w-0">
                          <Volume2 size={14} className={isMine ? 'text-[#0a0a0a]/60' : 'text-zinc-400'} />
                          <span className={`text-[11px] font-bold truncate ${isMine ? 'text-[#0a0a0a]/80' : 'text-zinc-200'}`}>{audioMedia.filename}</span>
                        </div>
                      )}
                      <div className="flex items-center gap-3">
                        <audio
                          ref={audioRef}
                          src={getMediaUrl(audioMedia?.url)}
                          preload="auto"
                        />
                        <button
                          onClick={toggleAudio}
                          className={`w-9 h-9 rounded-full flex items-center justify-center flex-shrink-0 ${isMine ? 'bg-[#0a0a0a]/10 hover:bg-[#0a0a0a]/20 text-[#0a0a0a]' : 'bg-primary text-white shadow-lg'} transition-all active:scale-95`}
                        >
                          {isPlaying ? (
                            <Pause size={16} fill="currentColor" />
                          ) : (
                            <Play size={16} fill="currentColor" className="ml-0.5" />
                          )}
                        </button>
                        <div className="flex-1 min-w-0">
                          <div className="flex items-center gap-[2px] h-6 cursor-pointer"
                            onClick={(e) => {
                              const audio = audioRef.current;
                              if (!audio || !audio.duration) return;
                              const rect = e.currentTarget.getBoundingClientRect();
                              const pct = (e.clientX - rect.left) / rect.width;
                              audio.currentTime = pct * audio.duration;
                              setAudioProgress(pct * 100);
                            }}>
                            {Array.from({ length: 28 }).map((_, i) => {
                              const barHeight = [40, 65, 35, 80, 50, 90, 45, 70, 55, 85, 30, 75, 60, 95, 40, 80, 50, 70, 35, 90, 55, 65, 45, 85, 60, 75, 50, 40][i] || 50;
                              const progress = audioProgress / 100;
                              const barProgress = i / 28;
                              const isActive = barProgress < progress;
                              return (
                                <div
                                  key={i}
                                  className={`flex-1 rounded-full transition-all duration-150 ${isActive
                                    ? isMine ? 'bg-[#0a0a0a]/70' : 'bg-primary'
                                    : isMine ? 'bg-[#0a0a0a]/10' : 'bg-white/20'
                                    }`}
                                  style={{ height: `${barHeight}%` }}
                                />
                              );
                            })}
                          </div>
                          <div className="flex justify-between items-center mt-0.5">
                            <span className={`text-[10px] font-bold tabular-nums ${isMine ? 'text-[#0a0a0a]/60' : 'text-zinc-500'}`}>
                              {isPlaying
                                ? formatDuration(audioRef.current?.currentTime || 0)
                                : (typeof audioMedia?.duration === 'number'
                                  ? formatDuration(audioMedia.duration)
                                  : (audioMedia?.duration || formatDuration(audioDuration || 0)))}
                            </span>
                            <div className="flex items-center gap-2">
                              <span className={`text-[10px] font-black uppercase tracking-tighter ${isMine ? 'text-[#0a0a0a]/40' : 'text-zinc-500'}`}>{formatSize(audioMedia?.size)}</span>
                              <a
                                href={getMediaUrl(audioMedia?.url)}
                                download={audioMedia?.filename || 'audio'}
                                target="_blank"
                                rel="noopener noreferrer"
                                className={`flex items-center justify-center p-1 rounded-md transition-all ${isMine ? 'hover:bg-[#0a0a0a]/10 text-[#0a0a0a]/40 hover:text-[#0a0a0a]' : 'hover:bg-white/10 text-zinc-500 hover:text-white'}`}
                              >
                                <Download size={12} />
                              </a>
                            </div>
                          </div>
                        </div>
                      </div>
                    </div>
                  );
                })()}

                {/* Файлы */}
                {hasFile &&
                  media
                    .filter((m) => m.type !== 'image' && m.type !== 'voice' && m.type !== 'video' && !isAudioFile(m) && m.type !== 'gif')
                    .map((m) => {
                      const formatSize = (bytes?: number | null) => {
                        if (!bytes) return "";
                        if (bytes < 1024) return bytes + " B";
                        if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB";
                        if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(1) + " MB";
                        return (bytes / (1024 * 1024 * 1024)).toFixed(1) + " GB";
                      };
                      return (
                        <a
                          key={m.id}
                          href={getMediaUrl(m.url)}
                          download={m.filename || 'file'}
                          target="_blank"
                          rel="noopener noreferrer"
                          className={`flex items-center gap-3 p-3 rounded-2xl ${isMine ? 'bg-[#0a0a0a]/5 hover:bg-[#0a0a0a]/10' : 'bg-zinc-900/50 hover:bg-zinc-800/80 border border-white/5'
                            } transition-all mb-1 group/file`}
                        >
                          <div className={`w-11 h-11 rounded-xl flex items-center justify-center ${isMine ? 'bg-[#0a0a0a]/10' : 'bg-primary/20'
                            } group-hover/file:scale-110 transition-transform`}>
                            <FileText size={22} className={isMine ? 'text-[#0a0a0a]' : 'text-primary'} />
                          </div>
                          <div className="flex-1 min-w-0">
                            <p className={`text-[13px] font-bold truncate ${isMine ? 'text-[#0a0a0a]' : 'text-zinc-200'}`}>{m.filename || t('fileLabel')}</p>
                            <p className={`text-[11px] font-medium ${isMine ? 'text-[#0a0a0a]/50' : 'text-zinc-500'}`}>
                              {formatSize(m.size) || t('download')}
                            </p>
                          </div>
                          <Download size={18} className={isMine ? 'text-[#0a0a0a]/30' : 'text-zinc-500'} />
                        </a>
                      );
                    })}

                {/* Опрос */}
                {message.type === 'poll' && message.pollOptions && (
                  <div className={`p-1.5 space-y-4 min-w-[260px] max-w-full ${isMine ? 'text-[#0a0a0a]' : 'text-zinc-200'}`}>
                    <div className="space-y-1">
                      <h4 className="text-[15px] font-bold leading-tight flex items-start gap-2 whitespace-pre-wrap break-words">
                        <BarChart2 size={18} className="mt-0.5 shrink-0 opacity-60" />
                        {message.content}
                      </h4>
                      <div className="flex items-center justify-between pl-7 pr-2">
                        <p className="text-[11px] font-medium opacity-50 uppercase tracking-widest">
                          {message.pollIsMultipleChoice ? t('multipleAnswers') : t('singleAnswer')}
                        </p>
                        {message.pollIsAnonymous && (
                          <span className="text-[10px] font-black uppercase tracking-tighter bg-black/5 px-2 py-0.5 rounded-sm opacity-40">
                            {t('anonymous')}
                          </span>
                        )}
                      </div>
                    </div>

                    <div className="space-y-2">
                      {(() => {
                        const hasVoted = (message.userVotedOptionIds && message.userVotedOptionIds.length > 0) ||
                          message.pollOptions?.some(o => o.voterIds?.includes(user?.id || ''));
                        const totalVotes = message.pollOptions!.reduce((sum, o) => sum + (o.voteCount || 0), 0);

                        return message.pollOptions.map((opt, idx) => {
                          const isVotedByMe = (message.userVotedOptionIds?.includes(opt.id)) ||
                            opt.voterIds?.includes(user?.id || '');
                          const percent = totalVotes > 0 ? Math.round(((opt.voteCount || 0) / totalVotes) * 100) : 0;

                          return (
                            <button
                              key={opt.id || idx}
                              disabled={hasVoted && !message.pollIsMultipleChoice} // If already voted and not multiple choice, disable. 
                              onClick={(e) => {
                                e.stopPropagation();
                                if (hasVoted && !message.pollIsMultipleChoice) return;

                                // Optimistic update for better UX
                                const currentVoted = message.userVotedOptionIds || [];
                                if (!currentVoted.includes(opt.id)) {
                                  useChatStore.getState().updateMessage({
                                    ...message,
                                    userVotedOptionIds: message.pollIsMultipleChoice ? [...currentVoted, opt.id] : [opt.id]
                                  });
                                }

                                const socket = getSocket();
                                if (socket) {
                                  socket.emit('vote_poll', {
                                    messageId: message.id,
                                    chatId: message.chatId,
                                    optionId: opt.id
                                  });
                                }
                              }}
                              className={`w-full group/opt relative rounded-2xl border transition-all duration-300 text-left p-3 flex flex-col gap-1.5
                            ${isMine
                                  ? 'bg-[#0a0a0a]/5 border-[#0a0a0a]/10 hover:bg-[#0a0a0a]/10 active:scale-[0.98] hover:z-20'
                                  : 'bg-white/5 border-white/5 hover:bg-white/10 active:scale-[0.98] hover:z-20'}`}
                            >
                              <div className="flex items-center justify-between relative z-10">
                                <div className="flex items-center gap-2 truncate flex-1">
                                  {isVotedByMe && <Check size={14} className={isMine ? 'text-[#0a0a0a]' : 'text-primary'} />}
                                  <span className="text-[14px] font-semibold truncate">{opt.text}</span>
                                </div>
                                {hasVoted && (
                                  <span className="text-[13px] font-black tabular-nums opacity-80">{percent}%</span>
                                )}
                              </div>

                              {hasVoted && (
                                <>
                                  <div className="relative h-1.5 w-full bg-white/5 rounded-full overflow-hidden z-10">
                                    <motion.div
                                      initial={false}
                                      animate={{ width: `${percent}%` }}
                                      transition={{ duration: 0.8, ease: "easeOut" }}
                                      className={`absolute inset-0 rounded-full ${isMine ? 'bg-[#0a0a0a]/40' : 'bg-primary'}`}
                                    />
                                  </div>

                                  <div className="flex items-center justify-between relative z-10 font-bold uppercase tracking-widest text-[10px]">
                                    <span className="opacity-40">{opt.voteCount || 0} {t('votes')}</span>
                                    {opt.voters && opt.voters.length > 0 && (
                                      <div className="relative group/voters flex -space-x-1.5 hover:space-x-0.5 transition-all duration-300">
                                        {opt.voters.slice(0, 5).map((voter) => (
                                          <Avatar
                                            key={voter.id}
                                            src={voter.avatar}
                                            name={voter.displayName}
                                            size="xs"
                                            className="ring-1 ring-white/20 shadow-lg"
                                          />
                                        ))}
                                        {opt.voters.length > 5 && (
                                          <div className="w-4 h-4 rounded-lg bg-white/10 flex items-center justify-center text-[7px] font-black tabular-nums ring-1 ring-white/20 text-white/50">
                                            +{opt.voters.length - 5}
                                          </div>
                                        )}

                                        {/* Подробный список при наведении */}
                                        <div className="absolute bottom-full right-0 mb-3 opacity-0 group-hover/voters:opacity-100 transition-all duration-300 pointer-events-none scale-95 group-hover/voters:scale-100 origin-bottom-right z-50">
                                          <div className="bg-[#1b1b1b] shadow-2xl rounded-2xl p-2 border border-white/10 min-w-[160px] backdrop-blur-xl">
                                            <div className="space-y-1">
                                              {opt.voters.map(v => (
                                                <div key={v.id} className="flex items-center gap-2.5 p-1.5 hover:bg-white/10 rounded-xl transition-colors">
                                                  <Avatar src={v.avatar} name={v.displayName} size="xs" />
                                                  <span className="text-[11px] font-bold text-white/90 truncate">{v.displayName}</span>
                                                </div>
                                              ))}
                                            </div>
                                          </div>
                                        </div>
                                      </div>
                                    )}
                                  </div>
                                </>
                              )}
                            </button>
                          );
                        });
                      })()}
                    </div>
                    {(() => {
                      const hasVoted = (message.userVotedOptionIds && message.userVotedOptionIds.length > 0) ||
                        message.pollOptions?.some(o => o.voterIds?.includes(user?.id || ''));
                      const totalVotes = message.pollOptions!.reduce((sum, o) => sum + (o.voteCount || 0), 0);
                      if (hasVoted) {
                        return <div className="text-[10px] font-black opacity-30 mt-2 px-2">ВСЕГО ПРОГОЛОСОВАЛО: {totalVotes}</div>
                      }
                      return null;
                    })()}
                  </div>
                )}

                {/* Текст */}
                {message.content && message.type !== 'poll' && (() => {
                  const onlyEmojiRegex = /^[\p{Extended_Pictographic}\s]+$/u;
                  const isOnlyEmojis = onlyEmojiRegex.test(message.content) && message.content.length <= 15;
                  return (
                    <div className="flex items-end gap-2 text-sm w-full">
                      <div className="flex-1 min-w-0 w-full">
                        <p className={`whitespace-pre-wrap break-words leading-relaxed w-full ${isOnlyEmojis ? 'text-5xl my-1' : ''} ${isMine ? 'text-[#0a0a0a] font-normal' : 'text-zinc-200'}`}>
                          {renderFormattedText(message.content)}
                        </p>
                        {firstUrl && !hasImage && !hasVideo && !hasFile && (
                          <div className="w-full mt-1 mb-1 relative overflow-hidden">
                            <LinkPreview url={firstUrl} />
                          </div>
                        )}
                      </div>
                      <span className={`text-[10px] font-bold flex-shrink-0 flex items-center gap-0.5 self-end float-right leading-none ${isOnlyEmojis ? '-mb-1' : 'mb-0.5'} ${isMine ? 'text-[#0a0a0a]/50' : 'text-on-surface-variant/40'}`}>
                        {message.isEdited && <span className="mr-0.5">{t('edited')}</span>}
                        {message.scheduledAt && <span className="material-symbols-outlined text-[12px] text-amber-400 mr-0.5">schedule</span>}
                        {isPinned && <Pin size={10} className={`rotate-45 ${isMine ? 'text-[#0a0a0a]/60 fill-[#0a0a0a]/20' : 'text-primary fill-primary/20'} mr-0.5`} />}
                        {timeStr}
                        {isMine && !message.scheduledAt && (
                          <span className={`material-symbols-outlined text-[14px] ${isRead ? 'text-[#0a0a0a]/80 fill-1' : 'text-[#0a0a0a]/40'}`} style={{ fontVariationSettings: `'FILL' ${isRead ? 1 : 0}` }}>
                            {isRead ? 'done_all' : 'done'}
                          </span>
                        )}
                      </span>
                    </div>
                  );
                })()}


              </div>
            );
          })()}

          {Object.keys(reactionGroups).length > 0 && (
            <div className={`flex flex-wrap gap-1.5 mt-2 ${isMine ? 'justify-end' : 'justify-start'} relative z-20`}>
              {Object.entries(reactionGroups).map(([emoji, data]) => (
                <button
                  key={emoji}
                  onClick={(e) => { e.stopPropagation(); handleReaction(emoji); }}
                  className={`flex items-center gap-2 px-2.5 py-1.5 rounded-[10px] transition-all border ${data.isMine
                    ? 'bg-primary/20 border-primary text-white shadow-lg'
                    : 'bg-[#201F1F] border-white/5 text-zinc-300 hover:bg-[#2a2a2a]'
                    } shadow-md group/react`}
                  title={data.users.join(', ')}
                >
                  <span className="text-[14px] leading-none">{emoji}</span>
                  {data.count > 1 && (
                    <span className="text-[13px] font-bold tabular-nums">{data.count}</span>
                  )}
                </button>
              ))}
            </div>
          )}
        </div>

        {isMine && (
          <div className="w-8 flex-shrink-0 ml-2 self-end">
            {showAvatar ? (
              <button onClick={() => onViewProfile?.(message.senderId)}>
                {senderAvatar ? (
                  <img src={senderAvatar} alt="" className="w-8 h-8 rounded-lg object-cover" />
                ) : (
                  <div className="w-8 h-8 rounded-lg bg-linear-to-br from-primary/80 to-primary flex items-center justify-center text-on-primary text-[10px] font-black shadow-inner">
                    {getInitials(senderName)}
                  </div>
                )}
              </button>
            ) : null}
          </div>
        )}
      </div>

      {typeof document !== 'undefined' && createPortal(
        <AnimatePresence>
          {showContext && (
            <motion.div
              ref={contextMenuRef}
              initial={{ opacity: 0, scale: 0.9 }}
              animate={{ opacity: 1, scale: 1 }}
              exit={{ opacity: 0, scale: 0.9 }}
              className="fixed z-[9999] w-52 rounded-[1.25rem] bg-[#1a1a1a] shadow-[0_20px_50px_rgba(0,0,0,0.5)] py-1.5 overflow-hidden border border-white/10"
              style={{ left: contextPos.x, top: contextPos.y }}
              onClick={(e) => e.stopPropagation()}
              onContextMenu={(e) => {
                e.preventDefault();
                e.stopPropagation();
              }}
            >
              {deleteMenuMode ? (
                <>
                  <div className="flex items-center gap-2 px-3 py-2.5 border-b border-border">
                    <button
                      onClick={() => setDeleteMenuMode(false)}
                      className="p-1 rounded-lg hover:bg-surface-hover transition-colors text-zinc-400 hover:text-white"
                    >
                      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="15 18 9 12 15 6" /></svg>
                    </button>
                    <span className="text-sm font-medium text-zinc-300">{t('delete')}</span>
                  </div>
                  <button
                    onClick={handleDeleteForMe}
                    className="flex items-center gap-3 w-full px-4 py-2.5 text-sm text-zinc-300 hover:bg-surface-hover hover:text-white transition-colors"
                  >
                    <Trash2 size={16} className="text-zinc-400" />
                    {t('deleteForMe')}
                  </button>
                  <button
                    onClick={handleDeleteForAll}
                    className="flex items-center gap-3 w-full px-4 py-2.5 text-sm text-red-400 hover:bg-red-500/10 hover:text-red-300 transition-colors"
                  >
                    <Trash2 size={16} />
                    {chatForDelete?.type === 'personal' && otherMemberName
                      ? `${t('deleteAlsoFor')} ${otherMemberName}`
                      : t('deleteForAll')}
                  </button>
                </>
              ) : (
                <>
                  <div className="flex items-center gap-1 px-3 py-2 border-b border-border">
                    {['👍', '❤️', '😂', '😮', '😢', '🔥'].map((emoji) => (
                      <button
                        key={emoji}
                        onClick={() => handleReaction(emoji)}
                        className="w-8 h-8 flex items-center justify-center rounded-lg hover:bg-surface-hover transition-colors text-lg"
                      >
                        {emoji}
                      </button>
                    ))}
                  </div>

                  <button
                    onClick={handleReply}
                    className="flex items-center gap-3 w-full px-4 py-2.5 text-sm text-zinc-300 hover:bg-surface-hover hover:text-white transition-colors"
                  >
                    <Reply size={16} />
                    {quotedText ? t('replyWithQuote') : t('reply')}
                  </button>

                  <button
                    onClick={() => {
                      setShowContext(false);
                      onStartSelectionMode?.(message.id);
                    }}
                    className="flex items-center gap-3 w-full px-4 py-2.5 text-sm text-zinc-300 hover:bg-surface-hover hover:text-white transition-colors"
                  >
                    <CheckCheck size={16} />
                    {t('select')}
                  </button>

                  <button
                    onClick={() => {
                      setShowContext(false);
                      onForward?.(message.id);
                    }}
                    className="flex items-center gap-3 w-full px-4 py-2.5 text-sm text-zinc-300 hover:bg-surface-hover hover:text-white transition-colors"
                  >
                    <Forward size={16} />
                    {t('forward')}
                  </button>

                  <button
                    onClick={handlePin}
                    className="flex items-center gap-3 w-full px-4 py-2.5 text-sm text-zinc-300 hover:bg-surface-hover hover:text-white transition-colors"
                  >
                    <Pin size={16} />
                    {isPinned ? t('unpinMessage') : t('pinMessage')}
                  </button>

                  {message.content && (
                    <button
                      onClick={handleCopy}
                      className="flex items-center gap-3 w-full px-4 py-2.5 text-sm text-zinc-300 hover:bg-surface-hover hover:text-white transition-colors"
                    >
                      <Copy size={16} />
                      {t('copy')}
                    </button>
                  )}

                  {isMine && message.content && (
                    <button
                      onClick={handleEdit}
                      className="flex items-center gap-3 w-full px-4 py-2.5 text-sm text-zinc-300 hover:bg-surface-hover hover:text-white transition-colors"
                    >
                      <Pencil size={16} />
                      {t('edit')}
                    </button>
                  )}

                  <div className="border-t border-border my-1" />
                  <button
                    onClick={() => isFavorites ? handleDeleteForMe() : setDeleteMenuMode(true)}
                    className="flex items-center gap-3 w-full px-4 py-2.5 text-sm text-red-400 hover:bg-red-500/10 transition-colors"
                  >
                    <Trash2 size={16} />
                    {t('delete')}
                  </button>
                </>
              )}
            </motion.div>
          )}
        </AnimatePresence>,
        document.body
      )}

      <AnimatePresence>
        {lightboxData && (
          <ImageLightbox
            images={media.filter(m => m.type === 'image' || m.type === 'video' || isMediaGif?.(m) || m.type === 'gif').map(m => ({
              url: getMediaUrl(m.url),
              type: (isMediaGif?.(m) || m.type === 'gif' || (m.type === 'image' && m.url?.toLowerCase().endsWith('.mp4'))) ? 'gif' : m.type
            }))}
            initialIndex={lightboxData.index}
            onClose={() => setLightboxData(null)}
          />
        )}
      </AnimatePresence>
    </>
  );
}

export default memo(MessageBubble);
