'use client';

import React, { useEffect, useRef, useState, useCallback } from 'react';
import type { ChatRoom, ChatMessage } from './useChat';
import { theme, fontFamily } from './theme';
import { smartTime, preciseTime, dateHeader, renderMarkdown } from './chatHelpers';
import Avatar from './Avatar';

interface Props {
  room:           ChatRoom;
  messages:       ChatMessage[];
  currentUserId:  number;
  typingUsers:    number[];
  onBack:         () => void;
  onSend:         (roomId: number, msg: string, replyToId?: number) => void;
  onSendFile?:    (roomId: number, file: File, replyToId?: number) => void;
  onTyping:       (roomId: number) => void;
  onMarkRead:     (roomId: number) => void;
  isOnline:       (userId: number) => boolean;
  isExpanded?:    boolean;
  onToggleExpand?: () => void;
}

const API_BASE = process.env.NEXT_PUBLIC_API_URL?.replace('/api', '') ?? '';

const QUICK_EMOJIS = ['👍', '❤️', '😂', '😮', '😢', '🔥', '🎉', '👏'];
const FULL_EMOJIS = [
  '😀','😃','😄','😁','😆','😅','😂','🤣','😊','😇','🙂','🙃','😉','😌','😍','🥰',
  '😘','😗','😙','😚','😋','😛','😝','😜','🤪','🤨','🧐','🤓','😎','🤩','🥳','😏',
  '👍','👎','👏','🙌','👐','🤲','🙏','✊','👊','🤛','🤜','🫶','❤️','🧡','💛','💚',
  '💙','💜','🖤','🤍','💔','❣️','💕','💞','💓','💗','💖','💘','💝','🔥','✨','⭐',
];

function resolveFileUrl(fileUrl: string | undefined): string {
  if (!fileUrl) return '';
  if (fileUrl.startsWith('http') || fileUrl.startsWith('blob:') || fileUrl.startsWith('data:')) return fileUrl;
  return `${API_BASE}${fileUrl}`;
}

// ── Typing indicator ──
function TypingIndicator({ name }: { name?: string }) {
  return (
    <div style={{ display: 'flex', alignItems: 'flex-end', gap: 8, padding: '4px 8px 8px' }}>
      <Avatar name={name || 'U'} size={28} />
      <div style={{
        backgroundColor: '#fff',
        padding: '10px 14px',
        borderRadius: '18px 18px 18px 4px',
        boxShadow: theme.shadow.sm,
        border: `1px solid ${theme.gray[100]}`,
        display: 'flex', gap: 4, alignItems: 'center',
      }}>
        {[0,1,2].map(i => (
          <span key={i} style={{
            width: 7, height: 7, borderRadius: '50%',
            backgroundColor: theme.gray[400],
            animation: `tBounce 1.3s ease-in-out ${i*0.15}s infinite`,
          }} />
        ))}
      </div>
    </div>
  );
}

// ── Read receipt ticks ──
function MessageStatus({ msg, isMine }: { msg: ChatMessage; isMine: boolean }) {
  if (!isMine) return null;
  if (msg.pending) {
    return <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke={theme.gray[400]} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>;
  }
  return (
    <svg width="14" height="14" viewBox="0 0 18 14" fill="none">
      <path d="M1 7L5 11L11 4" stroke={theme.brand[600]} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
      <path d="M7 11L11 7M11 7L17 1" stroke={theme.brand[600]} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
}

// ── Message body renderer ──
function MessageBody({
  msg, isMine, onImageClick,
}: {
  msg: ChatMessage; isMine: boolean; onImageClick: (url: string) => void;
}) {
  const fullUrl = resolveFileUrl(msg.file_url);

  if (msg.type === 'image' && fullUrl) {
    return (
      <img
        src={fullUrl}
        alt={msg.file_name || 'image'}
        onClick={() => !msg.pending && onImageClick(fullUrl)}
        style={{
          maxWidth: 280, maxHeight: 320, minWidth: 120,
          borderRadius: theme.radius.md, display: 'block',
          cursor: msg.pending ? 'wait' : 'zoom-in',
          objectFit: 'cover',
        }}
      />
    );
  }

  if (msg.type === 'file' && fullUrl) {
    const handleDownload = () => {
      const link = document.createElement('a');
      link.href = fullUrl;
      link.target = '_blank';
      link.rel = 'noopener noreferrer';
      link.download = msg.file_name || 'file';
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    };
    return (
      <button onClick={handleDownload} style={{
        display: 'flex', alignItems: 'center', gap: 12,
        padding: '8px 4px', color: 'inherit',
        background: 'none', border: 'none', cursor: 'pointer',
        textAlign: 'left', font: 'inherit',
        minWidth: 220, maxWidth: 260,
      }}>
        <div style={{
          width: 40, height: 40, borderRadius: theme.radius.md,
          backgroundColor: isMine ? 'rgba(255,255,255,0.2)' : theme.brand[50],
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          flexShrink: 0,
        }}>
          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke={isMine ? '#fff' : theme.brand[600]} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
            <polyline points="14 2 14 8 20 8"/>
          </svg>
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{
            fontSize: 13, fontWeight: 600,
            overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
          }}>{msg.file_name || msg.message}</div>
          <div style={{ fontSize: 11, opacity: 0.75, marginTop: 2 }}>Tap to download</div>
        </div>
      </button>
    );
  }

  return <span style={{ wordBreak: 'break-word' }}>{renderMarkdown(msg.message, isMine)}</span>;
}

