import { useState, useRef, useEffect, useCallback } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import {
  Send,
  Paperclip,
  Smile,
  Mic,
  X,
  Reply,
  Pencil,
  Image as ImageIcon,
  FileText,
  Music,
  Clock,
  ChevronLeft,
  ChevronRight,
  Calendar,
  Check,
} from 'lucide-react';
import { useChatStore } from '../../application/chatStore';
import { useAuthStore } from '../../../auth/application/authStore';
import { ChatApi } from '../../infrastructure/chatApi';
import { getSocket } from '../../../../core/infrastructure/socket';
import { useLang } from '../../../../core/infrastructure/i18n';
import { AUDIO_EXTENSIONS, MAX_FILE_SIZE, type ChatMember } from '../../../../core/domain/types';
import { useNotificationStore } from '../../../../core/application/stores/notificationStore';
import EmojiPicker from './EmojiPicker';

interface Attachment {
  file: File;
  preview?: string;
  type: 'image' | 'video' | 'file' | 'audio';
}

interface MessageInputProps {
  chatId: string;
}

export default function MessageInput({ chatId }: MessageInputProps) {
  const { user } = useAuthStore();
  const { t } = useLang();
  const { replyTo, editingMessage, setReplyTo, setEditingMessage, getDraft, setDraft, chats } = useChatStore();
  const [text, setText] = useState(() => getDraft(chatId));

  // Get current chat members for @mentions
  const chat = chats.find(c => c.id === chatId);
  const isGroup = chat?.type === 'group';
  const chatMembers = (chat?.members || []).filter((m) => m.user.id !== user?.id);
  const [showEmoji, setShowEmoji] = useState(false);
  const [isRecording, setIsRecording] = useState(false);
  const [recordingTime, setRecordingTime] = useState(0);
  const [showAttachMenu, setShowAttachMenu] = useState(false);
  const [attachments, setAttachments] = useState<Attachment[]>([]);
  const [isSending, setIsSending] = useState(false);
  const [isDragging, setIsDragging] = useState(false);
  const [formatMenu, setFormatMenu] = useState<{ show: boolean; x: number; y: number }>({ show: false, x: 0, y: 0 });
  const [mentionQuery, setMentionQuery] = useState<string | null>(null);
  const [mentionIndex, setMentionIndex] = useState(0);
  const [showSchedule, setShowSchedule] = useState(false);
  const [scheduleDate, setScheduleDate] = useState('');
  const [scheduleStep, setScheduleStep] = useState<'presets' | 'custom'>('presets');
  const [scheduleHour, setScheduleHour] = useState('12');
  const [scheduleMinute, setScheduleMinute] = useState('00');
  const [scheduleCalDate, setScheduleCalDate] = useState(''); // YYYY-MM-DD
  const [scheduleCalMonth, setScheduleCalMonth] = useState(new Date().getMonth());
  const [scheduleCalYear, setScheduleCalYear] = useState(new Date().getFullYear());
  const [scheduleToast, setScheduleToast] = useState<string | null>(null);

  // Filtered members for @mention
  const filteredMembers = mentionQuery !== null && isGroup
    ? chatMembers.filter((m) => {
        const q = mentionQuery.toLowerCase();
        return (m.user.displayName || '').toLowerCase().includes(q) 
          || (m.user.userName || '').toLowerCase().includes(q)
          || (m.user.username || '').toLowerCase().includes(q);
      }).slice(0, 6)
    : [];

  const insertMention = (member: ChatMember) => {
    const el = inputRef.current;
    if (!el) return;
    const username = member.user.userName || member.user.username;
    if (!username) return;
    const cursorPos = el.selectionStart;
    const before = text.substring(0, cursorPos);
    const after = text.substring(cursorPos);
    // Find the @ that started this mention
    const atIdx = before.lastIndexOf('@');
    if (atIdx === -1) return;
    const newText = before.substring(0, atIdx) + `@${username} ` + after;
    setText(newText);
    setDraft(chatId, newText);
    setMentionQuery(null);
    setMentionIndex(0);
    setTimeout(() => {
      el.focus();
      const newPos = atIdx + username.length + 2;
      el.setSelectionRange(newPos, newPos);
    }, 0);
  };

  const inputRef = useRef<HTMLTextAreaElement>(null);
  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
  const chunksRef = useRef<Blob[]>([]);
  const timerRef = useRef<ReturnType<typeof setInterval>>(undefined);
  const typingTimeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const imageInputRef = useRef<HTMLInputElement>(null);
  const analyserRef = useRef<AnalyserNode | null>(null);
  const audioContextRef = useRef<AudioContext | null>(null);
  const animFrameRef = useRef<number>(0);
  const recordingTimeRef = useRef<number>(0);
  const streamRef = useRef<MediaStream | null>(null);
  const [liveBars, setLiveBars] = useState<number[]>(() => Array(32).fill(5));

  // Cleanup recording resources on unmount
  useEffect(() => {
    return () => {
      if (timerRef.current) clearInterval(timerRef.current);
      if (animFrameRef.current) cancelAnimationFrame(animFrameRef.current);
      if (audioContextRef.current) audioContextRef.current.close().catch(() => {});
      if (streamRef.current) streamRef.current.getTracks().forEach(t => t.stop());
      if (mediaRecorderRef.current?.state === 'recording') {
        mediaRecorderRef.current.stop();
      }
    };
  }, []);

  // Автоподгон высоты textarea
  useEffect(() => {
    const el = inputRef.current;
    if (el) {
      el.style.height = '22px'; // Reset/Min height
      if (text) {
        el.style.height = Math.min(el.scrollHeight, 150) + 'px';
      }
    }
  }, [text]);

  // При редактировании — заполнить текст
  useEffect(() => {
    if (editingMessage?.content) {
      setText(editingMessage.content);
      inputRef.current?.focus();
    }
  }, [editingMessage]);

  // При ответе - фокус на поле ввода
  useEffect(() => {
    if (replyTo) {
      inputRef.current?.focus();
    }
  }, [replyTo]);

  // Load draft when switching chats
  useEffect(() => {
    if (!editingMessage) {
      setText(getDraft(chatId));
    }
  }, [chatId]);

  // Cleanup preview URLs
  useEffect(() => {
    (window as any).hasUnsavedAttachments = attachments.length > 0;
    return () => {
      attachments.forEach(a => {
        if (a.preview) URL.revokeObjectURL(a.preview);
      });
      (window as any).hasUnsavedAttachments = false;
    };
  }, [attachments]);

  // Typing events
  const emitTyping = useCallback(() => {
    const socket = getSocket();
    if (!socket) return;
    socket.emit('typing_start', chatId);

    if (typingTimeoutRef.current) clearTimeout(typingTimeoutRef.current);
    typingTimeoutRef.current = setTimeout(() => {
      socket.emit('typing_stop', chatId);
    }, 2000);
  }, [chatId]);

  const handleSend = async (scheduledAt?: string) => {
    const trimmed = text.trim();
    const hasAttachments = attachments.length > 0;

    if (!trimmed && !hasAttachments) return;
    if (isSending) return;

    const socket = getSocket();
    if (!socket) return;

    // Остановить typing
    socket.emit('typing_stop', chatId);
    if (typingTimeoutRef.current) clearTimeout(typingTimeoutRef.current);

    if (editingMessage) {
      socket.emit('edit_message', {
        messageId: editingMessage.id,
        content: trimmed,
        chatId,
      });
      setEditingMessage(null);
      setText('');
      setDraft(chatId, '');
      return;
    }

    if (hasAttachments) {
      setIsSending(true);
      try {
        const uploadPromises = attachments.map(a => ChatApi.uploadFile(a.file));
        const results = await Promise.all(uploadPromises);
        
        const socketAttachments = results.map((res, i) => ({
          type: attachments[i].type,
          url: res.url,
          fileName: res.filename,
          fileSize: res.size
        }));

        socket.emit('send_message', {
          chatId,
          content: trimmed || null,
          type: attachments.length > 0 ? (attachments.every(a => a.type === 'image') ? 'image' : 'file') : 'text',
          attachments: socketAttachments,
          replyToId: replyTo?.id || null,
          quote: replyTo?.quote || null,
          ...(scheduledAt ? { scheduledAt } : {}),
        });

        setReplyTo(null);
        clearAttachments();
      } catch (e) {
        console.error('Ошибка загрузки файла:', e);
        const { addNotification } = useNotificationStore.getState();
        addNotification('error', t('uploadError') || 'Ошибка загрузки файла');
      } finally {
        setIsSending(false);
      }
    } else {
      socket.emit('send_message', {
        chatId,
        content: trimmed,
        type: 'text',
        replyToId: replyTo?.id || null,
        quote: replyTo?.quote || null,
        ...(scheduledAt ? { scheduledAt } : {}),
      });
      setReplyTo(null);
    }

    setText('');
    setDraft(chatId, '');
  };

  const handleKeyDown = (e: React.KeyboardEvent) => {
    // Handle @mention navigation
    if (mentionQuery !== null && filteredMembers.length > 0) {
      if (e.key === 'ArrowDown') {
        e.preventDefault();
        setMentionIndex(i => (i + 1) % filteredMembers.length);
        return;
      }
      if (e.key === 'ArrowUp') {
        e.preventDefault();
        setMentionIndex(i => (i - 1 + filteredMembers.length) % filteredMembers.length);
        return;
      }
      if (e.key === 'Enter' || e.key === 'Tab') {
        e.preventDefault();
        insertMention(filteredMembers[mentionIndex]);
        return;
      }
      if (e.key === 'Escape') {
        e.preventDefault();
        setMentionQuery(null);
        return;
      }
    }
    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault();
      handleSend();
    }
  };

  const clearAttachments = () => {
    attachments.forEach(a => {
      if (a.preview) URL.revokeObjectURL(a.preview);
    });
    setAttachments([]);
  };

  const removeAttachment = (index: number) => {
    setAttachments(prev => {
      const newArr = [...prev];
      if (newArr[index].preview) URL.revokeObjectURL(newArr[index].preview!);
      newArr.splice(index, 1);
      return newArr;
    });
  };

  const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = Array.from(e.target.files || []);
    if (files.length > 0) {
      const { addNotification } = useNotificationStore.getState();
      const newAttachments: Attachment[] = [];
      
      let tooLarge = false;
      let limitExceeded = false;

      for (const file of files) {
        if (attachments.length + newAttachments.length >= 20) {
          limitExceeded = true;
          break;
        }
        if (file.size > MAX_FILE_SIZE) {
          tooLarge = true;
          continue;
        }
        const isAudio = file.type.startsWith('audio/') || AUDIO_EXTENSIONS.some(ext => file.name.toLowerCase().endsWith(ext));
        newAttachments.push({ file, type: isAudio ? 'audio' : 'file' });
      }

      if (tooLarge) addNotification('warning', t('fileTooLarge') || 'Некоторые файлы слишком большие');
      if (limitExceeded) addNotification('warning', 'Максимум 20 файлов');
      
      setAttachments(prev => [...prev, ...newAttachments]);
      inputRef.current?.focus();
    }
    e.target.value = '';
    setShowAttachMenu(false);
  };

  const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = Array.from(e.target.files || []);
    if (files.length > 0) {
      const { addNotification } = useNotificationStore.getState();
      const newAttachments: Attachment[] = [];
      
      let limitExceeded = false;

      for (const file of files) {
        if (attachments.length + newAttachments.length >= 20) {
          limitExceeded = true;
          break;
        }
        const isVideo = file.type.startsWith('video/');
        const preview = file.type.startsWith('image/') ? URL.createObjectURL(file) : undefined;
        newAttachments.push({ file, preview, type: isVideo ? 'video' : 'image' });
      }

      if (limitExceeded) addNotification('warning', 'Максимум 20 файлов');
      
      setAttachments(prev => [...prev, ...newAttachments]);
      inputRef.current?.focus();
    }
    e.target.value = '';
    setShowAttachMenu(false);
  };

  // Запись голосового
  const startRecording = async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      streamRef.current = stream;
      // Use ogg/opus for better compatibility, fallback to webm
      const mimeType = MediaRecorder.isTypeSupported('audio/ogg;codecs=opus')
        ? 'audio/ogg;codecs=opus'
        : MediaRecorder.isTypeSupported('audio/webm;codecs=opus')
          ? 'audio/webm;codecs=opus'
          : 'audio/webm';
      const ext = mimeType.includes('ogg') ? 'ogg' : 'webm';
      const recorder = new MediaRecorder(stream, { mimeType });
      mediaRecorderRef.current = recorder;
      chunksRef.current = [];

      // Set up AnalyserNode for live waveform
      const actx = new AudioContext();
      const source = actx.createMediaStreamSource(stream);
      const analyser = actx.createAnalyser();
      analyser.fftSize = 256;
      analyser.smoothingTimeConstant = 0.6;
      source.connect(analyser);
      audioContextRef.current = actx;
      analyserRef.current = analyser;

      const timeDomainData = new Uint8Array(analyser.frequencyBinCount);
      const updateBars = () => {
        if (!analyserRef.current) return;
        analyserRef.current.getByteTimeDomainData(timeDomainData);
        // Downsample to 32 bars
        const bars: number[] = [];
        const step = Math.floor(timeDomainData.length / 32);
        for (let i = 0; i < 32; i++) {
          let sum = 0;
          for (let j = 0; j < step; j++) {
            const val = Math.abs(timeDomainData[i * step + j] - 128);
            sum += val;
          }
          const avg = sum / step;
          // Map 0-128 to 8-100 with some exaggeration for visibility
          bars.push(Math.max(8, Math.min(100, avg * 1.8 + 8)));
        }
        setLiveBars(bars);
        animFrameRef.current = requestAnimationFrame(updateBars);
      };
      animFrameRef.current = requestAnimationFrame(updateBars);

      recorder.ondataavailable = (e) => {
        if (e.data.size > 0) chunksRef.current.push(e.data);
      };

      recorder.onstop = async () => {
        stream.getTracks().forEach((t) => t.stop());
        streamRef.current = null;
        const blob = new Blob(chunksRef.current, { type: mimeType });
        const file = new File([blob], `voice.${ext}`, { type: mimeType });

        try {
          const result = await ChatApi.uploadFile(file);
          const socket = getSocket();
          if (socket) {
            socket.emit('send_message', {
              chatId,
              content: null,
              type: 'voice',
              attachments: [{
                type: 'voice',
                url: result.url,
                fileName: result.filename,
                fileSize: result.size
              }],
              replyToId: replyTo?.id || null,
              quote: replyTo?.quote || null,
            });
            setReplyTo(null);
          }
        } catch (e) {
          console.error('Ошибка отправки голосового:', e);
        }
      };

      recorder.start();
      setIsRecording(true);
      setRecordingTime(0);
      recordingTimeRef.current = 0;
      timerRef.current = setInterval(() => {
        recordingTimeRef.current += 1;
        setRecordingTime((t) => t + 1);
      }, 1000);
    } catch (e) {
      console.error('Ошибка записи:', e);
    }
  };

  const cleanupAnalyser = () => {
    if (animFrameRef.current) cancelAnimationFrame(animFrameRef.current);
    analyserRef.current = null;
    if (audioContextRef.current) {
      audioContextRef.current.close().catch(() => {});
      audioContextRef.current = null;
    }
    setLiveBars(Array(32).fill(5));
  };

  const stopRecording = () => {
    if (mediaRecorderRef.current?.state === 'recording') {
      mediaRecorderRef.current.stop();
    }
    if (timerRef.current) clearInterval(timerRef.current);
    cleanupAnalyser();
    setIsRecording(false);
    setRecordingTime(0);
    // recordingTimeRef is consumed in onstop, don't reset here
  };

  const cancelRecording = () => {
    if (mediaRecorderRef.current?.state === 'recording') {
      mediaRecorderRef.current.ondataavailable = null;
      mediaRecorderRef.current.onstop = null;
      mediaRecorderRef.current.stop();
      mediaRecorderRef.current.stream?.getTracks().forEach((t) => t.stop());
      streamRef.current = null;
    }
    if (timerRef.current) clearInterval(timerRef.current);
    cleanupAnalyser();
    setIsRecording(false);
    setRecordingTime(0);
    recordingTimeRef.current = 0;
  };

  const formatTime = (sec: number) => {
    const m = Math.floor(sec / 60);
    const s = sec % 60;
    return `${m}:${s.toString().padStart(2, '0')}`;
  };

  const handleInputContextMenu = (e: React.MouseEvent) => {
    const el = inputRef.current;
    if (el && el.selectionStart !== el.selectionEnd) {
      e.preventDefault();
      setFormatMenu({ show: true, x: e.clientX, y: e.clientY });
    }
  };

  const applyFormat = (prefix: string, suffix: string) => {
    const el = inputRef.current;
    if (!el) return;
    const start = el.selectionStart;
    const end = el.selectionEnd;
    const val = el.value;
    const selected = val.substring(start, end);
    const newVal = val.substring(0, start) + prefix + selected + suffix + val.substring(end);
    setText(newVal);
    setFormatMenu({ show: false, x: 0, y: 0 });

    // refocus and update cursor
    setTimeout(() => {
      el.focus();
      el.setSelectionRange(start + prefix.length, end + prefix.length);
    }, 0);
  };

  const handleDragOver = (e: React.DragEvent) => {
    e.preventDefault();
    setIsDragging(true);
  };

  const handleDragLeave = (e: React.DragEvent) => {
    e.preventDefault();
    setIsDragging(false);
  };

  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault();
    setIsDragging(false);

    if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
      const files = Array.from(e.dataTransfer.files);
      const { addNotification } = useNotificationStore.getState();
      const newAttachments: Attachment[] = [];
      
      let tooLarge = false;
      let limitExceeded = false;

      for (const file of files) {
        if (attachments.length + newAttachments.length >= 20) {
          limitExceeded = true;
          break;
        }
        if (file.size > MAX_FILE_SIZE) {
          tooLarge = true;
          continue;
        }

        const isVideo = file.type.startsWith('video/');
        const isImage = file.type.startsWith('image/');
        const audioExts = ['.mp3', '.wav', '.ogg', '.m4a', '.aac', '.flac', '.wma', '.opus'];
        const isAudio = file.type.startsWith('audio/') || audioExts.some(ext => file.name.toLowerCase().endsWith(ext));

        const type = isImage ? 'image' : isVideo ? 'video' : isAudio ? 'audio' : 'file';
        const preview = isImage ? URL.createObjectURL(file) : undefined;

        newAttachments.push({ file, type, preview });
      }

      if (tooLarge) addNotification('warning', t('fileTooLarge') || 'Некоторые файлы слишком большие');
      if (limitExceeded) addNotification('warning', 'Максимум 20 файлов');
      
      setAttachments(prev => [...prev, ...newAttachments]);
      inputRef.current?.focus();
    }
  };

  const hasContent = text.trim() || attachments.length > 0;

  return (
    <div
      className="z-10 px-6 pt-2 pb-6 flex-shrink-0 bg-transparent relative"
      onDragOver={handleDragOver}
      onDragLeave={handleDragLeave}
      onDrop={handleDrop}
    >
      {/* Drag overlay */}
      <AnimatePresence>
        {isDragging && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="absolute inset-0 z-50 rounded-3xl mx-6 mb-6 mt-2 bg-primary/10 border-2 border-dashed border-primary/40 backdrop-blur-sm flex items-center justify-center pointer-events-none"
          >
            <div className="flex flex-col items-center gap-4 text-primary">
              <span className="material-symbols-outlined text-5xl animate-bounce">upload_file</span>
              <p className="font-bold text-lg font-headline uppercase tracking-widest">{t('dropFileHere')}</p>
            </div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* Reply / Edit indicator */}
      <AnimatePresence>
        {(replyTo || editingMessage) && (
          <motion.div
            initial={{ height: 0, opacity: 0, scale: 0.98 }}
            animate={{ height: 'auto', opacity: 1, scale: 1 }}
            exit={{ height: 0, opacity: 0, scale: 0.98 }}
            className="mb-2 max-w-4xl mx-auto overflow-hidden"
          >
            <div className="flex items-center gap-4 px-5 py-3 bg-surface-container-high/80 backdrop-blur-2xl border-none rounded-2xl relative shadow-xl slide-on-ice">
              <div className="absolute left-0 top-1/2 -translate-y-1/2 w-1.5 h-3/5 bg-primary rounded-r-full" />
              <div className="w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center flex-shrink-0">
                <span className="material-symbols-outlined text-primary text-[20px]">
                  {editingMessage ? 'edit' : 'reply'}
                </span>
              </div>
              <div className="flex-1 min-w-0 flex flex-col justify-center">
                <p className="text-[10px] font-bold tracking-widest uppercase text-primary mb-0.5">
                  {editingMessage
                    ? t('editing')
                    : `${t('replyTo')} ${replyTo?.sender?.displayName || replyTo?.sender?.userName || replyTo?.sender?.username || ''}`}
                </p>
                <div className="text-[13px] text-[#efeff3] truncate opacity-90 pl-1 border-l border-white/20 ml-0.5">
                  {replyTo?.quote ? `«${replyTo.quote}»` : (editingMessage || replyTo)?.content || t('media') || 'Медиа'}
                </div>
              </div>
              <button
                onClick={() => {
                  setReplyTo(null);
                  setEditingMessage(null);
                  setAttachments([]);
                  setText('');
                }}
                className="w-8 h-8 rounded-full flex items-center justify-center text-on-surface-variant/40 hover:text-primary hover:bg-primary/10 transition-all slide-on-ice"
              >
                <span className="material-symbols-outlined text-[20px]">close</span>
              </button>
            </div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* Attachment previews */}
      <AnimatePresence>
        {attachments.length > 0 && (
          <motion.div
            initial={{ height: 0, opacity: 0, y: 10, scale: 0.95 }}
            animate={{ height: 'auto', opacity: 1, y: 0, scale: 1 }}
            exit={{ height: 0, opacity: 0, y: 10, scale: 0.95 }}
            className="mb-2 max-w-3xl mx-auto overflow-hidden px-1.5"
          >
            <div className="flex flex-col gap-2 p-2 bg-white/[0.04] backdrop-blur-2xl border border-white/10 rounded-2xl shadow-xl">
              <div className="flex flex-wrap gap-2">
                {attachments.map((att, idx) => (
                  <motion.div
                    key={idx}
                    layout
                    className="group relative w-20 h-20 rounded-xl overflow-hidden border border-white/10 flex-shrink-0"
                  >
                    {att.preview ? (
                      <img
                        src={att.preview}
                        alt=""
                        className="w-full h-full object-cover"
                      />
                    ) : att.type === 'video' ? (
                      <div className="w-full h-full bg-knot-500/20 flex items-center justify-center">
                        <ImageIcon size={20} className="text-knot-400" />
                      </div>
                    ) : att.type === 'audio' ? (
                      <div className="w-full h-full bg-emerald-500/20 flex items-center justify-center">
                        <Music size={20} className="text-emerald-400" />
                      </div>
                    ) : (
                      <div className="w-full h-full bg-sky-500/20 flex items-center justify-center">
                        <FileText size={20} className="text-sky-400" />
                      </div>
                    )}
                    
                    <button
                      onClick={() => removeAttachment(idx)}
                      className="absolute top-1 right-1 w-5 h-5 rounded-full bg-black/60 text-white flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity"
                    >
                      <X size={12} />
                    </button>
                    
                    <div className="absolute bottom-0 left-0 right-0 bg-black/40 px-1 py-0.5 pointer-events-none">
                       <p className="text-[8px] text-white truncate">{att.file.name}</p>
                    </div>
                  </motion.div>
                ))}
              </div>
              <div className="flex items-center justify-between px-2 py-1 border-t border-white/5 mt-1">
                <span className="text-[10px] text-zinc-400">
                  {attachments.length} {t('files')} ({ (attachments.reduce((acc, a) => acc + a.file.size, 0) / 1024 / 1024).toFixed(2) } MB)
                </span>
                <button
                  onClick={clearAttachments}
                  className="text-[10px] text-zinc-500 hover:text-rose-400 transition-colors"
                >
                  {t('clearAll') || 'Очистить всё'}
                </button>
              </div>
            </div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* Recording UI */}
      {isRecording ? (
        <div className="flex items-center gap-4 bg-surface-container-high rounded-[2rem] px-6 py-4 w-full max-w-4xl mx-auto shadow-2xl animate-in slide-in-from-bottom-4 slide-on-ice">
          <button
            onClick={cancelRecording}
            className="w-10 h-10 rounded-full flex items-center justify-center text-error hover:bg-error/10 transition-all slide-on-ice"
          >
            <span className="material-symbols-outlined">delete</span>
          </button>
          <div className="flex-1 flex items-center gap-4">
            <div className="flex items-center gap-2">
              <span className="w-3 h-3 rounded-full bg-error animate-pulse shadow-[0_0_8px_rgba(244,67,54,0.5)]" />
              <span className="text-sm font-bold font-mono text-on-surface tracking-tighter w-12">{formatTime(recordingTime)}</span>
            </div>
            <div className="flex-1 flex items-center gap-[3px] h-8 items-center">
              {liveBars.map((h, i) => (
                <div
                  key={i}
                  className="flex-1 bg-primary/40 rounded-full transition-all duration-100"
                  style={{ height: `${h}%` }}
                />
              ))}
            </div>
          </div>
          <button
            onClick={stopRecording}
            className="w-12 h-12 rounded-2xl bg-primary text-on-primary flex items-center justify-center hover:scale-105 active:scale-95 transition-all shadow-lg shadow-primary/20 slide-on-ice"
          >
            <span className="material-symbols-outlined">send</span>
          </button>
        </div>
      ) : (
        <div className="flex items-end gap-3 w-full max-w-4xl mx-auto px-4 pb-4">
          {/* Attach - Outside */}
          <div className="relative flex-shrink-0 self-end mb-1">
            <button
              onClick={() => setShowAttachMenu(!showAttachMenu)}
              className="w-10 h-10 rounded-full text-on-surface-variant/60 hover:text-primary transition-all flex items-center justify-center p-0"
            >
              <Paperclip size={24} strokeWidth={1.5} />
            </button>
            <AnimatePresence>
              {showAttachMenu && (
                <>
                  <div className="fixed inset-0 z-40" onClick={() => setShowAttachMenu(false)} />
                  <motion.div
                    initial={{ opacity: 0, scale: 0.95, y: 15 }}
                    animate={{ opacity: 1, scale: 1, y: 0 }}
                    exit={{ opacity: 0, scale: 0.95, y: 15 }}
                    className="absolute bottom-[calc(100%+12px)] left-0 w-52 rounded-[1.5rem] glass-strong shadow-2xl z-50 p-2 border border-white/10 backdrop-blur-3xl"
                  >
                    <button
                      onClick={() => imageInputRef.current?.click()}
                      className="flex items-center gap-4 w-full px-3 py-3 rounded-xl text-sm font-medium text-zinc-200 hover:bg-white/5 hover:text-white transition-all group"
                    >
                      <div className="w-10 h-10 rounded-full bg-gradient-to-br from-knot-400/20 to-purple-500/20 flex items-center justify-center ring-1 ring-knot-400/30 group-hover:scale-110 transition-transform shadow-inner">
                        <ImageIcon size={18} className="text-knot-400" />
                      </div>
                      {t('photoVideo')}
                    </button>
                    <button
                      onClick={() => fileInputRef.current?.click()}
                      className="flex items-center gap-4 w-full px-3 py-3 rounded-xl text-sm font-medium text-zinc-200 hover:bg-white/5 hover:text-white transition-all group mt-1"
                    >
                      <div className="w-10 h-10 rounded-full bg-gradient-to-br from-emerald-400/20 to-teal-500/20 flex items-center justify-center ring-1 ring-emerald-400/30 group-hover:scale-110 transition-transform shadow-inner">
                        <FileText size={18} className="text-emerald-400" />
                      </div>
                      {t('file')}
                    </button>
                  </motion.div>
                </>
              )}
            </AnimatePresence>
            <input ref={fileInputRef} type="file" multiple className="hidden" onChange={handleFileChange} />
            <input ref={imageInputRef} type="file" multiple accept="image/*,video/*" className="hidden" onChange={handleImageChange} />
          </div>

          {/* Main Input Pill */}
          <div className="flex-1 flex items-end gap-2 bg-[#2a2a2a] rounded-2xl px-3 py-1.5 transition-all duration-300 focus-within:bg-[#323232] shadow-sm relative min-h-[44px]">
            <button
               onClick={() => setShowEmoji(!showEmoji)}
               className="w-8 h-8 rounded-full text-on-surface-variant/50 hover:text-primary transition-all flex items-center justify-center flex-shrink-0 mb-0.5"
            >
               <Smile size={20} strokeWidth={1.5} />
            </button>

            <div className="flex-1 relative self-center">
              <textarea
                ref={inputRef}
                value={text}
                onChange={(e) => {
                  const val = e.target.value;
                  setText(val);
                  setDraft(chatId, val);
                  emitTyping();
                  if (isGroup) {
                    const cursorPos = e.target.selectionStart;
                    const match = val.substring(0, cursorPos).match(/@(\w*)$/);
                    if (match) { setMentionQuery(match[1]); setMentionIndex(0); }
                    else setMentionQuery(null);
                  }
                }}
                onKeyDown={handleKeyDown}
                onContextMenu={handleInputContextMenu}
                rows={1}
                className="w-full bg-transparent border-none focus:ring-0 text-[#efeff3] placeholder-on-surface-variant/30 text-[16px] leading-[1.3] resize-none max-h-[140px] custom-scrollbar outline-none py-1 px-0"
                placeholder={attachments.length > 0 ? t('addCaption') : t('messagePlaceholder') || 'Сообщение...'}
              />
              <AnimatePresence>
                {mentionQuery !== null && filteredMembers.length > 0 && (
                  <motion.div
                    initial={{ opacity: 0, y: 8 }}
                    animate={{ opacity: 1, y: 0 }}
                    exit={{ opacity: 0, y: 8 }}
                    className="absolute bottom-full left-0 right-0 mb-4 rounded-xl glass-strong shadow-2xl border border-white/10 py-1 z-50 max-h-48 overflow-y-auto"
                  >
                    {filteredMembers.map((m, i) => (
                      <button
                        key={m.user.id}
                        onClick={() => insertMention(m)}
                        className={`flex items-center gap-3 w-full px-3 py-2 text-left transition-colors ${
                          i === mentionIndex ? 'bg-primary/20 text-white' : 'text-zinc-300 hover:bg-white/5'
                        }`}
                      >
                        <div className="w-7 h-7 rounded-full bg-gradient-to-br from-knot-500 to-purple-600 flex items-center justify-center text-white text-[10px] font-bold">
                          {(m.user.displayName || m.user.userName || m.user.username || '?')[0]?.toUpperCase()}
                        </div>
                        <div className="min-w-0">
                          <p className="text-sm font-medium truncate">{m.user.displayName || m.user.userName || m.user.username || '??'}</p>
                        </div>
                      </button>
                    ))}
                  </motion.div>
                )}
              </AnimatePresence>
            </div>
            
            <AnimatePresence>
              {showEmoji && (
                <div className="absolute left-0 bottom-[calc(100%+20px)]">
                  <EmojiPicker
                    onSelect={(emoji) => {
                      setText((prev) => {
                        const next = prev + emoji;
                        setDraft(chatId, next);
                        return next;
                      });
                      inputRef.current?.focus();
                    }}
                    onSelectGif={(gifUrl) => {
                      const socket = getSocket();
                      if (socket) {
                        socket.emit('send_message', {
                          chatId,
                          content: null,
                          type: 'image',
                          attachments: [{ type: 'image', url: gifUrl, fileName: 'gif.gif', fileSize: 0 }],
                        });
                      }
                      setShowEmoji(false);
                    }}
                    onClose={() => setShowEmoji(false)}
                  />
                </div>
              )}
            </AnimatePresence>
          </div>

          {/* Send / Mic - Circular button outside pill */}
          <div className="flex-shrink-0 relative">
            {hasContent ? (
              <>
                <button
                  onClick={() => handleSend()}
                  onContextMenu={(e) => { e.preventDefault(); setScheduleStep('presets'); setShowSchedule(true); }}
                  disabled={isSending}
                  className="w-11 h-11 flex items-center justify-center rounded-2xl bg-primary text-white hover:brightness-110 active:scale-95 transition-all shadow-[0_4px_15px_rgba(48,150,229,0.3)] disabled:opacity-50"
                >
                  <Send size={20} strokeWidth={2.5} className="translate-x-[1px]" />
                </button>
                <AnimatePresence>
                  {showSchedule && (
                    <>
                      <div className="fixed inset-0 z-40" onClick={() => setShowSchedule(false)} />
                      <motion.div
                        initial={{ opacity: 0, scale: 0.9, y: 10 }}
                        animate={{ opacity: 1, scale: 1, y: 0 }}
                        exit={{ opacity: 0, scale: 0.9, y: 10 }}
                        className="absolute bottom-[calc(100%+12px)] right-0 w-72 rounded-2xl glass-strong shadow-2xl z-50 border border-white/10 backdrop-blur-3xl overflow-hidden"
                      >
                        <div className="flex items-center gap-2 px-4 pt-4 pb-2">
                          {scheduleStep === 'custom' && (
                            <button onClick={() => setScheduleStep('presets')} className="p-1 rounded-lg hover:bg-white/10 text-zinc-400 hover:text-white transition-colors">
                              <ChevronLeft size={16} />
                            </button>
                          )}
                          <Clock size={16} className="text-knot-400" />
                          <span className="text-sm font-medium text-zinc-200">{t('scheduleMessage')}</span>
                        </div>

                        {scheduleStep === 'presets' ? (
                          <div className="p-2 space-y-1">
                            <button
                              onClick={() => {
                                const d = new Date(Date.now() + 3600000);
                                handleSend(d.toISOString());
                                setShowSchedule(false);
                                setScheduleToast(d.toLocaleString());
                              }}
                              className="w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm text-zinc-200 hover:bg-white/10 transition-colors text-left"
                            >
                              <Clock size={15} className="text-zinc-400 flex-shrink-0" />
                              {t('scheduleIn1h')}
                            </button>
                            <button
                              onClick={() => {
                                const d = new Date(Date.now() + 3 * 3600000);
                                handleSend(d.toISOString());
                                setShowSchedule(false);
                                setScheduleToast(d.toLocaleString());
                              }}
                              className="w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm text-zinc-200 hover:bg-white/10 transition-colors text-left"
                            >
                              <Clock size={15} className="text-zinc-400 flex-shrink-0" />
                              {t('scheduleIn3h')}
                            </button>
                            <button
                              onClick={() => {
                                const d = new Date(); d.setDate(d.getDate() + 1); d.setHours(9, 0, 0, 0);
                                handleSend(d.toISOString());
                                setShowSchedule(false);
                                setScheduleToast(d.toLocaleString());
                              }}
                              className="w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm text-zinc-200 hover:bg-white/10 transition-colors text-left"
                            >
                              <Calendar size={15} className="text-zinc-400 flex-shrink-0" />
                              {t('scheduleTomorrow')}
                            </button>
                            <div className="border-t border-white/5 my-1" />
                            <button
                              onClick={() => {
                                const now = new Date();
                                setScheduleCalYear(now.getFullYear());
                                setScheduleCalMonth(now.getMonth());
                                const m = String(now.getMonth() + 1).padStart(2, '0');
                                const d = String(now.getDate()).padStart(2, '0');
                                setScheduleCalDate(`${now.getFullYear()}-${m}-${d}`);
                                setScheduleHour(String(Math.min(now.getHours() + 1, 23)).padStart(2, '0'));
                                setScheduleMinute(String(now.getMinutes()).padStart(2, '0'));
                                setScheduleStep('custom');
                              }}
                              className="w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-sm text-knot-400 hover:bg-white/10 transition-colors text-left"
                            >
                              <Calendar size={15} className="flex-shrink-0" />
                              {t('scheduleCustom')}
                            </button>
                          </div>
                        ) : (
                          <ScheduleCalendar
                            calDate={scheduleCalDate} setCalDate={setScheduleCalDate}
                            calMonth={scheduleCalMonth} setCalMonth={setScheduleCalMonth}
                            calYear={scheduleCalYear} setCalYear={setScheduleCalYear}
                            hour={scheduleHour} setHour={setScheduleHour}
                            minute={scheduleMinute} setMinute={setScheduleMinute}
                            onSend={(iso) => { handleSend(iso); setShowSchedule(false); setScheduleToast(new Date(iso).toLocaleString()); }}
                            t={t}
                          />
                        )}
                      </motion.div>
                    </>
                  )}
                </AnimatePresence>
              </>
            ) : (
              <button
                onClick={startRecording}
                className="w-11 h-11 flex items-center justify-center rounded-2xl bg-primary text-white hover:brightness-110 active:scale-95 transition-all shadow-[0_4px_15px_rgba(48,150,229,0.3)]"
              >
                <Mic size={22} strokeWidth={1.5} />
              </button>
            )}
          </div>
        </div>
      )}

      {/* Formatting Context Menu */}
      <AnimatePresence>
        {formatMenu.show && (
          <>
            <div className="fixed inset-0 z-50 cursor-pointer" onClick={() => setFormatMenu({ ...formatMenu, show: false })} onContextMenu={(e) => { e.preventDefault(); setFormatMenu({ ...formatMenu, show: false }); }} />
            <motion.div
              initial={{ opacity: 0, scale: 0.95, y: 10 }}
              animate={{ opacity: 1, scale: 1, y: 0 }}
              exit={{ opacity: 0, scale: 0.95, y: 10 }}
              className="fixed z-[9999] w-48 rounded-2xl glass-strong shadow-2xl py-1"
              style={{ left: formatMenu.x, top: formatMenu.y - 180 }}
            >
              <button
                onClick={() => applyFormat('**', '**')}
                className="flex items-center gap-3 w-full px-4 py-2 text-sm text-zinc-200 hover:bg-white/10 transition-colors"
              >
                <b className="font-bold">{t('formatBold')}</b> <span className="text-xs text-zinc-500 ml-auto">{t('formatBoldHint')}</span>
              </button>
              <button
                onClick={() => applyFormat('_', '_')}
                className="flex items-center gap-3 w-full px-4 py-2 text-sm text-zinc-200 hover:bg-white/10 transition-colors"
              >
                <em className="italic">{t('formatItalic')}</em> <span className="text-xs text-zinc-500 ml-auto">{t('formatItalicHint')}</span>
              </button>
              <button
                onClick={() => applyFormat('~', '~')}
                className="flex items-center gap-3 w-full px-4 py-2 text-sm text-zinc-200 hover:bg-white/10 transition-colors"
              >
                <del className="line-through">{t('formatStrike')}</del> <span className="text-xs text-zinc-500 ml-auto">{t('formatStrikeHint')}</span>
              </button>
              <button
                onClick={() => applyFormat('`', '`')}
                className="flex items-center gap-3 w-full px-4 py-2 text-sm text-zinc-200 hover:bg-white/10 transition-colors"
              >
                <code className="bg-black/20 rounded px-1 font-mono">{t('formatMono')}</code> <span className="text-xs text-zinc-500 ml-auto">{t('formatMonoHint')}</span>
              </button>
            </motion.div>
          </>
        )}
      </AnimatePresence>

      {/* Schedule toast notification */}
      <AnimatePresence>
        {scheduleToast && (
          <motion.div
            initial={{ opacity: 0, y: -10, scale: 0.95 }}
            animate={{ opacity: 1, y: 0, scale: 1 }}
            exit={{ opacity: 0, y: -10, scale: 0.95 }}
            onAnimationComplete={() => {
              setTimeout(() => setScheduleToast(null), 3500);
            }}
            className="absolute bottom-[calc(100%+8px)] left-1/2 -translate-x-1/2 z-[9999] px-4 py-2.5 rounded-xl bg-surface shadow-2xl border border-border flex items-center gap-2 whitespace-nowrap"
          >
            <Check size={16} className="text-emerald-400 flex-shrink-0" />
            <span className="text-sm text-zinc-200">{t('messageScheduled')}</span>
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  );
}

/* =================== Schedule Mini Calendar =================== */
function ScheduleCalendar({
  calDate, setCalDate, calMonth, setCalMonth, calYear, setCalYear,
  hour, setHour, minute, setMinute, onSend, t,
}: {
  calDate: string;
  setCalDate: (v: string) => void;
  calMonth: number;
  setCalMonth: (v: number) => void;
  calYear: number;
  setCalYear: (v: number) => void;
  hour: string;
  setHour: (v: string) => void;
  minute: string;
  setMinute: (v: string) => void;
  onSend: (iso: string) => void;
  t: (k: any) => any;
}) {
  const today = new Date();
  const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;

  const daysInMonth = new Date(calYear, calMonth + 1, 0).getDate();
  const firstDayRaw = new Date(calYear, calMonth, 1).getDay();
  const firstDay = firstDayRaw === 0 ? 6 : firstDayRaw - 1;
  const cells: (number | null)[] = [];
  for (let i = 0; i < firstDay; i++) cells.push(null);
  for (let d2 = 1; d2 <= daysInMonth; d2++) cells.push(d2);

  const weekDays = t('weekDays') as string[];
  const months = t('months') as string[];

  const prevMonth = () => {
    if (calMonth === 0) { setCalMonth(11); setCalYear(calYear - 1); }
    else setCalMonth(calMonth - 1);
  };
  const nextMonth = () => {
    if (calMonth === 11) { setCalMonth(0); setCalYear(calYear + 1); }
    else setCalMonth(calMonth + 1);
  };

  const selectDay = (day: number) => {
    const m = String(calMonth + 1).padStart(2, '0');
    const d = String(day).padStart(2, '0');
    setCalDate(`${calYear}-${m}-${d}`);
  };

  const isSelected = (day: number) => {
    const m = String(calMonth + 1).padStart(2, '0');
    const d = String(day).padStart(2, '0');
    return calDate === `${calYear}-${m}-${d}`;
  };

  const isToday = (day: number) => {
    return today.getFullYear() === calYear && today.getMonth() === calMonth && today.getDate() === day;
  };

  const isPast = (day: number) => {
    const m = String(calMonth + 1).padStart(2, '0');
    const d = String(day).padStart(2, '0');
    return `${calYear}-${m}-${d}` < todayStr;
  };

  const canSend = (() => {
    if (!calDate) return false;
    const dt = new Date(`${calDate}T${hour}:${minute}:00`);
    return dt.getTime() > Date.now();
  })();

  const handleSend = () => {
    if (!canSend) return;
    const dt = new Date(`${calDate}T${hour}:${minute}:00`);
    onSend(dt.toISOString());
  };

  return (
    <div>
      {/* Mini calendar header */}
      <div className="flex items-center justify-between px-3 py-2 border-b border-white/5">
        <button onClick={prevMonth} className="p-1 rounded-lg hover:bg-white/10 text-zinc-400 hover:text-white transition-colors">
          <ChevronLeft size={16} />
        </button>
        <span className="text-xs font-medium text-zinc-300">{months[calMonth]} {calYear}</span>
        <button onClick={nextMonth} className="p-1 rounded-lg hover:bg-white/10 text-zinc-400 hover:text-white transition-colors">
          <ChevronRight size={16} />
        </button>
      </div>

      {/* Weekday headers */}
      <div className="grid grid-cols-7 px-2 pt-1">
        {weekDays.map((d) => (
          <div key={d} className="text-center text-[10px] text-zinc-500 font-medium py-0.5">{d}</div>
        ))}
      </div>

      {/* Days grid */}
      <div className="grid grid-cols-7 px-2 pb-2">
        {cells.map((day, i) => (
          <div key={i} className="flex items-center justify-center">
            {day ? (
              <button
                onClick={() => !isPast(day) && selectDay(day)}
                disabled={isPast(day)}
                className={`w-7 h-7 rounded-full text-xs flex items-center justify-center transition-all ${
                  isSelected(day)
                    ? 'bg-accent text-white font-semibold shadow-lg shadow-accent/30'
                    : isPast(day)
                      ? 'text-zinc-600 cursor-not-allowed'
                      : isToday(day)
                        ? 'text-knot-400 font-semibold ring-1 ring-knot-500/50'
                        : 'text-zinc-300 hover:bg-white/10'
                }`}
              >
                {day}
              </button>
            ) : (
              <span className="w-7 h-7" />
            )}
          </div>
        ))}
      </div>

      {/* Time picker */}
      <div className="px-3 pb-2">
        <label className="text-[11px] text-zinc-500 mb-1 block">{t('scheduleTime')}</label>
        <div className="flex items-center gap-2">
          <select
            value={hour}
            onChange={(e) => setHour(e.target.value)}
            className="flex-1 bg-white/5 border border-white/10 rounded-lg px-2 py-1.5 text-sm text-zinc-200 focus:outline-none focus:border-knot-500/50 appearance-none text-center"
          >
            {Array.from({ length: 24 }, (_, i) => String(i).padStart(2, '0')).map((h) => (
              <option key={h} value={h} className="bg-zinc-800">{h}</option>
            ))}
          </select>
          <span className="text-zinc-400 font-bold">:</span>
          <select
            value={minute}
            onChange={(e) => setMinute(e.target.value)}
            className="flex-1 bg-white/5 border border-white/10 rounded-lg px-2 py-1.5 text-sm text-zinc-200 focus:outline-none focus:border-knot-500/50 appearance-none text-center"
          >
            {Array.from({ length: 60 }, (_, i) => String(i).padStart(2, '0')).map((m) => (
              <option key={m} value={m} className="bg-zinc-800">{m}</option>
            ))}
          </select>
        </div>
      </div>

      {/* Send button */}
      <div className="px-3 pb-3">
        <button
          onClick={handleSend}
          disabled={!canSend}
          className="w-full py-2 rounded-xl bg-accent hover:bg-accent-hover disabled:bg-zinc-700 disabled:text-zinc-500 text-white text-sm font-medium transition-colors"
        >
          {t('scheduleSend')}
        </button>
      </div>
    </div>
  );
}
