import { useEffect, useMemo, useRef, useState, useCallback, type TouchEvent } from "react";
import { useNavigate, useParams } from "react-router-dom";
import {
  ArrowLeft, Image as ImageIcon, Mic, Send, Phone, Video, StopCircle,
  Smile, Camera, Eye, X, Pencil, Trash2, Check, Plus, ChevronDown, CornerUpLeft,
  UserX, Tag, MoreVertical, ImagePlus, Aperture, Copy,
} from "lucide-react";
import { supabase, createRealtimeChannel } from "@/integrations/supabase/client";
import { useAuth } from "@/hooks/useAuth";
import { useUserNickname } from "@/hooks/useUserNickname";
import { useBlockUser } from "@/hooks/useBlockUser";
import Avatar from "@/components/Avatar";
import VerifiedBadge from "@/components/VerifiedBadge";
import ViewOnceImage from "@/components/ViewOnceImage";
import CameraCapture from "@/components/CameraCapture";
import StickerPicker from "@/components/StickerPicker";
import MessageReactions, { ReactionPicker } from "@/components/MessageReactions";
import { useReactionsOptimized } from "@/hooks/useReactionsOptimized";
import { useTyping } from "@/hooks/useTyping";
import { formatLastSeen, isOnline } from "@/hooks/usePresence";

import { toast } from "sonner";
import { cn, fileToPng, profilePath, playNotificationSound } from "@/lib/utils";
import { motion, AnimatePresence } from "framer-motion";
import BrandLogo from "@/components/BrandLogo";
import AudioPlayer from "@/components/AudioPlayer";
import { format, isToday, isYesterday } from "date-fns";
import { ptBR } from "date-fns/locale";
import RGBName from "@/components/RGBName";
import ChatMediaViewer from "@/components/ChatMediaViewer";
import { AttachmentMenuPortal } from "@/components/AttachmentMenuPortal";
import { getMessageReads, markMessagesRead } from "@/lib/chunkedQueries";

/* ─── types ─────────────────────────────────────────── */
interface Message {
  id: string;
  conversation_id: string;
  sender_id: string;
  type: string;
  content: string | null;
  media_url: string | null;
  sticker_id: string | null;
  duration_seconds: number | null;
  is_view_once?: boolean;
  viewed_at?: string | null;
  viewed_by?: string | null;
  edited_at?: string | null;
  reply_to_message_id?: string;
  created_at: string;
  location_lat?: number;
  location_lng?: number;
}
interface Sticker { id: string; name: string; image_url: string; }

const EDIT_WINDOW_MS = 3 * 60 * 1000;

const formatDateSeparator = (date: string) => {
  const d = new Date(date);
  if (isToday(d))     return "Hoje";
  if (isYesterday(d)) return "Ontem";
  return format(d, "d 'de' MMMM", { locale: ptBR });
};

/* ─── ChatAvatar ─────────────────────────────────── */
function ChatAvatar({
  url, name, size = 32, className = "",
}: { url?: string; name?: string; size?: number; className?: string }) {
  return (
    <span
      className={cn("shrink-0 block rounded-full overflow-hidden", className)}
      style={{ width: size, height: size, flexShrink: 0 }}
    >
      {url ? (
        <img src={url} alt={name || "avatar"} loading="lazy"
          style={{ width: "100%", height: "100%", objectFit: "cover", display: "block" }}
        />
      ) : (
        <span style={{
          width: "100%", height: "100%", display: "flex",
          alignItems: "center", justifyContent: "center",
          background: "var(--surface-2)", color: "var(--text-secondary)",
          fontSize: size * 0.38, fontWeight: 600,
        }}>
          {name?.[0]?.toUpperCase() ?? "?"}
        </span>
      )}
    </span>
  );
}