export default function ChatWindow({
  room, messages, currentUserId, typingUsers,
  onBack, onSend, onSendFile, onTyping, onMarkRead, isOnline,
  isExpanded = false, onToggleExpand,
}: Props) {
  if (!room) return null;

  const [input,        setInput]        = useState('');
  const [replyTo,      setReplyTo]      = useState<ChatMessage | null>(null);
  const [showEmoji,    setShowEmoji]    = useState(false);
  const [showSearch,   setShowSearch]   = useState(false);
  const [search,       setSearch]       = useState('');
  const [searchIdx,    setSearchIdx]    = useState(0);
  const [ctxMenu,      setCtxMenu]      = useState<{ msg: ChatMessage; x: number; y: number } | null>(null);
  const [showScroll,   setShowScroll]   = useState(false);
  const [copied,       setCopied]       = useState(false);
  const [imageModal,   setImageModal]   = useState<string>('');
  const [hoverMsgId,   setHoverMsgId]   = useState<number | null>(null);

  const bottomRef    = useRef<HTMLDivElement>(null);
  const inputRef     = useRef<HTMLTextAreaElement>(null);
  const scrollRef    = useRef<HTMLDivElement>(null);
  const searchRefs   = useRef<Record<number, HTMLDivElement | null>>({});
  const fileInputRef = useRef<HTMLInputElement>(null);

  const otherName = `${room.other_first_name ?? ''} ${room.other_last_name ?? ''}`.trim() || room.name || 'Chat';
  const otherId   = room.other_user_id ?? 0;
  const online    = isOnline(otherId);

  useEffect(() => { onMarkRead(room.id); inputRef.current?.focus(); }, [room.id]);

  const scrollToBottom = useCallback((smooth = true) => {
    bottomRef.current?.scrollIntoView({ behavior: smooth ? 'smooth' : 'auto' });
  }, []);

  useEffect(() => { scrollToBottom(); }, [messages, scrollToBottom]);

  const handleScroll = () => {
    const el = scrollRef.current;
    if (!el) return;
    setShowScroll(el.scrollHeight - el.scrollTop - el.clientHeight > 200);
  };

  useEffect(() => {
    const close = () => { setCtxMenu(null); setShowEmoji(false); };
    document.addEventListener('click', close);
    return () => document.removeEventListener('click', close);
  }, []);

  const searchResults = search.trim()
    ? messages.filter(m => m.message.toLowerCase().includes(search.toLowerCase()))
    : [];

  useEffect(() => {
    if (searchResults.length > 0) {
      const target = searchResults[searchIdx];
      searchRefs.current[target.id]?.scrollIntoView({ behavior: 'smooth', block: 'center' });
    }
  }, [searchIdx, search]);

  const handleSend = useCallback(() => {
    if (!input.trim()) return;
    onSend(room.id, input.trim(), replyTo?.id);
    setInput('');
    setReplyTo(null);
    setShowEmoji(false);
    setTimeout(() => inputRef.current?.focus(), 50);
  }, [input, onSend, room.id, replyTo]);

  const handleKey = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
    if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSend(); }
    if (e.key === 'Escape') setReplyTo(null);
  };

  const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
    setInput(e.target.value);
    onTyping(room.id);
    e.currentTarget.style.height = 'auto';
    e.currentTarget.style.height = Math.min(e.currentTarget.scrollHeight, 140) + 'px';
  };

  const addEmoji = (emoji: string) => {
    setInput(prev => prev + emoji);
    inputRef.current?.focus();
  };

  const copyMsg = (text: string) => {
    navigator.clipboard.writeText(text).then(() => { setCopied(true); setTimeout(() => setCopied(false), 1800); });
    setCtxMenu(null);
  };

  const handleFilePick = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file || !onSendFile) return;
    if (file.size > 10 * 1024 * 1024) { alert('File too large (max 10MB)'); e.target.value = ''; return; }
    onSendFile(room.id, file, replyTo?.id);
    setReplyTo(null);
    e.target.value = '';
  };

  // Group by date
  const grouped: { date: string; msgs: ChatMessage[] }[] = [];
  messages.forEach(msg => {
    const dateStr = new Date(msg.created_at).toDateString();
    const last = grouped[grouped.length - 1];
    if (last?.date === dateStr) last.msgs.push(msg);
    else grouped.push({ date: dateStr, msgs: [msg] });
  });

  const typingUserName = typingUsers.length > 0 ? otherName : '';

  return (
    <div className="qrs-chat-window" style={{ display: 'flex', flexDirection: 'column', height: '100%', position: 'relative', backgroundColor: '#fff', fontFamily }}>
      <style>{`
        @keyframes tBounce { 0%,60%,100%{transform:translateY(0);opacity:.4} 30%{transform:translateY(-6px);opacity:1} }
        @keyframes fadeIn  { from{opacity:0;transform:translateY(4px)} to{opacity:1;transform:translateY(0)} }
        @keyframes msgIn   { from{opacity:0;transform:translateY(8px) scale(0.96)} to{opacity:1;transform:translateY(0) scale(1)} }
        .qrs-msg-row:hover .qrs-msg-actions { opacity:1 !important; pointer-events: auto !important; }
        .qrs-ta { resize:none; border:none; outline:none; background:transparent; width:100%; font-family:inherit; font-size:14px; line-height:1.5; color:${theme.gray[900]}; }
        .qrs-ta::placeholder { color:${theme.gray[400]}; }
        ::-webkit-scrollbar{width:6px;height:6px}
        ::-webkit-scrollbar-track{background:transparent}
        ::-webkit-scrollbar-thumb{background:${theme.gray[200]};border-radius:99px}
        ::-webkit-scrollbar-thumb:hover{background:${theme.gray[300]}}
      `}</style>

      {/* ── Header (clean white with subtle border) ── */}
      <div style={{
        padding: '14px 18px',
        display: 'flex', alignItems: 'center', gap: 12,
        backgroundColor: '#fff',
        borderBottom: `1px solid ${theme.gray[100]}`,
        flexShrink: 0,
      }}>
        <button onClick={onBack} aria-label="Back"
          style={{
            background: 'transparent', border: 'none', borderRadius: theme.radius.md,
            color: theme.gray[600], cursor: 'pointer',
            padding: 6, display: 'flex', alignItems: 'center',
            transition: 'all 0.15s',
          }}
          onMouseEnter={e => { e.currentTarget.style.backgroundColor = theme.gray[100]; e.currentTarget.style.color = theme.gray[900]; }}
          onMouseLeave={e => { e.currentTarget.style.backgroundColor = 'transparent'; e.currentTarget.style.color = theme.gray[600]; }}
        >
          <svg width="20" height="20" 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>

        <Avatar name={otherName} size={40} status={online ? 'online' : 'offline'} />

        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{
            fontWeight: 600, color: theme.gray[900], fontSize: 14.5,
            overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
            letterSpacing: '-0.01em',
          }}>{otherName}</div>
          <div style={{ fontSize: 12, color: theme.gray[500], display: 'flex', alignItems: 'center', gap: 4 }}>
            {typingUsers.length > 0 ? (
              <span style={{ color: theme.brand[600], fontWeight: 500 }}>typing…</span>
            ) : online ? (
              <>
                <span style={{ width: 6, height: 6, borderRadius: '50%', backgroundColor: theme.success, display: 'inline-block' }} />
                Online
              </>
            ) : 'Offline'}
          </div>
        </div>

        <div style={{ display: 'flex', gap: 2 }}>
          <button onClick={e => { e.stopPropagation(); setShowSearch(v => !v); setSearch(''); }}
            aria-label="Search messages" title="Search"
            style={{
              background: showSearch ? theme.brand[50] : 'transparent',
              border: 'none', borderRadius: theme.radius.md,
              color: showSearch ? theme.brand[600] : theme.gray[600],
              cursor: 'pointer', padding: 8, display: 'flex', alignItems: 'center',
              transition: 'all 0.15s',
            }}
            onMouseEnter={e => { if (!showSearch) e.currentTarget.style.backgroundColor = theme.gray[100]; }}
            onMouseLeave={e => { if (!showSearch) e.currentTarget.style.backgroundColor = 'transparent'; }}
          >
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
          </button>
          {onToggleExpand && (
            <button onClick={onToggleExpand} aria-label={isExpanded ? 'Shrink' : 'Expand'} title={isExpanded ? 'Shrink' : 'Expand'}
              style={{
                background: 'transparent', border: 'none', borderRadius: theme.radius.md,
                color: theme.gray[600], cursor: 'pointer',
                padding: 8, display: 'flex', alignItems: 'center', transition: 'all 0.15s',
              }}
              onMouseEnter={e => { e.currentTarget.style.backgroundColor = theme.gray[100]; }}
              onMouseLeave={e => { e.currentTarget.style.backgroundColor = 'transparent'; }}
            >
              {isExpanded ? (
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="4 14 10 14 10 20"/><polyline points="20 10 14 10 14 4"/><line x1="14" y1="10" x2="21" y2="3"/><line x1="3" y1="21" x2="10" y2="14"/></svg>
              ) : (
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/><line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/></svg>
              )}
            </button>
          )}
        </div>
      </div>

      {/* Search bar */}
      {showSearch && (
        <div style={{
          padding: '10px 14px', backgroundColor: theme.gray[50],
          borderBottom: `1px solid ${theme.gray[100]}`,
          display: 'flex', alignItems: 'center', gap: 8, flexShrink: 0,
          animation: 'fadeIn 0.15s ease',
        }}>
          <input
            autoFocus value={search}
            onChange={e => { setSearch(e.target.value); setSearchIdx(0); }}
            placeholder="Search in this conversation..."
            style={{
              flex: 1, padding: '8px 12px', borderRadius: theme.radius.md,
              border: `1.5px solid ${theme.gray[200]}`, outline: 'none',
              fontSize: 13, fontFamily, backgroundColor: '#fff',
            }}
          />
          {searchResults.length > 0 && (
            <>
              <span style={{ fontSize: 12, color: theme.gray[500], whiteSpace: 'nowrap', fontWeight: 500 }}>
                {searchIdx + 1}/{searchResults.length}
              </span>
              <button onClick={() => setSearchIdx(i => Math.max(0, i - 1))} style={{ background: 'none', border: 'none', cursor: 'pointer', color: theme.gray[600], padding: 4 }}>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="18 15 12 9 6 15"/></svg>
              </button>
              <button onClick={() => setSearchIdx(i => Math.min(searchResults.length - 1, i + 1))} style={{ background: 'none', border: 'none', cursor: 'pointer', color: theme.gray[600], padding: 4 }}>
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
              </button>
            </>
          )}
          {search && searchResults.length === 0 && (
            <span style={{ fontSize: 12, color: theme.danger, fontWeight: 500 }}>Not found</span>
          )}
        </div>
      )}

      {/* Messages */}
      <div ref={scrollRef} onScroll={handleScroll} style={{
        flex: 1, overflowY: 'auto', padding: '16px 16px 8px',
        backgroundColor: theme.gray[50],
        display: 'flex', flexDirection: 'column', gap: 1,
      }}>
        {messages.length === 0 ? (
          <div style={{
            flex: 1, display: 'flex', flexDirection: 'column',
            alignItems: 'center', justifyContent: 'center', gap: 12,
          }}>
            <div style={{
              width: 64, height: 64, borderRadius: theme.radius.full,
              background: theme.gradient.brandSoft,
              display: 'flex', alignItems: 'center', justifyContent: 'center',
            }}>
              <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke={theme.brand[600]} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
              </svg>
            </div>
            <div style={{ textAlign: 'center' }}>
              <div style={{ fontSize: 15, fontWeight: 600, color: theme.gray[800], marginBottom: 4 }}>
                Start the conversation
              </div>
              <div style={{ fontSize: 13, color: theme.gray[500] }}>
                Send a message to {otherName}
              </div>
            </div>
          </div>
        ) : (
          grouped.map(group => (
            <React.Fragment key={group.date}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 12, margin: '16px 4px 12px' }}>
                <div style={{ flex: 1, height: 1, backgroundColor: theme.gray[200] }} />
                <span style={{
                  fontSize: 11, color: theme.gray[500], fontWeight: 600,
                  whiteSpace: 'nowrap', padding: '4px 12px',
                  backgroundColor: '#fff', borderRadius: theme.radius.full,
                  border: `1px solid ${theme.gray[200]}`,
                  letterSpacing: '0.02em',
                }}>{dateHeader(group.msgs[0].created_at)}</span>
                <div style={{ flex: 1, height: 1, backgroundColor: theme.gray[200] }} />
              </div>

              {group.msgs.map((msg, i) => {
                const isMine    = msg.sender_id === currentUserId;
                const prev      = group.msgs[i - 1];
                const next      = group.msgs[i + 1];
                const sameAbove = prev?.sender_id === msg.sender_id;
                const sameBelow = next?.sender_id === msg.sender_id;
                const isSearchHit = !!(search.trim() && msg.message.toLowerCase().includes(search.toLowerCase()) && searchResults[searchIdx]?.id === msg.id);
                const isImageMsg = msg.type === 'image' && !!msg.file_url;
                const isFileMsg  = msg.type === 'file' && !!msg.file_url;

                const br = isMine
                  ? `${sameAbove ? 6 : 16}px ${sameAbove ? 6 : 16}px 4px ${sameBelow ? 6 : 16}px`
                  : `${sameAbove ? 6 : 16}px ${sameAbove ? 6 : 16}px ${sameBelow ? 6 : 16}px 4px`;

                const repliedMsg = msg.reply_to_id ? messages.find(m => m.id === msg.reply_to_id) : null;

                return (
                  <div key={msg.id}
                    ref={el => { searchRefs.current[msg.id] = el; }}
                    className="qrs-msg-row"
                    onMouseEnter={() => setHoverMsgId(msg.id)}
                    onMouseLeave={() => setHoverMsgId(null)}
                    style={{
                      display: 'flex',
                      flexDirection: isMine ? 'row-reverse' : 'row',
                      alignItems: 'flex-end', gap: 8,
                      marginBottom: sameBelow ? 2 : 8,
                      paddingLeft: isMine ? 60 : 0,
                      paddingRight: isMine ? 0 : 60,
                      animation: 'msgIn 0.25s cubic-bezier(0.4,0,0.2,1)',
                    }}
                    onContextMenu={e => { e.preventDefault(); setCtxMenu({ msg, x: e.clientX, y: e.clientY }); }}
                  >
                    {!isMine && (
                      <div style={{ width: 32, flexShrink: 0 }}>
                        {!sameBelow && <Avatar name={msg.sender_name || 'U'} size={32} />}
                      </div>
                    )}

                    <div style={{ display: 'flex', flexDirection: 'column', alignItems: isMine ? 'flex-end' : 'flex-start', maxWidth: '100%' }}>
                      {!isMine && !sameAbove && (
                        <div style={{
                          fontSize: 11.5, color: theme.gray[600], marginBottom: 4,
                          marginLeft: 12, fontWeight: 600,
                        }}>{msg.sender_name}</div>
                      )}

                      <div style={{
                        background: msg.pending ? theme.gray[400] : isMine ? theme.gradient.brand : '#fff',
                        color:           isMine ? '#fff' : theme.gray[900],
                        padding:         (isImageMsg || isFileMsg) ? 4 : '10px 14px',
                        borderRadius:    br,
                        fontSize:        14, lineHeight: 1.5,
                        boxShadow:       isMine ? `0 2px 8px ${theme.brand[500]}33` : theme.shadow.sm,
                        border:          isMine ? 'none' : `1px solid ${theme.gray[100]}`,
                        wordBreak:       'break-word', maxWidth: '100%',
                        opacity:         msg.pending ? 0.85 : 1,
                        outline:         isSearchHit ? `2px solid ${theme.warning}` : 'none',
                        position:        'relative',
                        transition:      'opacity 0.2s',
                      }}>
                        {repliedMsg && (
                          <div style={{
                            borderLeft: `3px solid ${isMine ? 'rgba(255,255,255,0.5)' : theme.brand[500]}`,
                            paddingLeft: 10, marginBottom: 6, padding: '4px 8px',
                            backgroundColor: isMine ? 'rgba(255,255,255,0.12)' : theme.gray[50],
                            borderRadius: theme.radius.sm,
                            opacity: 0.95,
                          }}>
                            <div style={{ fontSize: 11, fontWeight: 700, color: isMine ? 'rgba(255,255,255,0.9)' : theme.brand[600], marginBottom: 2 }}>
                              {repliedMsg.sender_id === currentUserId ? 'You' : repliedMsg.sender_name}
                            </div>
                            <div style={{
                              fontSize: 12, color: isMine ? 'rgba(255,255,255,0.8)' : theme.gray[600],
                              overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: 240,
                            }}>{repliedMsg.message}</div>
                          </div>
                        )}

                        <MessageBody msg={msg} isMine={isMine} onImageClick={setImageModal} />

                        {/* Quick actions on hover */}
                        <div className="qrs-msg-actions" style={{
                          opacity: 0, pointerEvents: 'none',
                          position: 'absolute', top: -34,
                          right: isMine ? 0 : 'auto', left: isMine ? 'auto' : 0,
                          display: 'flex', gap: 2, transition: 'opacity 0.15s',
                          backgroundColor: '#fff', borderRadius: theme.radius.md,
                          padding: 4, boxShadow: theme.shadow.md,
                          border: `1px solid ${theme.gray[100]}`,
                          whiteSpace: 'nowrap',
                        }}>
                          <button onClick={(e) => { e.stopPropagation(); setReplyTo(msg); inputRef.current?.focus(); }}
                            title="Reply" aria-label="Reply"
                            style={{
                              background: 'none', border: 'none', cursor: 'pointer',
                              padding: 6, borderRadius: theme.radius.sm,
                              color: theme.gray[600], display: 'flex', alignItems: 'center',
                            }}
                            onMouseEnter={e => { e.currentTarget.style.backgroundColor = theme.gray[100]; }}
                            onMouseLeave={e => { e.currentTarget.style.backgroundColor = 'transparent'; }}
                          >
                            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="9 17 4 12 9 7"/><path d="M20 18v-2a4 4 0 0 0-4-4H4"/></svg>
                          </button>
                          <button onClick={(e) => { e.stopPropagation(); copyMsg(msg.message); }}
                            title="Copy" aria-label="Copy"
                            style={{
                              background: 'none', border: 'none', cursor: 'pointer',
                              padding: 6, borderRadius: theme.radius.sm,
                              color: theme.gray[600], display: 'flex', alignItems: 'center',
                            }}
                            onMouseEnter={e => { e.currentTarget.style.backgroundColor = theme.gray[100]; }}
                            onMouseLeave={e => { e.currentTarget.style.backgroundColor = 'transparent'; }}
                          >
                            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
                          </button>
                        </div>
                      </div>

                      {!sameBelow && (
                        <div style={{
                          fontSize: 11, color: theme.gray[400], marginTop: 4,
                          display: 'flex', alignItems: 'center', gap: 4, padding: '0 6px',
                          fontWeight: 500,
                        }}>
                          <span>{preciseTime(msg.created_at)}</span>
                          <MessageStatus msg={msg} isMine={isMine} />
                        </div>
                      )}
                    </div>
                  </div>
                );
              })}
            </React.Fragment>
          ))
        )}

        {typingUsers.length > 0 && <TypingIndicator name={typingUserName} />}

        <div ref={bottomRef} style={{ height: 4 }} />
      </div>

      {/* Scroll-to-bottom */}
      {showScroll && (
        <button onClick={() => scrollToBottom()}
          aria-label="Scroll to latest"
          style={{
            position: 'absolute', bottom: 96, right: 20,
            width: 36, height: 36, borderRadius: '50%',
            backgroundColor: '#fff', border: `1px solid ${theme.gray[200]}`,
            boxShadow: theme.shadow.md, cursor: 'pointer',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            color: theme.gray[700], zIndex: 10,
            animation: 'fadeIn 0.2s ease',
          }}>
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg>
        </button>
      )}

      {/* Reply preview */}
      {replyTo && (
        <div style={{
          padding: '10px 16px', backgroundColor: theme.gray[50],
          borderTop: `1px solid ${theme.gray[100]}`,
          borderLeft: `3px solid ${theme.brand[500]}`,
          display: 'flex', alignItems: 'center', gap: 10, flexShrink: 0,
          animation: 'fadeIn 0.15s ease',
        }}>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 11, fontWeight: 700, color: theme.brand[600], marginBottom: 2 }}>
              Replying to {replyTo.sender_id === currentUserId ? 'yourself' : replyTo.sender_name}
            </div>
            <div style={{ fontSize: 12.5, color: theme.gray[600], overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
              {replyTo.message}
            </div>
          </div>
          <button onClick={() => setReplyTo(null)} aria-label="Cancel reply"
            style={{
              background: 'transparent', border: 'none', cursor: 'pointer',
              color: theme.gray[500], padding: 4, borderRadius: theme.radius.sm,
              display: 'flex', alignItems: 'center',
            }}
            onMouseEnter={e => { e.currentTarget.style.backgroundColor = theme.gray[200]; }}
            onMouseLeave={e => { e.currentTarget.style.backgroundColor = 'transparent'; }}
          >×</button>
        </div>
      )}

      {/* Emoji picker */}
      {showEmoji && (
        <div onClick={e => e.stopPropagation()} style={{
          position: 'absolute', bottom: 76, left: 16,
          backgroundColor: '#fff', borderRadius: theme.radius.lg,
          padding: 12, boxShadow: theme.shadow.lg,
          border: `1px solid ${theme.gray[200]}`, zIndex: 20,
          width: 280, maxHeight: 240, overflowY: 'auto',
          animation: 'fadeIn 0.15s ease',
        }}>
          <div style={{ fontSize: 11, fontWeight: 700, color: theme.gray[500], marginBottom: 8, letterSpacing: '0.04em', textTransform: 'uppercase' }}>Frequently used</div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(8, 1fr)', gap: 4, marginBottom: 12 }}>
            {QUICK_EMOJIS.map(e => (
              <button key={e} onClick={() => addEmoji(e)} style={{
                background: 'none', border: 'none', cursor: 'pointer',
                fontSize: 22, padding: 4, borderRadius: theme.radius.sm,
                transition: 'all 0.1s',
              }}
                onMouseEnter={el => (el.currentTarget.style.backgroundColor = theme.gray[100])}
                onMouseLeave={el => (el.currentTarget.style.backgroundColor = 'transparent')}
              >{e}</button>
            ))}
          </div>
          <div style={{ fontSize: 11, fontWeight: 700, color: theme.gray[500], marginBottom: 8, letterSpacing: '0.04em', textTransform: 'uppercase' }}>All</div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(8, 1fr)', gap: 4 }}>
            {FULL_EMOJIS.map(e => (
              <button key={e} onClick={() => addEmoji(e)} style={{
                background: 'none', border: 'none', cursor: 'pointer',
                fontSize: 20, padding: 4, borderRadius: theme.radius.sm,
                transition: 'all 0.1s',
              }}
                onMouseEnter={el => (el.currentTarget.style.backgroundColor = theme.gray[100])}
                onMouseLeave={el => (el.currentTarget.style.backgroundColor = 'transparent')}
              >{e}</button>
            ))}
          </div>
        </div>
      )}

      {/* Input area */}
      <div style={{
        padding: '12px 14px',
        backgroundColor: '#fff',
        borderTop: `1px solid ${theme.gray[100]}`,
        flexShrink: 0,
        display: 'flex', gap: 8, alignItems: 'flex-end',
      }}>
        <button onClick={e => { e.stopPropagation(); setShowEmoji(v => !v); }}
          aria-label="Emoji"
          style={{
            background: showEmoji ? theme.brand[50] : 'transparent',
            border: 'none', borderRadius: theme.radius.md,
            color: showEmoji ? theme.brand[600] : theme.gray[600],
            cursor: 'pointer', padding: 8,
            display: 'flex', alignItems: 'center',
            transition: 'all 0.15s', flexShrink: 0,
          }}
          onMouseEnter={e => { if (!showEmoji) e.currentTarget.style.backgroundColor = theme.gray[100]; }}
          onMouseLeave={e => { if (!showEmoji) e.currentTarget.style.backgroundColor = 'transparent'; }}
        >
          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/><line x1="9" y1="9" x2="9.01" y2="9"/><line x1="15" y1="9" x2="15.01" y2="9"/></svg>
        </button>

        <input ref={fileInputRef} type="file"
          accept="image/*,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.zip,.rar"
          onChange={handleFilePick}
          style={{ display: 'none' }}
        />
        <button onClick={() => fileInputRef.current?.click()}
          aria-label="Attach file" title="Attach file or image"
          style={{
            background: 'transparent', border: 'none', borderRadius: theme.radius.md,
            color: theme.gray[600], cursor: 'pointer', padding: 8,
            display: 'flex', alignItems: 'center', transition: 'all 0.15s', flexShrink: 0,
          }}
          onMouseEnter={e => { e.currentTarget.style.backgroundColor = theme.gray[100]; }}
          onMouseLeave={e => { e.currentTarget.style.backgroundColor = 'transparent'; }}
        >
          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
        </button>

        <div style={{
          flex: 1,
          backgroundColor: theme.gray[50],
          borderRadius: theme.radius.lg,
          border: `1.5px solid ${theme.gray[200]}`,
          transition: 'all 0.15s',
          display: 'flex', alignItems: 'flex-end',
          padding: '2px 4px',
        }}>
          <textarea
            ref={inputRef}
            className="qrs-ta"
            value={input}
            onChange={handleInputChange}
            onKeyDown={handleKey}
            placeholder="Type a message…"
            rows={1}
            style={{ padding: '10px 12px', minHeight: 38, maxHeight: 140 }}
            onFocus={e => { if (e.currentTarget.parentElement) { e.currentTarget.parentElement.style.borderColor = theme.brand[500]; e.currentTarget.parentElement.style.backgroundColor = '#fff'; e.currentTarget.parentElement.style.boxShadow = `0 0 0 3px ${theme.brand[500]}20`; } }}
            onBlur={e =>  { if (e.currentTarget.parentElement) { e.currentTarget.parentElement.style.borderColor = theme.gray[200]; e.currentTarget.parentElement.style.backgroundColor = theme.gray[50]; e.currentTarget.parentElement.style.boxShadow = 'none'; } }}
          />
        </div>

        <button onClick={handleSend} disabled={!input.trim()}
          aria-label="Send"
          style={{
            width: 40, height: 40, borderRadius: '50%', border: 'none', flexShrink: 0,
            background: input.trim() ? theme.gradient.brand : theme.gray[200],
            color: input.trim() ? '#fff' : theme.gray[400],
            cursor: input.trim() ? 'pointer' : 'not-allowed',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            transition: 'all 0.2s cubic-bezier(0.4,0,0.2,1)',
            boxShadow: input.trim() ? `0 2px 8px ${theme.brand[500]}66` : 'none',
            transform: input.trim() ? 'scale(1)' : 'scale(0.92)',
          }}>
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
        </button>
      </div>

      {/* Context menu */}
      {ctxMenu && (() => {
        const captured = ctxMenu;
        return (
          <div onClick={e => e.stopPropagation()} style={{
            position: 'fixed', top: captured.y, left: captured.x,
            backgroundColor: '#fff', borderRadius: theme.radius.md, overflow: 'hidden',
            boxShadow: theme.shadow.lg, zIndex: 9999,
            minWidth: 180, animation: 'fadeIn 0.12s ease',
            border: `1px solid ${theme.gray[200]}`,
            padding: 4,
          }}>
            {[
              { label: 'Reply', icon: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="9 17 4 12 9 7"/><path d="M20 18v-2a4 4 0 0 0-4-4H4"/></svg>,
                action: () => { setReplyTo(captured.msg); setCtxMenu(null); inputRef.current?.focus(); } },
              { label: 'Copy text', icon: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>,
                action: () => copyMsg(captured.msg.message) },
            ].map((item, i) => (
              <button key={i} onClick={item.action} style={{
                display: 'flex', alignItems: 'center', gap: 10,
                width: '100%', padding: '8px 12px',
                background: 'none', border: 'none', textAlign: 'left',
                fontSize: 13, color: theme.gray[800], cursor: 'pointer',
                borderRadius: theme.radius.sm, fontFamily,
              }}
                onMouseEnter={e => (e.currentTarget.style.backgroundColor = theme.gray[100])}
                onMouseLeave={e => (e.currentTarget.style.backgroundColor = 'transparent')}
              >
                <span style={{ color: theme.gray[500] }}>{item.icon}</span>
                {item.label}
              </button>
            ))}
          </div>
        );
      })()}

      {/* Copied toast */}
      {copied && (
        <div style={{
          position: 'absolute', bottom: 80, left: '50%', transform: 'translateX(-50%)',
          backgroundColor: theme.gray[900], color: '#fff', padding: '8px 16px',
          borderRadius: theme.radius.full, fontSize: 12.5, fontWeight: 500, zIndex: 99,
          animation: 'fadeIn 0.15s ease', whiteSpace: 'nowrap',
          boxShadow: theme.shadow.lg, fontFamily,
          display: 'flex', alignItems: 'center', gap: 6,
        }}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke={theme.success} strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>
          Copied to clipboard
        </div>
      )}

      {/* Image fullscreen modal */}
      {imageModal && (
        <div onClick={() => setImageModal('')} style={{
          position: 'fixed', inset: 0, zIndex: 10005,
          backgroundColor: 'rgba(15,23,42,0.92)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          cursor: 'zoom-out', animation: 'fadeIn 0.2s ease',
          backdropFilter: 'blur(8px)',
        }}>
          <img src={imageModal} alt="preview"
            style={{ maxWidth: '92%', maxHeight: '92%', borderRadius: theme.radius.md, boxShadow: '0 20px 60px rgba(0,0,0,0.5)' }}
            onClick={e => e.stopPropagation()}
          />
          <button onClick={() => setImageModal('')} aria-label="Close" style={{
            position: 'absolute', top: 24, right: 24,
            width: 44, height: 44, borderRadius: '50%',
            background: 'rgba(255,255,255,0.15)', border: 'none', color: '#fff',
            cursor: 'pointer',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            backdropFilter: 'blur(8px)', transition: 'background 0.15s',
          }}
            onMouseEnter={e => { e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.25)'; }}
            onMouseLeave={e => { e.currentTarget.style.backgroundColor = 'rgba(255,255,255,0.15)'; }}
          >
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
          </button>
        </div>
      )}
    </div>
  );
}