/* ─── Componente principal ─────────────────────────── */
export default function Chat() {
  const { id } = useParams();
  const navigate = useNavigate();
  const { user, profile, isAdmin, loading: authLoading } = useAuth();
  const [messages, setMessages]           = useState<Message[]>([]);
  const [text, setText]                   = useState("");
  const [other, setOther]                 = useState<any>(null);
  const [showStickers, setShowStickers]   = useState(false);
  
  const [recording, setRecording]         = useState(false);
  const [viewOnceMode, setViewOnceMode]   = useState(false);
  const [showAttachMenu, setShowAttachMenu] = useState(false);
  const [replyTo, setReplyTo] = useState<Message | null>(null);
  const [cameraOpen, setCameraOpen]       = useState(false);
  const [showJumpToBottom, setShowJumpToBottom] = useState(false);
  const [actionFor, setActionFor]         = useState<Message | null>(null);
  const [editingId, setEditingId]         = useState<string | null>(null);
  const [editText, setEditText]           = useState("");
  const [pressingId, setPressingId]       = useState<string | null>(null);
  const [pickerFor, setPickerFor]         = useState<string | null>(null);
  const [mediaViewer, setMediaViewer]     = useState<{ src: string; type: "image" | "video" } | null>(null);
  const [hasMoreMessages, setHasMoreMessages] = useState(false);
  const [isLoadingOlder, setIsLoadingOlder] = useState(false);
  const [isLoadingMessages, setIsLoadingMessages] = useState(false);
  const [swipeState, setSwipeState] = useState<{msgId: string; dx: number} | null>(null);
  const [readMessageIds, setReadMessageIds] = useState<Set<string>>(new Set());
  const [bgImage, setBgImage] = useState<string | null>(null);
  const [bgGradient, setBgGradient] = useState<string | null>(null);
  const [bgBubbleColor, setBgBubbleColor] = useState("rgba(255,255,255,0.08)");
  const [bgBubbleMineColor, setBgBubbleMineColor] = useState("rgba(250,204,21,0.9)");
  const [bgTextColor, setBgTextColor] = useState("#ffffff");
  const [availableBgs, setAvailableBgs] = useState<any[]>([]);
  const [showBgPicker, setShowBgPicker] = useState(false);
  const [PinguShake, setPinguShake] = useState(false);
  const [showMobileMenu, setShowMobileMenu] = useState(false);
  const [showNicknameInput, setShowNicknameInput] = useState(false);
  const [nicknameInputVal, setNicknameInputVal] = useState("");

  const [highlightMsgId, setHighlightMsgId] = useState<string | null>(null);
  const [audioPreview, setAudioPreview] = useState<{ blob: Blob; url: string; duration: number } | null>(null);
  const [deliveredIds, setDeliveredIds] = useState<Set<string>>(new Set());
  const [inputFocused, setInputFocused] = useState(false);

  const deliveredTimersRef = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());
  const lastClickTime    = useRef<Map<string, number>>(new Map());
  const recorderRef       = useRef<MediaRecorder | null>(null);
  const chunksRef         = useRef<Blob[]>([]);
  const startedAtRef      = useRef<number>(0);
  const scrollRef         = useRef<HTMLDivElement>(null);
  const fileInputRef      = useRef<HTMLInputElement>(null);
  const longPressTimer    = useRef<ReturnType<typeof setTimeout> | null>(null);
  const attachButtonRef   = useRef<HTMLButtonElement>(null);
  const swipeDxRef        = useRef<number>(0);
  const swipeStartXRef    = useRef<number>(0);
  const SWIPE_THRESHOLD   = 60;
  const initialScrollDone = useRef(false);
  const userScrolledUp    = useRef(false);
  const msgsLenRef        = useRef(0);
  msgsLenRef.current = messages.length;

  const messageIds   = useMemo(() => messages.map((m) => m.id), [messages]);
  const messageById  = useMemo(() => new Map(messages.map((m) => [m.id, m])), [messages]);
  const { getReactions, reload: reloadReactions } = useReactionsOptimized(messageIds, id);
  const { othersTyping, sendTyping }                       = useTyping(id, user?.id);
  const isOtherTyping = other && othersTyping.has(other.id);
  const { nickname: otherNickname, setNicknameForUser }    = useUserNickname(other?.id);
  const { isBlocked, blockUser, unblockUser }              = useBlockUser(other?.id);

  const isNearBottom = () => {
    const el = scrollRef.current;
    if (!el) return true;
    return el.scrollHeight - el.scrollTop - el.clientHeight < 240;
  };

  /* ── data loaders ── */
  const loadOther = async () => {
    if (!id || !user) return;
    try {
      const { data: parts, error: partErr } = await supabase
        .from("conversation_participants").select("user_id")
        .eq("conversation_id", id).limit(10);
      if (partErr) throw partErr;
      const memberIds = new Set((parts || []).map((p: any) => p.user_id));
      if (!memberIds.has(user.id)) { toast.error("Você não tem acesso a essa conversa"); navigate("/messages"); return; }
      const otherId = (parts || []).map((p: any) => p.user_id).find((uid: string) => uid !== user.id);
      if (!otherId) { setOther(null); return; }
      const { data: prof, error: profErr } = await supabase
        .from("profiles")
        .select("id, display_name, photo_url, username, is_verified, last_seen_at, show_activity, profile_theme")
        .eq("id", otherId).maybeSingle();
      if (profErr) throw profErr;
      setOther(prof);
    } catch (err: any) { console.error("[Chat] loadOther error:", err); toast.error("Falha ao carregar dados da conversa"); }
  };

  const PAGE_SIZE = 30;
  
  const loadMessages = async () => {
    if (!id || !user) return;
    setIsLoadingMessages(true);
    try {
      const { data, error, count } = await supabase.from("messages").select("*", { count: "exact" })
        .eq("conversation_id", id)
        .order("created_at", { ascending: false })
        .limit(PAGE_SIZE);
      if (error) throw error;
      const list = ((data as Message[]) || []).reverse();
      setMessages(list);
      setDeliveredIds(new Set(list.filter((m) => m.sender_id === user.id).map((m) => m.id)));
      setHasMoreMessages((count || 0) > list.length);
      const incoming = list.filter((m) => m.sender_id !== user.id).map((m) => m.id);
      if (incoming.length) {
        await markMessagesRead(supabase, user.id, incoming);
      }
    } catch (err: any) { toast.error(err.message || "Falha ao carregar mensagens"); }
    finally { setIsLoadingMessages(false); }
  };

  const loadOlderMessages = async () => {
    if (!id || !user || isLoadingOlder || !hasMoreMessages) return;
    try {
      setIsLoadingOlder(true);
      const oldestMessage = messages[0];
      if (!oldestMessage) { setIsLoadingOlder(false); return; }
      const { data, error } = await supabase.from("messages").select("*", { count: "exact" })
        .eq("conversation_id", id)
        .lt("created_at", oldestMessage.created_at)
        .order("created_at", { ascending: false })
        .limit(50);
      if (error) throw error;
      const newer = ((data as Message[]) || []).reverse();
      if (newer.length > 0) setMessages((prev) => [...newer, ...prev]);
      setHasMoreMessages(newer.length === 50);
    } catch (err: any) { console.error("[Chat] loadOlderMessages error:", err); }
    finally { setIsLoadingOlder(false); }
  };

  const loadOlderMessagesRef = useRef(loadOlderMessages);
  loadOlderMessagesRef.current = loadOlderMessages;

  const triggerPinguShake = () => {
    setPinguShake(true);
    window.setTimeout(() => setPinguShake(false), 340);
  };

  const messagesRef = useRef<Message[]>(messages);
  messagesRef.current = messages;
  const otherIdRef = useRef<string | undefined>(other?.id);
  otherIdRef.current = other?.id;
  const userIdRef = useRef<string | undefined>(user?.id);
  userIdRef.current = user?.id;

  const markMessagesAsRead = useCallback(async () => {
    const otherId = otherIdRef.current;
    const userId = userIdRef.current;
    const msgs = messagesRef.current;
    if (!id || !otherId || !msgs.length || !userId) return;
    const theirMsgIds = msgs.filter((m) => m.sender_id === otherId).map((m) => m.id);
    if (!theirMsgIds.length) return;
    const existingReads = await getMessageReads(supabase, userId, theirMsgIds);
    const alreadyReadSet = new Set(existingReads);
    const unreadIds = theirMsgIds.filter(id => !alreadyReadSet.has(id));
    if (unreadIds.length === 0) return;
    await markMessagesRead(supabase, userId, unreadIds);
  }, [id]);

  const isLoadingReadReceipts = useRef(false);

  const loadReadReceipts = useCallback(async () => {
    if (isLoadingReadReceipts.current) return;
    isLoadingReadReceipts.current = true;
    const otherId = otherIdRef.current;
    const userId = userIdRef.current;
    const msgs = messagesRef.current;
    if (!id || !otherId || !msgs.length) { isLoadingReadReceipts.current = false; return; }
    const myMsgIds = msgs.filter((m) => m.sender_id === userId).map((m) => m.id);
    if (!myMsgIds.length) { isLoadingReadReceipts.current = false; return; }
    const readIds = await getMessageReads(supabase, otherId, myMsgIds);
    setReadMessageIds(new Set(readIds));
    isLoadingReadReceipts.current = false;
  }, [id]);

  const initialLoadDone = useRef(false);
  useEffect(() => {
    if (!id || authLoading || !user) return;
    if (initialLoadDone.current) return;
    initialLoadDone.current = true;
    loadOther(); loadMessages(); loadBackground(); loadAvailableBgs();
  }, [id, user, authLoading]);

  useEffect(() => {
    if (!id || !user) return;
    const channel = createRealtimeChannel(`chat-${id}`)
      .on("postgres_changes", { event: "INSERT", schema: "public", table: "messages", filter: `conversation_id=eq.${id}` },
        (p: any) => {
          const msg = p.new as Message;
          setMessages((prev) => (prev.some((m) => m.id === msg.id) ? prev : [...prev, msg]));
          if (msg.sender_id === user.id) setDeliveredIds(prev => { const n = new Set(prev); n.add(msg.id); return n; });
          setTimeout(() => scrollToBottom("auto"), 50);
          if (msg.sender_id !== user.id) {
            if (profile?.notification_settings?.chat !== false && profile?.notification_settings?.sound !== false && document.visibilityState !== "visible") playNotificationSound();
          }
        })
      .on("postgres_changes", { event: "UPDATE", schema: "public", table: "messages", filter: `conversation_id=eq.${id}` },
        (p: any) => { const u = p.new as Message; setMessages((prev) => prev.map((m) => m.id === u.id ? { ...m, ...u } : m)); })
      .on("postgres_changes", { event: "DELETE", schema: "public", table: "messages", filter: `conversation_id=eq.${id}` },
        (p: any) => setMessages((prev) => prev.filter((m) => m.id !== p.old.id)))
      .subscribe();
    return () => {
      supabase.removeChannel(channel);
      for (const timer of deliveredTimersRef.current.values()) clearTimeout(timer);
      deliveredTimersRef.current.clear();
    };
  }, [id, user]);

  useEffect(() => {
    if (!other?.id || !id || authLoading) return;
    const readsChannel = createRealtimeChannel(`reads-${id}`)
      .on("postgres_changes", { event: "INSERT", schema: "public", table: "message_reads", filter: `user_id=eq.${other.id}` },
        () => loadReadReceiptsRef.current())
      .subscribe();
    return () => { supabase.removeChannel(readsChannel); };
  }, [other?.id, id, authLoading]);

  useEffect(() => {
    if (!id || authLoading || !user) return;
    if (initialLoadDone.current && messages.length === 0) loadMessages();
  }, [id, user, authLoading, messages.length]);

  const loadReadReceiptsRef = useRef(loadReadReceipts);
  const markMessagesAsReadRef = useRef(markMessagesAsRead);
  useEffect(() => {
    loadReadReceiptsRef.current = loadReadReceipts;
    markMessagesAsReadRef.current = markMessagesAsRead;
  }, [loadReadReceipts, markMessagesAsRead]);

  useEffect(() => {
    if (messages.length > 0 && other?.id) loadReadReceiptsRef.current();
  }, [messages.length, other?.id]);

  useEffect(() => {
    if (!user || !other?.id || messages.length === 0) return;
    const checkAndMarkRead = () => {
      if (document.visibilityState === "visible" && scrollRef.current) {
        markMessagesAsReadRef.current();
        loadReadReceiptsRef.current();
      }
    };
    checkAndMarkRead();
    const interval = setInterval(checkAndMarkRead, 2000);
    const handleVisibility = () => { if (document.visibilityState === "visible") checkAndMarkRead(); };
    document.addEventListener("visibilitychange", handleVisibility);
    return () => { clearInterval(interval); document.removeEventListener("visibilitychange", handleVisibility); };
  }, [user, other?.id, messages.length]);

  useEffect(() => {
    if (!other?.id) return;
    const ch = createRealtimeChannel(`presence-${other.id}`)
      .on("postgres_changes", { event: "UPDATE", schema: "public", table: "profiles", filter: `id=eq.${other.id}` },
        (p: any) => setOther((prev: any) => ({ ...prev, ...p.new })))
      .subscribe();
    const tick = setInterval(() => setOther((prev: any) => prev && { ...prev }), 30_000);
    return () => { supabase.removeChannel(ch); clearInterval(tick); };
  }, [other?.id]);

  const scrollToBottom = (behavior: ScrollBehavior = "smooth") => {
    scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight, behavior });
  };

  useEffect(() => {
    if (messages.length === 0) return;
    if (!userScrolledUp.current) scrollToBottom("auto");
  }, [messages.length]);

  useEffect(() => {
    const el = scrollRef.current;
    if (!el) return;
    const ro = new ResizeObserver(() => {
      if (!userScrolledUp.current && msgsLenRef.current > 0) scrollToBottom("auto");
    });
    ro.observe(el);
    return () => ro.disconnect();
  }, []);

  const isLoadingMoreRef = useRef(false);
  useEffect(() => {
    const el = scrollRef.current;
    if (!el) return;
    let ticking = false;
    const onScroll = () => {
      if (ticking) return;
      ticking = true;
      requestAnimationFrame(() => {
        const nearBottom = isNearBottom();
        setShowJumpToBottom(!nearBottom);
        userScrolledUp.current = !nearBottom;
        if (el.scrollTop < 240 && hasMoreMessages && !isLoadingOlder && !isLoadingMoreRef.current) {
          isLoadingMoreRef.current = true;
          loadOlderMessagesRef.current().finally(() => { isLoadingMoreRef.current = false; });
        }
        ticking = false;
      });
    };
    el.addEventListener("scroll", onScroll, { passive: true });
    onScroll();
    return () => el.removeEventListener("scroll", onScroll as any);
  }, [hasMoreMessages, isLoadingOlder]);

  useEffect(() => {
    if (!initialScrollDone.current && messages.length > 0) {
      requestAnimationFrame(() => { scrollToBottom("auto"); setTimeout(() => scrollToBottom("auto"), 300); });
      initialScrollDone.current = true;
      return;
    }
    if (isNearBottom()) scrollToBottom("smooth");
  }, [messages, isOtherTyping]);

  const touchStartX = useRef(0);
  const touchStartY = useRef(0);
  useEffect(() => {
    const el = scrollRef.current;
    if (!el) return;
    const handleTouchStart = (e: TouchEvent) => {
      touchStartX.current = e.touches[0].clientX;
      touchStartY.current = e.touches[0].clientY;
    };
    el.addEventListener('touchstart', handleTouchStart, { passive: true });
    return () => el.removeEventListener('touchstart', handleTouchStart);
  }, []);

  /* ── wallpaper ── */
  const loadBackground = async () => {
    if (!id) return;
    const { data } = await supabase.from("conversation_backgrounds").select("*, chat_backgrounds(*)").eq("conversation_id", id).maybeSingle();
    if (data) {
      const bg = (data as any).chat_backgrounds;
      if (bg) {
        setBgImage(bg.image_url || null); setBgGradient(bg.gradient_css || null);
        setBgBubbleColor(bg.chat_bubble_color || "rgba(255,255,255,0.08)");
        setBgBubbleMineColor(bg.chat_bubble_mine_color || "rgba(250,204,21,0.9)");
        setBgTextColor(bg.chat_text_color || "#ffffff");
      } else if ((data as any).custom_image_url) {
        setBgImage((data as any).custom_image_url); setBgGradient(null);
      }
    }
  };

  const loadAvailableBgs = async () => {
    try {
      const { data, error } = await supabase.from("chat_backgrounds").select("*").eq("is_active", true);
      if (error) throw error;
      if (data && data.length > 0) setAvailableBgs(data);
    } catch (e) { console.error("Error loading backgrounds:", e); }
  };

  const setWallpaper = async (bgId: string | null, customUrl?: string) => {
    if (!id || !user) return;
    if (bgId) {
      const bg = availableBgs.find((b: any) => b.id === bgId);
      if (bg) { setBgImage(bg.image_url || null); setBgGradient(bg.gradient_css || null); setBgBubbleColor(bg.chat_bubble_color); setBgBubbleMineColor(bg.chat_bubble_mine_color); setBgTextColor(bg.chat_text_color); }
    } else { setBgImage(customUrl || null); setBgGradient(null); }
    await supabase.from("conversation_backgrounds").upsert({ conversation_id: id, background_id: bgId, custom_image_url: customUrl || null, set_by: user.id }, { onConflict: "conversation_id" });
    setShowBgPicker(false);
  };

  const removeWallpaper = async () => {
    if (!id) return;
    await supabase.from("conversation_backgrounds").delete().eq("conversation_id", id);
    setBgImage(null); setBgGradient(null);
    setBgBubbleColor("rgba(255,255,255,0.08)"); setBgBubbleMineColor("rgba(250,204,21,0.9)"); setBgTextColor("#ffffff");
    setShowBgPicker(false);
  };

  /* ── actions ── */
  const send = async (overrides?: Partial<Message>) => {
    if (!user || !id) return;
    const tempId = crypto.randomUUID();
    const payload: any = { id: tempId, conversation_id: id, sender_id: user.id, type: "text", content: text.trim() || null, ...overrides };
    if (replyTo) payload.reply_to_message_id = replyTo.id;
    if (payload.type === "text" && !payload.content) return;
    const inputText = text;
    setText(""); setReplyTo(null);
    const optimisticMessage: Message = {
      id: tempId, conversation_id: id, sender_id: user.id,
      type: payload.type, content: payload.content || null,
      media_url: payload.media_url || null, sticker_id: payload.sticker_id || null,
      duration_seconds: payload.duration_seconds || null,
      is_view_once: payload.is_view_once || false,
      reply_to_message_id: payload.reply_to_message_id || null,
      location_lat: payload.location_lat, location_lng: payload.location_lng,
      created_at: new Date().toISOString(),
    };
    setMessages((prev) => [...prev, optimisticMessage]);
    setDeliveredIds((prev) => { const n = new Set(prev); n.add(tempId); return n; });
    try {
      const { data, error } = await supabase.from("messages").insert(payload).select().single();
      if (error) { setMessages((prev) => prev.filter((m) => m.id !== tempId)); if (payload.type === "text") setText(inputText); toast.error(error.message || "Falha ao enviar"); return; }
      if (data) {
        setMessages((prev) => prev.map((m) => m.id === tempId ? (data as Message) : m));
        const timer = setTimeout(() => {
          setDeliveredIds(prev => { const n = new Set(prev); n.add(data.id); return n; });
          deliveredTimersRef.current.delete(data.id);
        }, 1500);
        deliveredTimersRef.current.set(data.id, timer);
      }
    } catch (err: any) { setMessages((prev) => prev.filter((m) => m.id !== tempId)); if (payload.type === "text") setText(inputText); toast.error(err.message || "Falha ao enviar"); }
  };

  const sendImage = async (file: File, viewOnce = false) => {
    if (!user || !id) return;
    if (file.size > 8 * 1024 * 1024) return toast.error("Imagem muito grande");
    let pngFile: File;
    try { pngFile = await fileToPng(file); } catch { return toast.error("Falha ao converter imagem"); }
    if (pngFile.size > 8 * 1024 * 1024) return toast.error("Imagem PNG ficou muito grande (máx 8MB)");
    let lat: number | undefined, lng: number | undefined;
    try {
      const pos = await new Promise<GeolocationPosition>((res, rej) => navigator.geolocation.getCurrentPosition(res, rej, { timeout: 5000 }));
      lat = pos.coords.latitude; lng = pos.coords.longitude;
    } catch {}
    const safeName = pngFile.name.replace(/[^\w.-]+/g, "_");
    const path = `${user.id}/${Date.now()}-${safeName}`;
    const { error: upErr } = await supabase.storage.from("chat-media").upload(path, pngFile, { contentType: "image/png", upsert: false });
    if (upErr) return toast.error("Falha no upload");
    const { data: signed } = await supabase.storage.from("chat-media").createSignedUrl(path, 60 * 60 * 24 * 365);
    if (!signed?.signedUrl) return toast.error("Falha ao gerar URL");
    await send({ type: "image", media_url: signed.signedUrl, content: null, is_view_once: viewOnce, location_lat: lat, location_lng: lng } as any);
    setViewOnceMode(false);
  };

  const sendVideo = async (file: File) => {
    if (!user || !id) return;
    if (file.size > 100 * 1024 * 1024) return toast.error("Vídeo muito grande (máx 100MB)");
    const safeName = file.name.replace(/[^\w.-]+/g, "_");
    const path = `${user.id}/${Date.now()}-${safeName}`;
    const { error: upErr } = await supabase.storage.from("chat-media").upload(path, file, { upsert: false });
    if (upErr) return toast.error("Falha no upload do vídeo");
    const { data: signed } = await supabase.storage.from("chat-media").createSignedUrl(path, 60 * 60 * 24 * 365);
    if (!signed?.signedUrl) return toast.error("Falha ao gerar URL");
    const video = document.createElement("video");
    video.preload = "metadata";
    const dur = await new Promise<number>((resolve) => {
      video.onloadedmetadata = () => { resolve(Math.round(video.duration)); };
      video.onerror = () => resolve(0);
      video.src = signed.signedUrl;
    });
    await send({ type: "video", media_url: signed.signedUrl, content: null, duration_seconds: dur } as any);
  };

  const startRecording = async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      const rec = new MediaRecorder(stream);
      chunksRef.current = []; startedAtRef.current = Date.now();
      rec.ondataavailable = (e) => chunksRef.current.push(e.data);
      rec.onstop = () => {
        stream.getTracks().forEach((t) => t.stop());
        const blob = new Blob(chunksRef.current, { type: "audio/webm" });
        const dur = Math.round((Date.now() - startedAtRef.current) / 1000);
        const url = URL.createObjectURL(blob);
        setAudioPreview({ blob, url, duration: dur });
      };
      rec.start(); recorderRef.current = rec; setRecording(true);
    } catch { toast.error("Microfone bloqueado"); }
  };
  const stopRecording = () => { recorderRef.current?.stop(); recorderRef.current = null; setRecording(false); };

  const openStickers = () => setShowStickers((s) => !s);
  
  const startCall = async (type: "audio" | "video") => {
    if (!user || !other) return;
    const { data, error } = await supabase.from("calls").insert({ caller_id: user.id, callee_id: other.id, type, status: "ringing" }).select().single();
    if (error || !data) return toast.error("Falha ao chamar");
    navigate(`/call/${data.id}`);
  };

  const handlePressStart = (msg: Message) => {
    setPressingId(msg.id);
    longPressTimer.current = setTimeout(() => {
      setActionFor(msg);
      setPressingId(null);
      if ('vibrate' in navigator) navigator.vibrate(12);
    }, 400);
  };
  const handlePressEnd   = () => {
    setPressingId(null);
    if (longPressTimer.current) { clearTimeout(longPressTimer.current); longPressTimer.current = null; }
  };
  const canEdit = (m: Message) => m.sender_id === user?.id && m.type === "text" && Date.now() - new Date(m.created_at).getTime() < EDIT_WINDOW_MS;
  const startEdit = (m: Message) => { setActionFor(null); setEditingId(m.id); setEditText(m.content || ""); };
  const saveEdit = async () => {
    if (!editingId) return;
    const newText = editText.trim();
    if (!newText) { setEditingId(null); return; }
    const { error } = await supabase.rpc("edit_message", { p_message_id: editingId, p_new_content: newText });
    if (error) toast.error(error.message || "Falha ao editar");
    setEditingId(null); setEditText("");
  };
  const deleteMsg = async (m: Message) => { setActionFor(null); const { error } = await supabase.from("messages").delete().eq("id", m.id); if (error) toast.error("Falha ao excluir"); };
  const cancelReply = () => setReplyTo(null);
  const handleReplyMessage = (m: Message) => { setReplyTo(m); setActionFor(null); };

  const handleTouchStartForReply = (e: TouchEvent, msg: Message) => {
    swipeStartXRef.current = e.touches[0].clientX; swipeDxRef.current = 0;
  };
  const handleTouchMoveForReply = (e: TouchEvent, msg: Message) => {
    const dx = e.touches[0].clientX - swipeStartXRef.current;
    swipeDxRef.current = dx;
    const clamped = Math.min(Math.max(dx, 0), 80);
    if (clamped > 0) setSwipeState({ msgId: msg.id, dx: clamped });
  };
  const handleTouchEndForReply = (msg: Message) => {
    if (swipeDxRef.current >= SWIPE_THRESHOLD) { setReplyTo(msg); if ('vibrate' in navigator) navigator.vibrate(30); }
    setSwipeState(null); swipeDxRef.current = 0;
  };

  const addReaction = useCallback(async (msgId: string, emoji: string) => {
    if (!user) return;
    await supabase.from("message_reactions").upsert(
      { user_id: user.id, message_id: msgId, emoji },
      { onConflict: "message_id,user_id,emoji", ignoreDuplicates: true }
    );
    reloadReactions();
  }, [user, reloadReactions]);

  const handleDoubleClick = useCallback((msgId: string) => {
    addReaction(msgId, "❤️");
  }, [addReaction]);

  const handleMessageClick = useCallback((msgId: string) => {
    const now = Date.now();
    const last = lastClickTime.current.get(msgId) || 0;
    if (now - last < 400) {
      handleDoubleClick(msgId);
      lastClickTime.current.delete(msgId);
    } else {
      lastClickTime.current.set(msgId, now);
    }
  }, [handleDoubleClick]);

  const scrollToMessage = useCallback(async (targetMsgId: string) => {
    if (!scrollRef.current) return;
    let attempts = 0;
    const tryScroll = () => {
      const el = scrollRef.current!.querySelector(`[data-message-id="${targetMsgId}"]`) as HTMLElement | null;
      if (el) {
        const top = el.offsetTop - scrollRef.current!.offsetTop - 120;
        scrollRef.current!.scrollTo({ top, behavior: 'smooth' });
        setHighlightMsgId(targetMsgId);
        setTimeout(() => setHighlightMsgId(null), 2000);
        el.style.scrollMargin = "120px";
        return true;
      }
      return false;
    };
    const check = () => {
      if (tryScroll()) return;
      if (attempts < 3 && hasMoreMessages) { attempts++; loadOlderMessages(); setTimeout(check, 800); }
    };
    check();
  }, [hasMoreMessages, loadOlderMessages]);

  const handleReplyClick = useCallback((msgId: string) => { scrollToMessage(msgId); }, [scrollToMessage]);

  const cancelAudioPreview = useCallback(() => {
    if (audioPreview) { URL.revokeObjectURL(audioPreview.url); setAudioPreview(null); }
  }, [audioPreview]);

  const confirmAudioPreview = useCallback(async () => {
    if (!audioPreview || !user || !id) return;
    const blob = audioPreview.blob;
    const dur = audioPreview.duration;
    const path = `${user.id}/${Date.now()}.webm`;
    const { error: upErr } = await supabase.storage.from("chat-media").upload(path, blob);
    if (upErr) { toast.error("Falha no upload"); return; }
    const { data: signed } = await supabase.storage.from("chat-media").createSignedUrl(path, 60 * 60 * 24 * 365);
    if (signed?.signedUrl) await send({ type: "audio", media_url: signed.signedUrl, duration_seconds: dur, content: null });
    cancelAudioPreview();
  }, [audioPreview, user, id, send, cancelAudioPreview]);

  const presenceLabel = other?.show_activity !== false ? formatLastSeen(other?.last_seen_at) : "";
  const onlineNow     = other?.show_activity !== false && isOnline(other?.last_seen_at);

  /* ─────────────────────── JSX ─── */
  return (
    <div className="relative flex h-[100dvh] w-full flex-col overflow-hidden bg-base">

      {/* ── Centering shell ── */}
      <div className="relative mx-auto flex h-full w-full flex-col md:max-w-3xl md:py-4 lg:max-w-4xl">
        <div className="flex h-full flex-col overflow-hidden md:rounded-[28px] md:shadow-2xl md:shadow-black/70 md:border md:border-border-dim bg-surface-0">

          {/* ══ HEADER ══ */}
          <header className="shrink-0 z-[1000] bg-black/70 border-b border-white/[0.04] backdrop-blur-2xl pt-[env(safe-area-inset-top,0px)]">
            <div className="flex items-center gap-2 px-4 py-3 sm:px-6">

              {/* Back */}
              <button
                onClick={() => navigate(-1)}
                aria-label="Voltar"
                className="shrink-0 flex items-center justify-center w-[38px] h-[38px] sm:w-9 sm:h-9 rounded-xl bg-white/[0.04] hover:bg-white/[0.08] transition-all text-muted-foreground hover:text-foreground"
              >
                <ArrowLeft className="w-[17px] h-[17px]" />
              </button>

              {/* User info clickable */}
              {other && (
                <>
                  <button
                    onPointerDown={triggerPinguShake}
                    onClick={() => navigate(profilePath(other.id, other.username))}
                    className="flex min-w-0 flex-1 items-center gap-2.5 rounded-2xl px-2 py-1.5 hover:bg-white/[0.03] transition-all active:scale-[0.99]"
                  >
                    {/* Avatar with online ring */}
                    <div className="relative shrink-0">
                      <div className={cn(
                        "rounded-full p-[2px]",
                        onlineNow
                          ? "bg-gradient-to-br from-green-400 to-emerald-500"
                          : "bg-white/[0.06]"
                      )}>
                        <div className="rounded-full overflow-hidden bg-surface" style={{ width: 34, height: 34 }}>
                          <ChatAvatar url={other.photo_url} name={other.display_name} size={34} />
                        </div>
                      </div>
                      {/* Active pulsing dot */}
                      {onlineNow && (
                        <span className="absolute bottom-0 right-0 w-2.5 h-2.5 rounded-full bg-green-500 border-2 border-base" />
                      )}
                    </div>

                    <div className="min-w-0 flex-1">
                      <div className="flex items-center gap-1.5">
                        <RGBName
                          name={otherNickname || other.display_name || other.username || "Usuário"}
                          profile_theme={other.profile_theme}
                          className="text-[14px] font-bold leading-tight truncate"
                        />
                        {other.is_verified && <VerifiedBadge size="xs" />}
                        {otherNickname && (
                          <span className="text-[9px] font-bold tracking-wider uppercase px-1.5 py-[2px] rounded-md bg-primary/10 text-primary/80 border border-primary/15 shrink-0">
                            apelido
                          </span>
                        )}
                      </div>
                      <p className={cn("text-[11px] font-medium leading-none mt-0.5", onlineNow ? "text-green-400" : "text-muted-foreground/70")}>
                        {isOtherTyping
                          ? <span className="text-primary animate-pulse">digitando...</span>
                          : onlineNow ? "online agora" : (presenceLabel || "offline")}
                      </p>
                    </div>
                  </button>

                  {/* Desktop actions */}
                  <div className="hidden md:flex shrink-0 items-center gap-1">
                    <button onClick={() => startCall("audio")} aria-label="Voz"
                      className="w-9 h-9 rounded-xl bg-white/[0.04] hover:bg-white/[0.08] text-muted-foreground hover:text-foreground transition-all hidden md:flex items-center justify-center">
                      <Phone className="w-[15px] h-[15px]" />
                    </button>
                    <button onClick={() => startCall("video")} aria-label="Vídeo"
                      className="w-9 h-9 rounded-xl bg-white/[0.04] hover:bg-white/[0.08] text-muted-foreground hover:text-foreground transition-all hidden md:flex items-center justify-center">
                      <Video className="w-[15px] h-[15px]" />
                    </button>
                    <div className="w-px h-5 bg-white/[0.07] mx-0.5" />
                    <button onClick={() => { loadAvailableBgs(); setShowBgPicker(true); }} aria-label="Fundo"
                      className={cn("w-9 h-9 rounded-xl bg-white/[0.04] hover:bg-white/[0.08] text-muted-foreground hover:text-foreground transition-all hidden md:flex items-center justify-center",
                        (bgImage || bgGradient) ? "bg-primary/10 border-primary/25 text-primary" : ""
                      )}>
                      <svg className="w-[15px] h-[15px]" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
                    </button>
                    <button onClick={() => { setNicknameInputVal(otherNickname || ""); setShowNicknameInput(true); }} aria-label="Apelido"
                      className={cn("w-9 h-9 rounded-xl bg-white/[0.04] hover:bg-white/[0.08] text-muted-foreground hover:text-foreground transition-all hidden md:flex items-center justify-center",
                        otherNickname ? "bg-primary/10 border-primary/25 text-primary" : ""
                      )}>
                      <Tag className="w-[15px] h-[15px]" />
                    </button>
                  </div>

                  {/* Mobile menu */}
                  <button
                    onClick={() => setShowMobileMenu(!showMobileMenu)}
                    aria-label="Menu"
                    className={cn("w-9 h-9 rounded-xl bg-white/[0.04] hover:bg-white/[0.08] text-muted-foreground hover:text-foreground transition-all md:hidden flex items-center justify-center",
                      showMobileMenu ? "bg-primary/10 border-primary/25 text-primary" : ""
                    )}
                  >
                    <MoreVertical className="w-[15px] h-[15px]" />
                  </button>
                </>
              )}
            </div>

            {/* Mobile bottom sheet menu */}
            <AnimatePresence>
              {showMobileMenu && (
                <>
                  <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}
                    className="md:hidden fixed inset-0 z-[11999] bg-black/60 backdrop-blur-sm"
                    onClick={() => setShowMobileMenu(false)}
                  />
                  <motion.div
                    initial={{ y: "100%", opacity: 0 }} animate={{ y: 0, opacity: 1 }} exit={{ y: "100%", opacity: 0 }}
                    transition={{ type: "spring", damping: 30, stiffness: 350 }}
                    className="md:hidden fixed bottom-0 left-0 right-0 z-[12000] mx-auto rounded-t-[28px] p-5 pt-4 bg-surface-1 border border-border-soft border-b-0 pb-[max(20px,env(safe-area-inset-bottom,20px))]"
                    style={{ maxWidth: 480 }}
                  >
                    <div className="w-10 h-[3px] rounded-full mx-auto mb-5 bg-white/[0.08]" />
                    <p className="text-[11px] font-bold text-muted-foreground/60 uppercase tracking-widest mb-3 px-1">Ações</p>
                    <div className="grid grid-cols-4 gap-3 mb-4">
                      {[
                        { icon: Phone, label: "Voz", colorClass: "text-green-400", bgClass: "bg-green-400/15", fn: () => { startCall("audio"); setShowMobileMenu(false); } },
                        { icon: Video, label: "Vídeo", colorClass: "text-blue-400", bgClass: "bg-blue-400/15", fn: () => { startCall("video"); setShowMobileMenu(false); } },
                        { icon: () => <svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>, label: "Fundo", colorClass: "text-primary", bgClass: "bg-primary/15", active: !!(bgImage || bgGradient), fn: () => { loadAvailableBgs(); setShowBgPicker(true); setShowMobileMenu(false); } },
                        { icon: Tag, label: "Apelido", colorClass: "text-violet-400", bgClass: "bg-violet-400/15", active: !!otherNickname, fn: () => { setNicknameInputVal(otherNickname || ""); setShowNicknameInput(true); setShowMobileMenu(false); } },
                      ].map(({ icon: Icon, label, colorClass, bgClass, active, fn }) => (
                        <button key={label} onClick={fn}
                          className="flex flex-col items-center gap-2 py-3 rounded-2xl transition-all hover:bg-white/[0.04] active:scale-95"
                        >
                          <span className={cn("w-12 h-12 rounded-2xl flex items-center justify-center", active ? bgClass : "bg-white/[0.05]")}>
                            <Icon className={active ? colorClass : "text-muted-foreground"} size={18} />
                          </span>
                          <span className={cn("text-[10px] font-semibold", active ? colorClass : "text-muted-foreground/80")}>{label}</span>
                        </button>
                      ))}
                    </div>
                    <button onClick={() => setShowMobileMenu(false)}
                      className="w-full py-3 rounded-2xl text-[13px] font-semibold text-muted-foreground/70 bg-white/[0.03] hover:bg-white/[0.06] hover:text-foreground transition-all active:scale-[0.98]">
                      Fechar
                    </button>
                  </motion.div>
                </>
              )}
            </AnimatePresence>
          </header>

          {/* ══ MESSAGES AREA ══ */}
          <div className="relative min-h-0 flex flex-1 flex-col overflow-hidden">

            {/* Wallpaper */}
            {(bgImage || bgGradient) && (
              <div aria-hidden className="absolute inset-0 z-0 pointer-events-none"
                style={{ ...(bgImage ? { backgroundImage: `url(${bgImage})`, backgroundSize: "cover", backgroundPosition: "center" } : { background: bgGradient! }) }}
              />
            )}

            {/* Scroll container */}
            <div ref={scrollRef}
              className="scrollbar-hide relative z-[1] flex-1 overflow-y-auto overscroll-y-contain touch-pan-y px-3 pt-4 pb-3 sm:px-4"
            >
              {/* Loading older */}
              {isLoadingOlder && (
                <div className="flex justify-center pb-3 pt-1">
                  <div className="flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-white/[0.05] border border-border-soft">
                    {[0, 100, 200].map((d) => (
                      <span key={d} className="w-1.5 h-1.5 rounded-full bg-primary animate-bounce" style={{ animationDelay: `${d}ms`, opacity: 0.7 }} />
                    ))}
                  </div>
                </div>
              )}

              {/* Loading skeleton */}
              {messages.length === 0 && isLoadingMessages && (
                <div className="flex flex-col gap-4 px-4 py-6">
                  {[1, 2, 3, 4].map((i) => (
                    <div key={i} className={cn("flex items-end gap-2.5", i % 2 === 0 && "justify-end")}>
                      {i % 2 !== 0 && (
                        <div className="w-7 h-7 rounded-full bg-white/[0.04] animate-pulse shrink-0" />
                      )}
                      <div className={cn("space-y-2.5 flex flex-col", i % 2 === 0 && "items-end")}>
                        <div className={cn("h-[34px] rounded-2xl bg-white/[0.04] animate-pulse", i % 2 === 0 ? "w-44" : "w-32")}
                          style={{ animationDelay: `${i * 100}ms` }} />
                        <div className={cn("h-[34px] rounded-2xl bg-white/[0.04] animate-pulse", i % 2 === 0 ? "w-28" : "w-40")}
                          style={{ animationDelay: `${i * 150 + 100}ms` }} />
                      </div>
                    </div>
                  ))}
                </div>
              )}

              {/* Empty state */}
              {messages.length === 0 && !isLoadingMessages && !authLoading && other && (
                <div className="flex flex-col items-center justify-center py-16 gap-4">
                  <div className="relative">
                    <div className="w-20 h-20 rounded-full overflow-hidden flex items-center justify-center bg-white/[0.04] border-2 border-white/[0.04] shadow-xl shadow-black/30">
                      <BrandLogo size={60} />
                    </div>
                  </div>
                  <div className="text-center space-y-2">
                    <RGBName name={otherNickname || other.display_name || "Usuário"} profile_theme={other.profile_theme} className="text-[15px] font-bold block" />
                    <div className="flex items-center justify-center gap-2">
                      <span className="w-5 h-px bg-white/[0.04]" />
                      <p className="text-[9px] font-semibold tracking-[0.2em] uppercase text-muted-foreground/40">
                        início da conversa
                      </p>
                      <span className="w-5 h-px bg-white/[0.04]" />
                    </div>
                    <p className="text-[10px] text-muted-foreground/30 font-medium">🔒 criptografada de ponta a ponta</p>
                  </div>
                </div>
              )}

              {/* Message list */}
              <div className="flex flex-col gap-[1px]">
                {messages.map((m, idx) => {
                  const mine         = m.sender_id === user?.id;
                  const replyMessage = m.reply_to_message_id ? messageById.get(m.reply_to_message_id) || null : null;
                  const isEditing    = editingId === m.id;
                  const prevMsg      = idx > 0 ? messages[idx - 1] : null;
                  const nextMsg      = idx < messages.length - 1 ? messages[idx + 1] : null;

                  const showDateSep    = !prevMsg || new Date(prevMsg.created_at).toDateString() !== new Date(m.created_at).toDateString();
                  const isLastInGroup  = !nextMsg || nextMsg.sender_id !== m.sender_id || new Date(nextMsg.created_at).toDateString() !== new Date(m.created_at).toDateString();
                  const isFirstInGroup = !prevMsg || prevMsg.sender_id !== m.sender_id || showDateSep;

                  // Instagram-style bubble radius: only tail on last message in group
                  const TAIL = 20;
                  const BODY = 20;
                  const TIP  = 6;
                  const mineRadius = mine
                    ? `${BODY}px ${isFirstInGroup ? BODY : TIP}px ${isLastInGroup ? TIP : TIP}px ${BODY}px`
                    : `${isFirstInGroup ? BODY : TIP}px ${BODY}px ${BODY}px ${isLastInGroup ? TIP : TIP}px`;

                  return (
                    <div key={m.id} data-message-id={m.id}
                      style={{ marginTop: isFirstInGroup ? 14 : 0 }}
                      className={cn(highlightMsgId === m.id && "ring-1 ring-primary/30 shadow-[0_0_20px_-6px] shadow-primary/20 rounded-2xl animate-pulse")}
                    >
                      {/* Date separator */}
                      {showDateSep && (
                        <div className="flex items-center justify-center my-3">
                          <span className="px-4 py-1.5 text-[9px] font-semibold tracking-[0.1em] uppercase text-white/50 bg-white/[0.04] backdrop-blur-md rounded-full border border-white/[0.04] select-none">
                            {formatDateSeparator(m.created_at)}
                          </span>
                        </div>
                      )}

                      {/* Message row */}
                      <motion.div
                        initial={{ opacity: 0, x: mine ? 12 : -12 }}
                        animate={{ opacity: 1, x: 0 }}
                        transition={{ duration: 0.18, ease: [0.22, 1, 0.36, 1] }}
                        className={cn("flex items-end gap-1.5", mine ? "justify-end" : "justify-start")}
                      >
                        {/* Other avatar — only on last message in group */}
                        {!mine && (
                          <div className="w-6 shrink-0 self-end mb-1">
                            {isLastInGroup ? (
                              <div className="w-6 h-6 rounded-full overflow-hidden">
                                <ChatAvatar url={other?.photo_url} name={other?.display_name} size={24} />
                              </div>
                            ) : (
                              <div style={{ width: 24, height: 24 }} />
                            )}
                          </div>
                        )}

                        {/* Bubble wrapper */}
                        <div
                          className={cn("relative", m.type === "sticker" ? "z-20 w-auto" : "w-full max-w-[85%] md:max-w-[70%] lg:max-w-[65%]")}
                        >
                          <div
                            onClick={() => handleMessageClick(m.id)}
                            onPointerDown={() => handlePressStart(m)}
                            onPointerUp={handlePressEnd}
                            onPointerLeave={handlePressEnd}
                            onContextMenu={(e) => { e.preventDefault(); setActionFor(m); }}
                            onTouchStart={(e) => handleTouchStartForReply(e, m)}
                            onTouchMove={(e) => handleTouchMoveForReply(e, m)}
                            onTouchEnd={() => { handlePressEnd(); handleTouchEndForReply(m); }}
                            className={cn(
                              "relative select-none",
                              m.type === "sticker" ? "bg-transparent p-0 border-none shadow-none overflow-visible" : "overflow-hidden",
                              m.type !== "sticker" && "cursor-default",
                              m.type !== "sticker" && m.type !== "image" && m.type !== "video" && m.type !== "audio" && "px-[11px] py-[7px]",
                              m.type !== "sticker" && mine && "shadow-sm",
                              m.type !== "sticker" && "hover:brightness-110",
                              pressingId === m.id && "scale-[0.96] brightness-[0.92]",
                            )}
                            style={{
                              borderRadius: m.type === "sticker" ? "0" : mineRadius,
                              transition: swipeState?.msgId === m.id ? 'none' : 'transform 0.15s cubic-bezier(0.2, 0.8, 0.2, 1), filter 0.12s ease',
                              transform: swipeState?.msgId === m.id ? `translateX(${swipeState.dx}px)` : 'translateX(0)',
                              ...(m.type !== "sticker" && (mine
                                ? {
                                    background: bgGradient || bgImage ? bgBubbleMineColor : "var(--bek-primary)",
                                    color: bgGradient || bgImage ? bgTextColor : "var(--text-bright)",
                                    boxShadow: "0 2px 8px rgba(59,130,246,0.15)",
                                  }
                                : {
                                    background: bgGradient || bgImage ? bgBubbleColor : "var(--surface-1)",
                                    color: bgGradient || bgImage ? bgTextColor : "var(--text-primary)",
                                    border: "1px solid rgba(255,255,255,0.06)",
                                  }))
                            }}
                          >
                            {/* Subtle shine on mine bubble */}
                            {mine && m.type !== "sticker" && (
                              <div aria-hidden className="absolute inset-0 pointer-events-none rounded-[inherit]"
                                style={{ background: "linear-gradient(160deg, rgba(255,255,255,0.18) 0%, transparent 45%)" }} />
                            )}

                            {/* Reply preview */}
                            {replyMessage && (
                              <div
                                onClick={() => m.reply_to_message_id && handleReplyClick(m.reply_to_message_id)}
                                className="mb-2 px-2.5 pt-2 pb-1.5 rounded-xl cursor-pointer active:scale-[0.98] transition-transform hover:brightness-110 backdrop-blur-sm"
                                style={{
                                  background: mine ? "rgba(0,0,0,0.15)" : "rgba(255,255,255,0.06)",
                                  borderLeft: `2.5px solid ${mine ? "rgba(255,255,255,0.4)" : "rgba(250,204,21,0.6)"}`,
                                }}
                              >
                                <p className="text-[9px] font-bold uppercase tracking-wide mb-0.5"
                                  style={{ color: mine ? "rgba(255,255,255,0.7)" : "rgba(250,204,21,0.85)" }}>
                                  {replyMessage.sender_id === user?.id ? "Você" : other?.display_name || "Usuário"}
                                </p>
                                <p className="text-[11px] leading-snug line-clamp-2 text-white/60">
                                  {replyMessage.type === "text"
                                    ? (replyMessage.content || "").slice(0, 55) + ((replyMessage.content?.length || 0) > 55 ? "…" : "")
                                    : replyMessage.type === "image" ? "📷 Foto"
                                    : replyMessage.type === "video" ? "🎬 Vídeo"
                                    : replyMessage.type === "audio" ? "🎤 Áudio"
                                    : replyMessage.type === "sticker" ? "💫 Sticker"
                                    : "📎 Mensagem"}
                                </p>
                              </div>
                            )}

                            {/* TEXT */}
                            {m.type === "text" && !isEditing && (
                              <p className="text-[14px] leading-[1.45] whitespace-pre-wrap break-words"
                                style={{ wordBreak: "break-word", overflowWrap: "anywhere" }}>
                                {m.content}
                              </p>
                            )}

                            {/* EDIT inline */}
                            {m.type === "text" && isEditing && (
                              <div className="w-full bg-white/[0.06] rounded-xl px-3 py-2 text-sm text-bright border border-white/[0.06] outline-none resize-none" style={{ minWidth: 200 }}>
                                <input autoFocus value={editText}
                                  onChange={(e) => setEditText(e.target.value)}
                                  onKeyDown={(e) => { if (e.key === "Enter") saveEdit(); if (e.key === "Escape") setEditingId(null); }}
                                  className="flex-1 bg-transparent text-[13px] outline-none text-primary placeholder-white/30 px-1.5"
                                />
                                <button onClick={saveEdit}
                                  className="w-7 h-7 rounded-lg flex items-center justify-center bg-primary/20 hover:bg-primary/30 transition-colors">
                                  <Check size={13} className="text-primary" />
                                </button>
                                <button onClick={() => setEditingId(null)}
                                  className="w-7 h-7 rounded-lg flex items-center justify-center bg-white/8 hover:bg-white/15 transition-colors">
                                  <X size={13} className="text-muted-foreground" />
                                </button>
                              </div>
                            )}

                            {/* IMAGE */}
                            {m.type === "image" && m.media_url && (
                              <div style={{ overflow: "hidden", borderRadius: "inherit" }}>
                                {m.is_view_once ? (
                                  <ViewOnceImage messageId={m.id} mediaUrl={m.media_url} isMine={mine} isAdmin={isAdmin} viewedAt={m.viewed_at || null} />
                                ) : (
                                  <img src={m.media_url} alt=""
                                    style={{ maxHeight: 320, width: "100%", objectFit: "cover", display: "block", cursor: "pointer" }}
                                    onClick={() => setMediaViewer({ src: m.media_url!, type: "image" })}
                                  />
                                )}
                              </div>
                            )}

                            {/* VIDEO */}
                            {m.type === "video" && m.media_url && (
                              <div className="overflow-hidden cursor-pointer group"
                                style={{ borderRadius: "inherit", position: "relative" }}
                                onClick={() => setMediaViewer({ src: m.media_url!, type: "video" })}>
                                <video src={m.media_url}
                                  style={{ maxHeight: 320, width: "100%", objectFit: "cover", display: "block" }}
                                  preload="metadata" playsInline muted />
                                <div className="absolute inset-0 flex items-center justify-center bg-black/10 group-hover:bg-black/20 transition-colors">
                                  <div className="w-12 h-12 rounded-full bg-black/60 backdrop-blur-md border border-white/20 flex items-center justify-center shadow-lg shadow-black/30 group-hover:scale-105 transition-transform">
                                    <svg className="w-5 h-5 text-white ml-0.5" viewBox="0 0 24 24" fill="currentColor"><polygon points="5,3 19,12 5,21"/></svg>
                                  </div>
                                </div>
                                {m.duration_seconds && (
                                  <span className="absolute bottom-2 right-2 px-1.5 py-0.5 rounded-md bg-black/70 text-[10px] font-medium text-white tabular-nums backdrop-blur-sm">
                                    {Math.floor(m.duration_seconds / 60)}:{(m.duration_seconds % 60).toString().padStart(2, "0")}
                                  </span>
                                )}
                              </div>
                            )}

                            {/* STICKER */}
                            {m.type === "sticker" && m.media_url && (
                              <img src={m.media_url} alt="sticker" loading="lazy"
                                style={{ width: 120, height: 120, objectFit: "contain", filter: "drop-shadow(0 4px 12px rgba(0,0,0,0.3))", display: "block" }} />
                            )}

                            {/* AUDIO */}
                            {m.type === "audio" && m.media_url && (
                              <AudioPlayer url={m.media_url} duration={m.duration_seconds || 0} isMine={mine} />
                            )}

                            {/* Reactions */}
                            {m.type !== "sticker" && getReactions(m.id).length > 0 && (
                              <div className="mt-1 -mb-0.5">
                                <MessageReactions
                                  messageId={m.id}
                                  reactions={getReactions(m.id)}
                                  onChange={() => reloadReactions()}
                                  align={mine ? "end" : "start"}
                                />
                              </div>
                            )}

                            {/* Timestamp + status */}
                            {m.type !== "sticker" && (
                              <div
                                className={cn("flex items-center gap-1", {
                                  "mt-1": m.type !== "image" && m.type !== "video",
                                })}
                                style={{
                                  justifyContent: mine ? "flex-end" : "flex-start",
                                  position: m.type === "image" || m.type === "video" ? "absolute" : "relative",
                                  ...(m.type === "image" || m.type === "video" ? { bottom: 4, right: 6 } : {}),
                                }}
                              >
                                {(m.type === "image" || m.type === "video") && (
                                  <div className="absolute inset-[-4px] rounded-md bg-gradient-to-t from-black/60 via-black/20 to-transparent pointer-events-none" />
                                )}
                                <div className={cn(
                                  "flex items-center gap-1 z-[1]",
                                  (m.type === "image" || m.type === "video") && "px-1 py-0.5"
                                )}>
                                  {m.edited_at && (
                                    <span className="text-[9px]" style={{ color: mine ? "rgba(255,255,255,0.45)" : "rgba(255,255,255,0.3)" }}>editado ·</span>
                                  )}
                                  <span className="text-[10px] font-medium tabular-nums"
                                    style={{ color: mine ? (m.type === "image" || m.type === "video" ? "rgba(255,255,255,0.9)" : "rgba(255,255,255,0.6)") : "rgba(255,255,255,0.35)" }}>
                                    {new Date(m.created_at).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}
                                  </span>
                                  {/* Read receipt checkmarks */}
                                  {mine && (
                                    <div className="flex items-center ml-0.5">
                                      {(() => {
                                        const isRead = readMessageIds.has(m.id);
                                        const isDelivered = deliveredIds.has(m.id);
                                        const checkColor = isRead ? "#60a5fa" : (m.type === "image" || m.type === "video" ? "rgba(255,255,255,0.85)" : "rgba(255,255,255,0.45)");
                                        return (
                                          <motion.svg
                                            initial={{ scale: 0.8, opacity: 0 }}
                                            animate={{ scale: 1, opacity: 1 }}
                                            transition={{ duration: 0.15 }}
                                            width={isRead || isDelivered ? 14 : 10} height={10} viewBox="0 0 14 10" fill="none"
                                          >
                                            <motion.path
                                              initial={{ pathLength: 0 }} animate={{ pathLength: 1 }}
                                              transition={{ duration: 0.2 }}
                                              d="M1 4.5L4 7.5L8 3"
                                              stroke={isRead ? "#60a5fa" : checkColor} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"
                                            />
                                            {(isRead || isDelivered) && (
                                              <motion.path
                                                initial={{ pathLength: 0 }} animate={{ pathLength: 1 }}
                                                transition={{ duration: 0.2, delay: 0.05 }}
                                                d="M5.5 4.5L8.5 7.5L13 2.5"
                                                stroke={isRead ? "#60a5fa" : checkColor} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"
                                              />
                                            )}
                                          </motion.svg>
                                        );
                                      })()}
                                    </div>
                                  )}
                                </div>
                              </div>
                            )}
                          </div>

                          {/* Reaction picker */}
                          {pickerFor === m.id && (
                            <div style={{ position: "absolute", bottom: "100%", zIndex: 40, marginBottom: 8, ...(mine ? { right: 0 } : { left: 0 }) }}>
                              <ReactionPicker messageId={m.id} onClose={() => setPickerFor(null)} onReacted={() => reloadReactions()} />
                            </div>
                          )}

                          {/* Swipe reply indicator */}
                          {swipeState?.msgId === m.id && swipeState.dx > 16 && (
                            <motion.div
                              initial={{ opacity: 0, scale: 0.5 }}
                              animate={{ opacity: Math.min(swipeState.dx / 60, 1), scale: 1 }}
                              className="absolute top-1/2 -translate-y-1/2 flex items-center gap-1"
                              style={{ left: mine ? undefined : -32, right: mine ? -32 : undefined }}
                            >
                              <span className="w-7 h-7 rounded-full bg-blue-500/20 border border-blue-500/30 flex items-center justify-center backdrop-blur-sm">
                                <CornerUpLeft size={12} className="text-blue-400" />
                              </span>
                            </motion.div>
                          )}
                        </div>
                      </motion.div>
                    </div>
                  );
                })}

                {/* Jump to bottom */}
                <AnimatePresence>
                  {showJumpToBottom && (
                    <motion.div
                      initial={{ opacity: 0, scale: 0.8, y: 10 }} animate={{ opacity: 1, scale: 1, y: 0 }} exit={{ opacity: 0, scale: 0.8, y: 10 }}
                      transition={{ type: "spring", damping: 25, stiffness: 350 }}
                      className="absolute bottom-4 right-4 z-10"
                    >
                      <button
                        onClick={() => { userScrolledUp.current = false; scrollToBottom("smooth"); }}
                        className="w-10 h-10 rounded-full bg-surface-1/90 backdrop-blur-xl border border-white/[0.08] shadow-xl flex items-center justify-center text-muted-foreground hover:text-foreground transition-all hover:scale-105"
                      >
                        <ChevronDown size={14} />
                      </button>
                    </motion.div>
                  )}
                </AnimatePresence>
              </div>
            </div>
          </div>

          {/* ══ TYPING INDICATOR ══ */}
          <AnimatePresence>
            {isOtherTyping && (
              <motion.div
                initial={{ opacity: 0, height: 0 }} animate={{ opacity: 1, height: "auto" }} exit={{ opacity: 0, height: 0 }}
                transition={{ duration: 0.15 }}
                className="shrink-0 overflow-hidden"
              >
                <div className="flex items-center gap-2 px-4 py-1.5">
                  <div className="flex items-center gap-[3px] bg-white/[0.04] border border-white/[0.04] rounded-2xl px-4 py-3">
                    {[0, 150, 300].map((d) => (
                      <span key={d} className="w-[5px] h-[5px] rounded-full bg-primary/70 animate-bounce" style={{ animationDelay: `${d}ms` }} />
                    ))}
                  </div>
                  <div className="flex items-center gap-1">
                    <span className="w-4 h-4 rounded-full overflow-hidden shrink-0">
                      <ChatAvatar url={other?.photo_url} name={other?.display_name} size={16} />
                    </span>
                    <span className="text-[10px] font-medium text-muted-foreground/50">
                      {other?.display_name?.split(" ")[0] || "Alguém"} está digitando
                    </span>
                  </div>
                </div>
              </motion.div>
            )}
          </AnimatePresence>

          {/* ══ INPUT BAR ══ */}
          <div className="shrink-0 bg-black/70 backdrop-blur-2xl border-t border-white/[0.04] px-4 pt-3 pb-[max(12px,env(safe-area-inset-bottom,12px))] sm:px-6">
            <input ref={fileInputRef} type="file" accept="image/*,video/*" className="hidden"
              onChange={(e) => {
                const f = e.target.files?.[0];
                if (f) { f.type.startsWith("video/") ? sendVideo(f) : sendImage(f, viewOnceMode); }
                e.currentTarget.value = "";
              }}
            />

            {/* Audio preview */}
            <AnimatePresence>
              {audioPreview && (
                <motion.div
                  initial={{ opacity: 0, height: 0 }} animate={{ opacity: 1, height: "auto" }} exit={{ opacity: 0, height: 0 }}
                  transition={{ duration: 0.15, ease: [0.22, 1, 0.36, 1] }} className="overflow-hidden mb-2"
                >
                  <div className="flex items-center gap-2.5 px-3 py-2.5 rounded-2xl bg-primary/[0.05] border border-primary/[0.1]">
                    <div className="w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center shrink-0">
                      <Mic size={14} className="text-primary" />
                    </div>
                    <audio src={audioPreview.url} controls className="h-9 min-w-[120px] flex-1 [&::-webkit-media-controls-panel]:bg-transparent" />
                    <span className="text-[10px] font-mono text-muted-foreground/70 shrink-0 tabular-nums">{audioPreview.duration}s</span>
                    <button onClick={confirmAudioPreview}
                      className="w-8 h-8 rounded-full flex items-center justify-center bg-primary text-white hover:bg-primary/90 transition-all shrink-0 active:scale-90">
                      <Send size={13} className="ml-0.5" />
                    </button>
                    <button onClick={cancelAudioPreview}
                      className="w-8 h-8 rounded-full flex items-center justify-center bg-white/[0.06] text-muted-foreground hover:text-foreground hover:bg-white/[0.1] transition-all shrink-0 active:scale-90">
                      <X size={13} />
                    </button>
                  </div>
                </motion.div>
              )}
            </AnimatePresence>

            {/* Reply preview */}
            <AnimatePresence>
              {replyTo && (
                <motion.div
                  initial={{ opacity: 0, height: 0 }} animate={{ opacity: 1, height: "auto" }} exit={{ opacity: 0, height: 0 }}
                  transition={{ duration: 0.15, ease: [0.22, 1, 0.36, 1] }} className="overflow-hidden mb-2"
                >
                  <div className="flex items-center gap-2.5 px-3.5 py-2.5 rounded-2xl bg-white/[0.04] border border-white/[0.06] active:scale-[0.99] transition-transform">
                    <div className="w-[3px] h-8 rounded-full shrink-0 bg-primary" />
                    <div className="min-w-0 flex-1">
                      <p className="text-[10px] font-bold mb-0.5 text-primary/90">
                        Respondendo a {replyTo.sender_id === user?.id ? "você mesmo" : (other?.display_name || "Alguém")}
                      </p>
                      <p className="text-[11px] truncate text-muted-foreground/70">
                        {replyTo.type === "text" ? replyTo.content : replyTo.type === "image" ? "📷 Foto" : replyTo.type === "video" ? "🎬 Vídeo" : replyTo.type === "audio" ? "🎤 Áudio" : replyTo.type === "sticker" ? "💫 Sticker" : "📎 Mensagem"}
                      </p>
                    </div>
                    <button onClick={cancelReply}
                      className="w-6 h-6 rounded-lg flex items-center justify-center bg-white/[0.06] text-muted-foreground hover:text-foreground hover:bg-white/[0.1] transition-colors shrink-0 active:scale-90">
                      <X size={11} />
                    </button>
                  </div>
                </motion.div>
              )}
            </AnimatePresence>

            {/* View-once indicator */}
            <AnimatePresence>
              {viewOnceMode && (
                <motion.div initial={{ opacity: 0, height: 0 }} animate={{ opacity: 1, height: "auto" }} exit={{ opacity: 0, height: 0 }} transition={{ duration: 0.15 }} className="overflow-hidden mb-2">
                  <div className="flex items-center justify-between px-3.5 py-2 rounded-2xl bg-amber-500/[0.08] border border-amber-500/20">
                    <div className="flex items-center gap-2 text-[11px] font-bold text-amber-400">
                      <span className="w-6 h-6 rounded-lg flex items-center justify-center bg-amber-500/15">
                        <Eye size={12} />
                      </span>
                      <span>Visualização única</span>
                    </div>
                    <button onClick={() => setViewOnceMode(false)} className="w-6 h-6 rounded-lg flex items-center justify-center bg-amber-500/10 text-amber-400/70 hover:text-amber-400 hover:bg-amber-500/20 transition-colors active:scale-90">
                      <X size={11} />
                    </button>
                  </div>
                </motion.div>
              )}
            </AnimatePresence>

            {/* Sticker picker */}
            <AnimatePresence>
              {showStickers && (
                <StickerPicker
                  onSelect={(s) => { setShowStickers(false); send({ type: "sticker", sticker_id: s.id, media_url: s.image_url, content: null }); }}
                  onClose={() => setShowStickers(false)}
                />
              )}
            </AnimatePresence>

            {/* Composer row */}
              <div className="flex items-end gap-1.5 sm:gap-2">

              {/* Left: stickers + attach */}
              <div className="flex items-center gap-0.5 shrink-0 pb-[5px]">
                <button onClick={openStickers}
                  className={cn("flex items-center justify-center w-[38px] h-[38px] sm:w-10 sm:h-10 rounded-full transition-all active:scale-90",
                    showStickers ? "bg-orange-500/20 text-orange-400" : "text-muted-foreground hover:text-foreground hover:bg-white/[0.06]"
                  )}>
                  <Smile size={20} />
                </button>
                <button ref={attachButtonRef} onClick={() => setShowAttachMenu((v) => !v)}
                  className={cn("flex items-center justify-center w-[38px] h-[38px] sm:w-10 sm:h-10 rounded-full transition-all active:scale-90",
                    showAttachMenu ? "bg-primary/15 text-primary" : "text-muted-foreground hover:text-foreground hover:bg-white/[0.06]"
                  )}>
                  <Plus size={20} />
                </button>
                <AttachmentMenuPortal isOpen={showAttachMenu} onClose={() => setShowAttachMenu(false)} onCamera={() => setCameraOpen(true)} onGallery={() => fileInputRef.current?.click()} onVideo={() => fileInputRef.current?.click()} onViewOnce={() => { setViewOnceMode(true); fileInputRef.current?.click(); }} triggerRef={attachButtonRef} />
              </div>

              {/* Text input */}
              <div className={cn(
                "flex-1 relative flex items-end rounded-2xl overflow-hidden min-h-[44px] sm:min-h-[48px] border border-white/[0.06] bg-white/[0.04] transition-all duration-200",
                inputFocused ? "border-primary/30" : "",
              )}>
                <AnimatePresence>
                  {inputFocused && (
                    <motion.div
                      initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}
                      transition={{ duration: 0.2 }}
                      className="absolute inset-[-2px] rounded-[24px] pointer-events-none"
                      style={{ boxShadow: "0 0 0 2px rgba(59,130,246,0.15)" }}
                    />
                  )}
                </AnimatePresence>
                <textarea
                  rows={1}
                  value={text}
                  translate="no" autoCorrect="off" autoComplete="off" autoCapitalize="sentences" spellCheck={false}
                  data-gramm="false" data-gramm_editor="false" data-enable-grammarly="false"
                  placeholder="Mensagem..."
                  className="flex-1 resize-none bg-transparent border-none outline-none text-[15px] sm:text-[14px] leading-[1.45] w-full px-4 py-[11px] text-primary placeholder-muted-foreground/40"
                  style={{ maxHeight: 120, scrollbarWidth: "none", fontFamily: "inherit" }}
                  onFocus={() => setInputFocused(true)}
                  onBlur={() => setInputFocused(false)}
                  onChange={(e) => {
                    setText(e.target.value);
                    sendTyping();
                    e.target.style.height = "auto";
                    e.target.style.height = `${Math.min(e.target.scrollHeight, 120)}px`;
                  }}
                  onKeyDown={(e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); send(); } }}
                />
              </div>

              {/* Right: send / stop / mic */}
              <div className="shrink-0 pb-[5px]">
                <AnimatePresence mode="wait">
                  {text.trim() ? (
                    <motion.button key="send"
                      initial={{ scale: 0.5, opacity: 0 }} animate={{ scale: 1, opacity: 1 }} exit={{ scale: 0.5, opacity: 0 }}
                      transition={{ duration: 0.12, ease: [0.22, 1, 0.36, 1] }}
                      onClick={() => send()}
                      className="flex items-center justify-center w-[38px] h-[38px] sm:w-[42px] sm:h-[42px] rounded-full bg-primary text-white shadow-lg shadow-primary/25 hover:shadow-primary/40 transition-all active:scale-90">
                      <Send size={15} className="ml-0.5" />
                    </motion.button>
                  ) : recording ? (
                    <motion.button key="stop"
                      initial={{ scale: 0.5, opacity: 0 }} animate={{ scale: 1, opacity: 1 }} exit={{ scale: 0.5, opacity: 0 }}
                      onClick={stopRecording}
                      className="flex items-center justify-center w-[38px] h-[38px] sm:w-[42px] sm:h-[42px] rounded-full relative overflow-hidden bg-red-500 text-white shadow-lg shadow-red-500/30 active:scale-90">
                      <span className="absolute inset-0 rounded-full animate-ping bg-red-400/30" />
                      <StopCircle size={16} className="relative" />
                    </motion.button>
                  ) : (
                    <motion.button key="mic"
                      initial={{ scale: 0.5, opacity: 0 }} animate={{ scale: 1, opacity: 1 }} exit={{ scale: 0.5, opacity: 0 }}
                      onClick={startRecording}
                      className="w-[38px] h-[38px] sm:w-10 sm:h-10 rounded-full flex items-center justify-center text-muted-foreground hover:text-foreground hover:bg-white/[0.06] transition-all active:scale-90">
                      <Mic size={18} />
                    </motion.button>
                  )}
                </AnimatePresence>
              </div>
            </div>
          </div>

        </div>
      </div>

      {/* ══ ACTION SHEET (modern bottom sheet) ══ */}
      <AnimatePresence>
        {actionFor && (
          <>
            <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}
              onClick={() => setActionFor(null)}
              className="fixed inset-0 z-[14000] bg-black/70 backdrop-blur-sm"
            />
            <motion.div
              initial={{ y: "100%", opacity: 0 }} animate={{ y: 0, opacity: 1 }} exit={{ y: "100%", opacity: 0 }}
              transition={{ type: "spring", damping: 32, stiffness: 450 }}
              className="fixed bottom-0 left-0 right-0 z-[14001] mx-auto rounded-t-[32px] p-5 pt-4 bg-surface-1 border border-border-soft border-b-0 pb-[max(20px,env(safe-area-inset-bottom,20px))]"
              style={{ maxWidth: 480 }}
            >
              <div className="w-10 h-[3px] rounded-full mx-auto mb-3 bg-white/[0.08]" />

              {/* Message preview */}
              <div className="mb-4 px-3.5 py-2.5 rounded-2xl bg-white/[0.03] border-l-[3px] border-primary/40">
                <p className="text-[10px] font-semibold text-muted-foreground/70 mb-0.5">
                  {actionFor.sender_id === user?.id ? "Você" : other?.display_name || "Usuário"}
                </p>
                <p className="text-[13px] text-bright truncate font-medium leading-snug">
                  {actionFor.type === "text" ? actionFor.content
                    : actionFor.type === "image" ? "📷 Foto"
                    : actionFor.type === "video" ? "🎬 Vídeo"
                    : actionFor.type === "audio" ? "🎤 Áudio"
                    : actionFor.type === "sticker" ? "💫 Sticker" : "📎 Mensagem"}
                </p>
              </div>

              {/* Reactions */}
              <div className="mb-3">
                <p className="text-[9px] font-bold text-muted-foreground/50 uppercase tracking-[0.2em] mb-2 px-1">Reagir</p>
                <ReactionPicker messageId={actionFor.id} onClose={() => setActionFor(null)} onReacted={() => { reloadReactions(); setActionFor(null); }} />
              </div>

              <div className="h-px mb-3 bg-white/[0.04]" />

              {/* Action buttons - horizontal scrollable row with good tap targets */}
              <div className="flex gap-2 overflow-x-auto pb-1 scrollbar-hide -mx-1 px-1 mb-3">
                {[
                  { icon: CornerUpLeft, label: "Responder", colorClass: "text-blue-400", bgClass: "bg-blue-400/15", fn: () => handleReplyMessage(actionFor) },
                  ...(actionFor.type === "text" && actionFor.content ? [{ icon: Copy, label: "Copiar", colorClass: "text-emerald-400", bgClass: "bg-emerald-400/15", fn: () => { navigator.clipboard.writeText(actionFor.content || ""); toast.success("Copiado!"); setActionFor(null); } }] : []),
                  ...(canEdit(actionFor) ? [{ icon: Pencil, label: "Editar", colorClass: "text-primary", bgClass: "bg-primary/15", fn: () => startEdit(actionFor) }] : []),
                  { icon: Trash2, label: "Excluir", colorClass: "text-red-400", bgClass: "bg-red-400/15", fn: () => deleteMsg(actionFor) },
                ].map(({ icon: Icon, label, colorClass, bgClass, fn }) => (
                  <button key={label} onClick={fn}
                    className="flex flex-col items-center gap-1.5 py-2.5 px-3.5 min-w-[68px] rounded-2xl transition-all hover:bg-white/[0.04] active:scale-90 shrink-0">
                    <span className={cn("w-11 h-11 rounded-2xl flex items-center justify-center", bgClass)}>
                      <Icon size={18} className={colorClass} />
                    </span>
                    <span className={cn("text-[11px] font-semibold whitespace-nowrap", colorClass)}>{label}</span>
                  </button>
                ))}
              </div>

              <button onClick={() => setActionFor(null)}
                className="w-full py-3 rounded-2xl text-[13px] font-semibold text-muted-foreground/60 bg-white/[0.03] hover:bg-white/[0.06] hover:text-foreground transition-all active:scale-[0.98]">
                Cancelar
              </button>
            </motion.div>
          </>
        )}
      </AnimatePresence>

      {/* ══ NICKNAME DIALOG ══ */}
      <AnimatePresence>
        {showNicknameInput && (
          <>
            <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}
              onClick={() => setShowNicknameInput(false)}
              className="fixed inset-0 z-[16000] bg-black/70 backdrop-blur-md"
            />
            <motion.div
              initial={{ y: "100%", opacity: 0 }} animate={{ y: 0, opacity: 1 }} exit={{ y: "100%", opacity: 0 }}
              transition={{ type: "spring", damping: 30, stiffness: 350 }}
              className="fixed bottom-0 left-0 right-0 z-[16001] mx-auto rounded-t-[32px] p-5 pt-4 bg-surface-1 border border-border-soft border-b-0 pb-[max(20px,env(safe-area-inset-bottom,20px))]"
              style={{ maxWidth: 480 }}
            >
              <div className="w-10 h-[3px] rounded-full mx-auto mb-5 bg-white/[0.08]" />
              <div className="flex items-center gap-3 mb-5">
                <div className="w-10 h-10 rounded-2xl flex items-center justify-center bg-primary/10 shrink-0">
                  <Tag size={16} className="text-primary" />
                </div>
                <div>
                  <p className="text-[14px] font-bold text-bright">{otherNickname ? `Apelido: "${otherNickname}"` : "Adicionar apelido"}</p>
                  <p className="text-[11px] text-muted-foreground/60">Só você vê esse apelido</p>
                </div>
              </div>
              <div className="flex gap-2.5">
                <input
                  value={nicknameInputVal}
                  onChange={e => setNicknameInputVal(e.target.value.slice(0, 40))}
                  placeholder={`Apelido para ${other?.display_name || "este usuário"}…`}
                  autoFocus
                  onKeyDown={e => {
                    if (e.key === "Enter" && nicknameInputVal.trim()) { setNicknameForUser(nicknameInputVal.trim() || null); setShowNicknameInput(false); toast.success("Apelido salvo"); }
                    if (e.key === "Escape") setShowNicknameInput(false);
                  }}
                  className="flex-1 py-3 px-4 rounded-xl text-[13px] outline-none bg-white/[0.05] border border-white/[0.08] text-primary placeholder-muted-foreground/40"
                />
                <button
                  onClick={() => { setNicknameForUser(nicknameInputVal.trim() || null); setShowNicknameInput(false); toast.success("Apelido salvo"); }}
                  disabled={!nicknameInputVal.trim()}
                  className={cn("py-2.5 px-5 rounded-xl text-xs font-bold transition-all active:scale-95",
                    nicknameInputVal.trim()
                      ? "bg-gradient-to-br from-[#FFD700] to-[#FFAA00] text-[#0a0a0a]"
                      : "bg-white/[0.04] text-white/20 cursor-default"
                  )}
                >
                  Salvar
                </button>
              </div>
              {otherNickname && (
                <button onClick={() => { setNicknameForUser(null); setShowNicknameInput(false); toast.success("Apelido removido"); }}
                  className="mt-3 w-full py-3 rounded-2xl text-[12px] font-semibold text-red-400 bg-red-400/8 border border-red-400/15 hover:bg-red-400/15 transition-all active:scale-[0.98]">
                  Remover apelido
                </button>
              )}
              <button onClick={() => setShowNicknameInput(false)}
                className="mt-2 w-full py-3 rounded-2xl text-[13px] font-semibold text-muted-foreground/70 bg-white/[0.03] hover:bg-white/[0.06] hover:text-foreground transition-all active:scale-[0.98]">
                Cancelar
              </button>
            </motion.div>
          </>
        )}
      </AnimatePresence>

      {/* ══ WALLPAPER PICKER ══ */}
      <AnimatePresence>
        {showBgPicker && (
          <>
            <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}
              onClick={() => setShowBgPicker(false)}
              className="fixed inset-0 z-[15000] bg-black/60 backdrop-blur-md"
            />
            <motion.div
              initial={{ y: "100%", opacity: 0 }} animate={{ y: 0, opacity: 1 }} exit={{ y: "100%", opacity: 0 }}
              transition={{ type: "spring", damping: 30, stiffness: 350 }}
              className="fixed bottom-0 left-0 right-0 z-[15001] mx-auto rounded-t-[32px] p-5 pt-4 bg-surface-1 border border-border-soft border-b-0 pb-[max(20px,env(safe-area-inset-bottom,20px))]"
              style={{ maxWidth: 480 }}
            >
              <div className="w-10 h-[3px] rounded-full mx-auto mb-4 bg-white/[0.08]" />
              <div className="flex items-center gap-2.5 mb-5">
                <div className="w-9 h-9 rounded-xl flex items-center justify-center bg-white/[0.05]">
                  <svg className="w-[15px] h-[15px] text-primary" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21 15 16 10 5 21"/></svg>
                </div>
                <p className="text-[14px] font-bold text-bright">Plano de fundo</p>
              </div>

              <div className="mb-4">
                <input type="file" accept="image/*"
                  onChange={(e) => {
                    const file = e.target.files?.[0];
                    if (file) { const reader = new FileReader(); reader.onload = (ev) => setWallpaper(null, ev.target?.result as string); reader.readAsDataURL(file); }
                  }}
                  className="hidden" id="wallpaper-upload"
                />
                <label htmlFor="wallpaper-upload" className="flex items-center justify-center gap-2 w-full py-3 rounded-xl cursor-pointer border border-dashed border-primary/25 bg-primary/[0.04] hover:bg-primary/[0.08] transition-all active:scale-[0.98]">
                  <ImagePlus size={15} className="text-primary" />
                  <span className="text-[12px] font-medium text-primary">Usar minha própria imagem</span>
                </label>
              </div>

              <div className="mb-4">
                <p className="text-[9px] font-bold text-muted-foreground/50 uppercase tracking-[0.2em] mb-2.5">Paleta</p>
                <div className="flex flex-wrap gap-2">
                  {[
                    "linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
                    "linear-gradient(135deg, #f093fb 0%, #f5576c 100%)",
                    "linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)",
                    "linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)",
                    "linear-gradient(135deg, #fa709a 0%, #fee140 100%)",
                    "linear-gradient(135deg, #1e3c72 0%, #2a5298 100%)",
                    "linear-gradient(135deg, #cc2b5e 0%, #753a88 100%)",
                    "linear-gradient(135deg, #de6262 0%, #ffb88c 100%)",
                    "#000000", "#1a1a2e", "#16213e", "#0f3460",
                  ].map((grad, i) => (
                    <button key={i}
                      onClick={() => { setBgGradient(grad); setBgImage(null); setBgBubbleColor("rgba(255,255,255,0.08)"); setBgBubbleMineColor("rgba(250,204,21,0.9)"); setBgTextColor("#ffffff"); if (id && user) supabase.from("conversation_backgrounds").upsert({ conversation_id: id, background_id: null, custom_gradient: grad, set_by: user.id }, { onConflict: "conversation_id" }); setShowBgPicker(false); }}
                      className="w-[42px] h-[42px] rounded-xl border border-white/10 hover:border-primary hover:scale-105 transition-all active:scale-95"
                      style={{ background: grad }}
                    />
                  ))}
                </div>
              </div>

              {availableBgs.length > 0 && (
                <div>
                  <p className="text-[9px] font-bold text-muted-foreground/50 uppercase tracking-[0.2em] mb-2.5">Fundos do App</p>
                  <div className="max-h-[180px] overflow-y-auto scrollbar-hide">
                    <div className="flex flex-wrap gap-2">
                      <button onClick={removeWallpaper}
                        className="w-[60px] h-[60px] rounded-xl flex items-center justify-center cursor-pointer transition-all active:scale-95 bg-white/[0.03] border-[1.5px] border-dashed border-white/[0.09] text-white/25 hover:text-muted-foreground hover:border-white/[0.15]">
                        <X size={14} />
                      </button>
                      {availableBgs.map((bg: any) => (
                        <button key={bg.id} onClick={() => setWallpaper(bg.id)}
                          className="relative w-[60px] h-[60px] rounded-xl overflow-hidden cursor-pointer transition-all hover:scale-105 active:scale-95 shadow-lg shadow-black/30"
                          style={{
                            ...(bg.image_url ? { backgroundImage: `url(${bg.image_url})`, backgroundSize: "cover", backgroundPosition: "center" } : {}),
                            ...(bg.gradient_css ? { background: bg.gradient_css } : {}),
                          }}>
                          <span className="absolute inset-x-0 bottom-0 py-0.5 text-[7px] text-white text-center font-semibold truncate px-1"
                            style={{ background: "linear-gradient(transparent, rgba(0,0,0,0.55))" }}>
                            {bg.name}
                          </span>
                        </button>
                      ))}
                    </div>
                  </div>
                </div>
              )}
            </motion.div>
          </>
        )}
      </AnimatePresence>

      <CameraCapture open={cameraOpen} onClose={() => setCameraOpen(false)} onCapture={(file) => {
        file.type.startsWith("video/") ? sendVideo(file) : sendImage(file, viewOnceMode);
      }} />

      <ChatMediaViewer src={mediaViewer?.src || null} type={mediaViewer?.type || "image"} onClose={() => setMediaViewer(null)} />
    </div>
  );
}
