"use client"

import { useState, useRef, useCallback, useEffect, useMemo } from "react"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar"
import { ScrollArea } from "@/components/ui/scroll-area"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import {
  Search, Send, Phone, MoreHorizontal, Paperclip,
  Smile, Flag, Ban, Trash2, Image, FileIcon, X, Mic, Square, Play, Pause, Check, CheckCheck,
  CornerDownRight, Forward, Pencil, Download, Undo2, CalendarDays, Loader2, FolderOpen, Mail,
} from "lucide-react"
import { hasBlockedCodeExtension, filterBlockedFiles } from "@/lib/blocked-extensions"
import {
  Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription,
  DialogFooter, DialogClose,
} from "@/components/ui/dialog"
import { Label } from "@/components/ui/label"
import { Textarea } from "@/components/ui/textarea"
import {
  Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
} from "@/components/ui/select"
import { useTheme } from "next-themes"
import { useUser } from "@/providers/user-provider"
import { toast } from "sonner"
import { io, Socket } from "socket.io-client"
import VoiceCallModal from "@/components/chats/voice-call-modal"
import MediaPicker from "@/components/chats/media-picker"

const activeAudioRef: { current: HTMLAudioElement | null } = { current: null }
const previewAudioRef: { current: HTMLAudioElement | null } = { current: null }
const previewAnimRef: { current: number } = { current: 0 }

function VoiceMessagePlayer({ src, initialDuration, isOwn }: { src: string; initialDuration: number; isOwn?: boolean }) {
  const [playing, setPlaying] = useState(false)
  const [current, setCurrent] = useState(0)
  const [duration, setDuration] = useState(initialDuration)
  const audioRef = useRef<HTMLAudioElement>(null)
  const animRef = useRef<number>(0)
  const progRef = useRef<HTMLInputElement>(null)

  useEffect(() => {
    const audio = audioRef.current
    if (!audio) return
    const onLoaded = () => { if (isFinite(audio.duration)) setDuration(audio.duration) }
    const onEnded = () => { setPlaying(false); setCurrent(0) }
    audio.addEventListener("loadedmetadata", onLoaded)
    audio.addEventListener("ended", onEnded)
    return () => { audio.removeEventListener("loadedmetadata", onLoaded); audio.removeEventListener("ended", onEnded) }
  }, [src])

  useEffect(() => {
    if (!playing) { cancelAnimationFrame(animRef.current); return }
    const tick = () => { if (audioRef.current) setCurrent(audioRef.current.currentTime); animRef.current = requestAnimationFrame(tick) }
    animRef.current = requestAnimationFrame(tick)
    return () => cancelAnimationFrame(animRef.current)
  }, [playing])

  const toggle = () => {
    if (!audioRef.current) return
    if (playing) { audioRef.current.pause(); setPlaying(false) }
    else {
      if (activeAudioRef.current && activeAudioRef.current !== audioRef.current) { activeAudioRef.current.pause() }
      activeAudioRef.current = audioRef.current
      audioRef.current.play(); setPlaying(true)
    }
  }

  const seek = (e: React.ChangeEvent<HTMLInputElement>) => {
    const val = parseFloat(e.target.value)
    if (audioRef.current) { audioRef.current.currentTime = val; setCurrent(val) }
  }

  const replay = () => {
    if (!audioRef.current) return
    audioRef.current.currentTime = 0; setCurrent(0)
    if (!playing) { audioRef.current.play(); setPlaying(true) }
  }

  const displayDuration = isFinite(duration) && duration > 0 ? duration : initialDuration
  const pct = displayDuration > 0 ? (current / displayDuration) * 100 : 0
  const fmt = (s: number) => { const secs = isFinite(s) ? Math.max(0, Math.floor(s)) : 0; return `${Math.floor(secs / 60)}:${(secs % 60).toString().padStart(2, "0")}` }

  const barCount = 28
  const waveform = Array.from({ length: barCount }, (_, i) => {
    const peak = 0.15 + Math.sin(i * 1.1) * 0.35 + Math.sin(i * 2.3) * 0.2 + Math.sin(i * 0.7) * 0.3
    return Math.max(0.15, Math.min(1, peak))
  })

  return (
    <div className="flex items-center gap-2 min-w-[200px] select-none">
      <audio ref={audioRef} src={src} preload="metadata" />
      <button type="button" onClick={toggle} className="h-8 w-8 shrink-0 rounded-full flex items-center justify-center hover:bg-black/10 transition-colors">
        {playing ? <Pause className="h-4 w-4 fill-current" /> : <Play className="h-4 w-4 ml-0.5 fill-current" />}
      </button>
      <div className="flex-1 flex flex-col gap-0.5 min-w-0">
        <div className="flex items-center gap-1 h-8">
          {waveform.map((h, i) => {
            const filled = (i / barCount) <= (pct / 100)
            return <div key={i} className="flex-1 rounded-full transition-colors duration-75" style={{ height: `${h * 100}%`, minHeight: 3, background: filled ? "currentColor" : "currentColor", opacity: filled ? 1 : 0.35 }} />
          })}
        </div>
        <input type="range" ref={progRef} min={0} max={displayDuration || 1} step={0.1} value={Math.min(current, displayDuration)} onChange={seek} className="w-full h-1 cursor-pointer appearance-none bg-transparent [&::-webkit-slider-runnable-track]:h-1 [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:bg-white/20 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:h-3 [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-white [&::-webkit-slider-thumb]:border-0" />
      </div>
      <div className="flex flex-col items-end gap-0.5 shrink-0">
        <span className="text-[11px] tabular-nums opacity-70">{fmt(current)}</span>
        <button type="button" onClick={replay} className="opacity-50 hover:opacity-100 transition-opacity">
          <Undo2 className="h-2.5 w-2.5" />
        </button>
      </div>
    </div>
  )
}

const MAX_CACHED_CONVERSATIONS = 5
const otherParticipant = (conv: any) => conv.otherUser

export default function ChatsPage() {
  const { theme } = useTheme()
  const { user } = useUser()
  const [activeChat, setActiveChat] = useState<string | null>(null)
  const [messageInput, setMessageInput] = useState("")
  const [showEmojiPicker, setShowEmojiPicker] = useState(false)
  const [showAttachMenu, setShowAttachMenu] = useState(false)
  const [attachments, setAttachments] = useState<File[]>([])
  const [panelWidth, setPanelWidth] = useState(320)
  const [isResizing, setIsResizing] = useState(false)
  const [reportDialogOpen, setReportDialogOpen] = useState(false)
  const [reportReason, setReportReason] = useState("")
  const [forwardDialogOpen, setForwardDialogOpen] = useState(false)
  const [forwardMessage, setForwardMessage] = useState<any>(null)
  const [forwardSearch, setForwardSearch] = useState("")
  const [searchQuery, setSearchQuery] = useState("")
  const [isRecording, setIsRecording] = useState(false)
  const [isPaused, setIsPaused] = useState(false)
  const [recordingDuration, setRecordingDuration] = useState(0)
  const recordingDurationRef = useRef(0)
  const [previewBlob, setPreviewBlob] = useState<Blob | null>(null)
  const [previewUrl, setPreviewUrl] = useState<string | null>(null)
  const [previewDuration, setPreviewDuration] = useState(0)
  const [isPreviewPlaying, setIsPreviewPlaying] = useState(false)
  const [previewCurrent, setPreviewCurrent] = useState(0)
  const [voiceMessages, setVoiceMessages] = useState<Map<string, { url: string; duration: number }>>(new Map())
  const [messageAttachments, setMessageAttachments] = useState<Map<string, { name: string; type: string; url: string }[]>>(new Map())
  const [replyingTo, setReplyingTo] = useState<any>(null)
  const [editingMessage, setEditingMessage] = useState<any>(null)
  const [replyMap, setReplyMap] = useState<Map<string, { repliedToSender: string; repliedToContent: string }>>(new Map())
  // message status tracking removed — now using msg.read from API
  const [conversations, setConversations] = useState<any[]>([])
  const [conversationMessages, setConversationMessages] = useState<Map<string, any[]>>(new Map())
  const [loadingChats, setLoadingChats] = useState(true)
  const [searchResults, setSearchResults] = useState<any[]>([])
  const [searchingUsers, setSearchingUsers] = useState(false)
  const [unreadMap, setUnreadMap] = useState<Map<string, number>>(new Map())
  const [previewAvatarUrl, setPreviewAvatarUrl] = useState<string | null>(null)
  const [previewImageUrl, setPreviewImageUrl] = useState<string | null>(null)
  const [scheduleDialogOpen, setScheduleDialogOpen] = useState(false)
  const [scheduleTitle, setScheduleTitle] = useState("")
  const [scheduleDate, setScheduleDate] = useState("")
  const [scheduleTime, setScheduleTime] = useState("")
  const [scheduleDuration, setScheduleDuration] = useState("30")
  const [scheduleType, setScheduleType] = useState<string>("meeting")
  const [scheduleSaving, setScheduleSaving] = useState(false)
  const fileInputRef = useRef<HTMLInputElement>(null)
  const textareaRef = useRef<HTMLTextAreaElement>(null)
  const emojiPickerRef = useRef<HTMLDivElement>(null)
  const isSendingRef = useRef(false)
  const attachMenuRef = useRef<HTMLDivElement>(null)
  const messagesEndRef = useRef<HTMLDivElement>(null)
  const mediaRecorderRef = useRef<MediaRecorder | null>(null)
  const recordingChunksRef = useRef<Blob[]>([])
  const resizeStartRef = useRef({ x: 0, width: 0 })
  const blobUrlsRef = useRef<string[]>([])
  const conversationOrderRef = useRef<string[]>([])
  const pollTimerRef = useRef<ReturnType<typeof setInterval> | null>(null)
  const [isCallModalOpen, setIsCallModalOpen] = useState(false)
  const socketRef = useRef<Socket | null>(null)
  const isDeletingRef = useRef(false)

  const isOnlyEmoji = (text: string) => /^(\p{Extended_Pictographic}\s*)+$/u.test(text.trim())

const formatPreviewContent = (content: string) => {
  if (!content?.startsWith("{")) return content
  try {
    const p = JSON.parse(content)
    if (p.gif) return "📷 GIF"
    if (p.v) return "🎤 Voice message"
    if (p.sticker) return "💮 Sticker"
  } catch {}
  return content
}

  const autoResizeTextarea = useCallback(() => {
    const ta = textareaRef.current
    if (!ta) return
    ta.style.height = "auto"
    ta.style.height = `${ta.scrollHeight}px`
  }, [])

  if (!user) return null

  const messages = useMemo(() => conversationMessages.get(activeChat || "") || [], [conversationMessages, activeChat])
  const conversation = useMemo(() => conversations.find((c) => c.id === activeChat), [conversations, activeChat])
  const filteredConversations = useMemo(() => {
    if (!searchQuery.trim()) return conversations
    return conversations.filter((conv) => otherParticipant(conv).name.toLowerCase().includes(searchQuery.toLowerCase()))
  }, [conversations, searchQuery])

  // Fetch conversations from API
  useEffect(() => {
    const fetchConvs = async () => {
      try {
        const res = await fetch("/api/conversations")
        if (res.ok) {
          const data = await res.json()
          const convs = data.conversations || []
          setConversations(convs)
          setUnreadMap(new Map(convs.map((c: any) => [c.id, c.unread])))
          if (convs.length > 0) setActiveChat(convs[0].id)
        }
      } catch {
        console.warn("Failed to fetch conversations in chats page")
      } finally {
        setLoadingChats(false)
      }
    }
    fetchConvs()
  }, [])

  // Fetch messages when active chat changes, and mark as read
  useEffect(() => {
    if (!activeChat) return
    conversationOrderRef.current = [
      activeChat,
      ...conversationOrderRef.current.filter((id) => id !== activeChat),
    ]
    const fetchMsgs = async () => {
      try {
        const res = await fetch(`/api/conversations/${activeChat}/messages`)
        if (res.ok) {
          const data = await res.json()
          setConversationMessages((prev) => {
            const next = new Map(prev)
            next.set(activeChat, data.messages || [])
            const recent = conversationOrderRef.current.slice(0, MAX_CACHED_CONVERSATIONS)
            const recentSet = new Set(recent)
            for (const key of next.keys()) {
              if (!recentSet.has(key)) next.delete(key)
            }
            const validMsgIds = new Set<string>()
            for (const msgs of next.values()) {
              for (const m of msgs) validMsgIds.add(m.id)
            }
            setVoiceMessages((v) => {
              const n = new Map(v)
              for (const k of n.keys()) if (!validMsgIds.has(k)) n.delete(k)
              return n
            })
            setMessageAttachments((a) => {
              const n = new Map(a)
              for (const k of n.keys()) if (!validMsgIds.has(k)) n.delete(k)
              // Restore persisted file attachments from JSON content
              for (const msgs of next.values()) {
                for (const m of msgs) {
                  try {
                    const parsed = JSON.parse(m.content)
                    if (parsed.fileAttachments && Array.isArray(parsed.fileAttachments)) {
                      n.set(m.id, parsed.fileAttachments)
                    }
                  } catch {}
                }
              }
              return n
            })
            setReplyMap((r) => {
              const n = new Map(r)
              for (const k of n.keys()) if (!validMsgIds.has(k)) n.delete(k)
              return n
            })
            return next
          })
        }
      } catch {
        // ignore
      }
      // Mark conversation as read
      fetch(`/api/conversations/${activeChat}/read`, { method: "POST" }).catch(() => {})
      setUnreadMap((prev) => { const m = new Map(prev); m.set(activeChat, 0); return m })
    }
    fetchMsgs()
  }, [activeChat])

  // Search users when search query changes
  useEffect(() => {
    const q = searchQuery.trim()
    if (!q) { setSearchResults([]); return }
    const timer = setTimeout(async () => {
      setSearchingUsers(true)
      try {
        const res = await fetch(`/api/users/search?q=${encodeURIComponent(q)}`)
        if (res.ok) {
          const data = await res.json()
          const existingIds = new Set(conversations.map((c) => otherParticipant(c).id))
          setSearchResults(data.users.filter((u: any) => !existingIds.has(u.id)))
        }
      } catch { console.warn("Failed to search users in chats page") }
      setSearchingUsers(false)
    }, 300)
    return () => clearTimeout(timer)
  }, [searchQuery, conversations])

  useEffect(() => {
    const handleClickOutside = (e: MouseEvent) => {
      if (emojiPickerRef.current && !emojiPickerRef.current.contains(e.target as Node)) {
        setShowEmojiPicker(false)
      }
    }
    document.addEventListener("mousedown", handleClickOutside)
    return () => document.removeEventListener("mousedown", handleClickOutside)
  }, [])

  // Strip blocked files from attachments on every change
  useEffect(() => {
    if (attachments.length === 0) return
    const { allowed, rejected } = filterBlockedFiles(attachments)
    if (rejected.length > 0) {
      toast.error(`Blocked file type: ${rejected[0].name}`)
      setAttachments(allowed)
    }
  }, [attachments])

  useEffect(() => {
    const handleClickOutside = (e: MouseEvent) => {
      if (attachMenuRef.current && !attachMenuRef.current.contains(e.target as Node)) {
        setShowAttachMenu(false)
      }
    }
    document.addEventListener("mousedown", handleClickOutside)
    return () => document.removeEventListener("mousedown", handleClickOutside)
  }, [])

  // revoke blob URLs on unmount
  useEffect(() => {
    return () => {
      blobUrlsRef.current.forEach((url) => URL.revokeObjectURL(url))
      blobUrlsRef.current = []
    }
  }, [])

  // Poll for new messages every 4 seconds for real-time sync
  useEffect(() => {
    if (!activeChat) return
    pollTimerRef.current = setInterval(async () => {
      try {
        const res = await fetch(`/api/conversations/${activeChat}/messages?limit=50`)
        if (!res.ok) return
        const data = await res.json()
        const serverMsgs = data.messages || []
        setConversationMessages((prev) => {
          const existing = prev.get(activeChat) || []
          if (serverMsgs.length === existing.length) return prev
          const next = new Map(prev)
          next.set(activeChat, serverMsgs)
          return next
        })
        setConversations((prev) => {
          const updated = [...prev]
          const convIdx = updated.findIndex((c) => c.id === activeChat)
          if (convIdx >= 0 && serverMsgs.length > 0) {
            const last = serverMsgs[serverMsgs.length - 1]
            updated[convIdx] = { ...updated[convIdx], lastMessage: last.content, lastMessageTime: last.timestamp }
          }
          return updated
        })
      } catch { /* polling silently */ }
    }, 4000)
    return () => { if (pollTimerRef.current) clearInterval(pollTimerRef.current) }
  }, [activeChat])

  // Connect to signaling server for real-time message deletion events
  useEffect(() => {
    let socket: Socket | null = null
    let cancelled = false
    ;(async () => {
      try {
        const res = await fetch("/api/auth/jwt")
        if (!res.ok) return
        const { token } = await res.json()
        if (cancelled) return
        socket = io(process.env.NEXT_PUBLIC_SIGNALING_URL || "http://localhost:3007", {
          auth: { token },
          transports: ["websocket", "polling"],
        })
        socketRef.current = socket
        socket.on("message:deleted", ({ conversationId, messageId }: { conversationId: string; messageId: string }) => {
          setConversationMessages((prev) => {
            const existing = prev.get(conversationId)
            if (!existing) return prev
            const next = new Map(prev)
            next.set(conversationId, existing.filter((m) => m.id !== messageId))
            return next
          })
        })
      } catch { /* socket connection failed silently */ }
    })()
    return () => { cancelled = true; socket?.disconnect(); socketRef.current = null }
  }, [])

  const handleResizeStart = useCallback((e: React.MouseEvent) => {
    e.preventDefault()
    setIsResizing(true)
    resizeStartRef.current = { x: e.clientX, width: panelWidth }
  }, [panelWidth])

  useEffect(() => {
    if (!isResizing) return
    const handleMouseMove = (e: MouseEvent) => {
      const delta = e.clientX - resizeStartRef.current.x
      const newWidth = Math.max(240, Math.min(560, resizeStartRef.current.width + delta))
      setPanelWidth(newWidth)
    }
    const handleMouseUp = () => setIsResizing(false)
    document.addEventListener("mousemove", handleMouseMove)
    document.addEventListener("mouseup", handleMouseUp)
    return () => {
      document.removeEventListener("mousemove", handleMouseMove)
      document.removeEventListener("mouseup", handleMouseUp)
    }
  }, [isResizing])

  useEffect(() => {
    messagesEndRef.current?.scrollIntoView({ behavior: "smooth" })
  }, [conversations])

  const handleEmojiSelect = (emoji: string) => {
    setMessageInput((prev) => prev + emoji)
    setShowEmojiPicker(false)
    setTimeout(() => autoResizeTextarea(), 0)
  }

  const handleMediaSelect = (content: string) => {
    addMessageToChat(content)
    setShowEmojiPicker(false)
  }

  const MAX_FILE_SIZE = 10 * 1024 * 1024 // 10MB

  const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
    const raw = Array.from(e.target.files ?? [])
    const oversized = raw.filter((f) => f.size > MAX_FILE_SIZE)
    if (oversized.length > 0) {
      toast.error(`${oversized[0].name} exceeds the 10MB file size limit`)
      if (e.target) e.target.value = ""
      return
    }
    const { allowed, rejected } = filterBlockedFiles(raw)
    if (rejected.length > 0) {
      toast.error(`Blocked file type: ${rejected[0].name}`)
    }
    setAttachments((prev) => [...prev, ...allowed])
    if (e.target) e.target.value = ""
  }

  const removeAttachment = (index: number) => {
    setAttachments((prev) => prev.filter((_, i) => i !== index))
  }

  const addMessageToChat = async (content: string, voice?: { url: string; duration: number }, replyTo?: { senderName: string; content: string }, fileAttachments?: { name: string; type: string; url: string }[]) => {
    if (!activeChat || !user) return
    const payload = voice
      ? "[Voice message]"
      : fileAttachments && fileAttachments.length > 0
        ? JSON.stringify({ text: content, fileAttachments })
        : content
    try {
      const res = await fetch(`/api/conversations/${activeChat}/messages`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ content: payload }),
      })
      if (!res.ok) return
      const data = await res.json()
      const msg = data.message
      setConversationMessages((prev) => {
        const next = new Map(prev)
        const existing = next.get(activeChat) || []
        next.set(activeChat, [...existing, msg])
        return next
      })
      setConversations((prev) => {
        const updated = prev.map((conv) =>
          conv.id === activeChat
            ? { ...conv, lastMessage: getDisplayContent(content), lastMessageTime: "Just now" }
            : conv
        )
        const idx = updated.findIndex((c) => c.id === activeChat)
        if (idx > 0) {
          const [item] = updated.splice(idx, 1)
          updated.unshift(item)
        }
        return updated
      })
      setUnreadMap((prev) => { const m = new Map(prev); m.set(activeChat, 0); return m })
      await fetch(`/api/conversations/${activeChat}/read`, { method: "POST" })
      if (voice) {
        setVoiceMessages((prev) => {
          const next = new Map(prev)
          next.set(msg.id, voice)
          return next
        })
      }
      if (replyTo) {
        setReplyMap((prev) => {
          const next = new Map(prev)
          next.set(msg.id, { repliedToSender: replyTo.senderName, repliedToContent: replyTo.content })
          return next
        })
      }
      if (fileAttachments && fileAttachments.length > 0) {
        setMessageAttachments((prev) => {
          const next = new Map(prev)
          next.set(msg.id, fileAttachments)
          return next
        })
      }
    } catch {
      console.warn("Failed to send message in chats page")
      toast.error("Failed to send message")
    }
  }

  const handleSend = async (e: React.FormEvent) => {
    e.preventDefault()
    if (!messageInput.trim() && attachments.length === 0) return
    if (isSendingRef.current) return
    // Check blocked files before sending
    if (attachments.some((f) => hasBlockedCodeExtension(f.name))) {
      toast.error("Remove blocked file types before sending")
      return
    }
    isSendingRef.current = true
    try {
      if (editingMessage) {
        setConversationMessages((prev) => {
          const next = new Map(prev)
          const msgs = (next.get(activeChat || "") || []).map((m) =>
            m.id === editingMessage.id ? { ...m, content: messageInput.trim() } : m
          )
          next.set(activeChat || "", msgs)
          return next
        })
        setEditingMessage(null)
        setMessageInput("")
        setTimeout(() => autoResizeTextarea(), 0)
        return
      }
      const fileAttachments = attachments.length > 0
        ? await Promise.all(attachments.map(async (f) => {
            const url = await fileToDataURL(f)
            return { name: f.name, type: f.type, url }
          }))
        : undefined
      if (replyingTo) {
        const replySender = replyingTo.senderId === user.id ? user.name : otherParticipant(conversation!).name
        await addMessageToChat(messageInput.trim(), undefined, { senderName: replySender, content: replyingTo.content }, fileAttachments)
        setReplyingTo(null)
      } else {
        await addMessageToChat(messageInput.trim(), undefined, undefined, fileAttachments)
      }
      setMessageInput("")
      setTimeout(() => autoResizeTextarea(), 0)
      setAttachments([])
    } finally {
      isSendingRef.current = false
    }
  }

  const handleDeleteMessage = async (messageId: string) => {
    if (!activeChat || !user) return
    if (isDeletingRef.current) return
    isDeletingRef.current = true

    const prevMessages = conversationMessages.get(activeChat) || []

    try {
      const res = await fetch(`/api/conversations/${activeChat}/messages/${messageId}`, { method: "DELETE" })
      if (!res.ok) {
        const err = await res.json().catch(() => ({}))
        throw new Error(err.error || "Delete failed")
      }

      // Broadcast deletion to other participants via Socket.io
      const socket = socketRef.current
      if (socket?.connected) {
        socket.emit("message:deleted", { conversationId: activeChat, messageId, senderId: user.id })
      }

      // Revoke blob URLs for attachments and voice
      const files = messageAttachments.get(messageId)
      if (files) files.forEach((f) => { URL.revokeObjectURL(f.url); blobUrlsRef.current = blobUrlsRef.current.filter((u) => u !== f.url) })
      const voice = voiceMessages.get(messageId)
      if (voice) { URL.revokeObjectURL(voice.url); blobUrlsRef.current = blobUrlsRef.current.filter((u) => u !== voice.url) }

      // Remove from local state
      setConversationMessages((prev) => {
        const next = new Map(prev)
        const msgs = (next.get(activeChat || "") || []).filter((m) => m.id !== messageId)
        next.set(activeChat || "", msgs)
        return next
      })
      setConversations((prev) =>
        prev.map((conv) =>
          conv.id === activeChat
            ? { ...conv, lastMessage: getDisplayContent(prevMessages.filter((m) => m.id !== messageId).at(-1)?.content ?? "") }
            : conv
        )
      )
      toast.success("Message deleted")
    } catch (err: any) {
      toast.error(err?.message || "Unable to delete voice note. Please try again.")
    } finally {
      isDeletingRef.current = false
    }
  }

  const startRecording = async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
      const mime = MediaRecorder.isTypeSupported("audio/webm;codecs=opus") ? "audio/webm;codecs=opus" : "audio/webm"
      const recorder = new MediaRecorder(stream, { mimeType: mime })
      recordingChunksRef.current = []
      recorder.ondataavailable = (e) => {
        if (e.data.size > 0) recordingChunksRef.current.push(e.data)
      }
      recorder.onstop = () => {
        if (recordingChunksRef.current.length === 0) return
        const blob = new Blob(recordingChunksRef.current, { type: mime })
        const url = URL.createObjectURL(blob)
        blobUrlsRef.current.push(url)
        setPreviewBlob(blob)
        setPreviewUrl(url)
        setPreviewDuration(recordingDurationRef.current)
        stream.getTracks().forEach((t) => t.stop())
        setRecordingDuration(0)
      }
      mediaRecorderRef.current = recorder
      recorder.start()
      setIsRecording(true)
      setIsPaused(false)
    } catch (err: any) {
      if (err?.name === "NotAllowedError" || err?.name === "PermissionDeniedError") {
        toast.error("Microphone access is required to record voice notes.")
      } else {
        toast.error("Failed to start recording. Please check your microphone.")
      }
    }
  }

  const togglePauseRecording = () => {
    const recorder = mediaRecorderRef.current
    if (!recorder || recorder.state === "inactive") return
    if (recorder.state === "recording") {
      recorder.pause()
      setIsPaused(true)
    } else {
      recorder.resume()
      setIsPaused(false)
    }
  }

  const stopRecording = () => {
    mediaRecorderRef.current?.stop()
    setIsRecording(false)
    setIsPaused(false)
  }

  const discardRecording = () => {
    if (mediaRecorderRef.current && mediaRecorderRef.current.state !== "inactive") {
      mediaRecorderRef.current.ondataavailable = null
      mediaRecorderRef.current.onstop = null
      mediaRecorderRef.current.stop()
      mediaRecorderRef.current.stream?.getTracks().forEach((t) => t.stop())
    }
    setIsRecording(false)
    setIsPaused(false)
    setRecordingDuration(0)
    recordingDurationRef.current = 0
    recordingChunksRef.current = []
    clearPreview()
  }

  const clearPreview = () => {
    if (previewUrl) { URL.revokeObjectURL(previewUrl); blobUrlsRef.current = blobUrlsRef.current.filter((u) => u !== previewUrl) }
    setPreviewBlob(null)
    setPreviewUrl(null)
    setPreviewDuration(0)
    setIsPreviewPlaying(false)
    setPreviewCurrent(0)
  }

  const cancelVoicePreview = () => {
    if (previewAudioRef.current) { previewAudioRef.current.pause(); previewAudioRef.current = null! }
    cancelAnimationFrame(previewAnimRef.current)
    clearPreview()
  }

  const togglePreviewPlay = () => {
    if (!previewUrl) return
    if (isPreviewPlaying) {
      previewAudioRef.current?.pause()
      setIsPreviewPlaying(false)
    } else {
      const audio = new Audio(previewUrl)
      audio.onloadedmetadata = () => { if (isFinite(audio.duration)) setPreviewDuration(audio.duration) }
      audio.onended = () => { setIsPreviewPlaying(false); setPreviewCurrent(0) }
      audio.onerror = () => { toast.error("Failed to play preview"); setIsPreviewPlaying(false) }
      previewAudioRef.current = audio
      audio.play().then(() => setIsPreviewPlaying(true)).catch(() => toast.error("Failed to play preview"))
      const tick = () => { if (previewAudioRef.current) setPreviewCurrent(previewAudioRef.current.currentTime); previewAnimRef.current = requestAnimationFrame(tick) }
      cancelAnimationFrame(previewAnimRef.current)
      previewAnimRef.current = requestAnimationFrame(tick)
    }
  }

  const sendVoiceRecording = async () => {
    if (!previewBlob || !previewUrl) return
    try {
      cancelAnimationFrame(previewAnimRef.current)
      previewAudioRef.current?.pause()
      const formData = new FormData()
      const ext = previewBlob.type.includes("webm") ? "webm" : "webm"
      formData.append("audio", previewBlob, `voice.${ext}`)
      formData.append("duration", previewDuration.toString())
      const uploadRes = await fetch("/api/upload/voice", { method: "POST", body: formData })
      if (!uploadRes.ok) { toast.error("Failed to upload voice recording"); return }
      const { url: serverUrl, duration } = await uploadRes.json()
      const voicePayload = JSON.stringify({ v: true, u: serverUrl, d: duration || previewDuration })
      await addMessageToChat(voicePayload, { url: serverUrl, duration: duration || previewDuration })
      clearPreview()
    } catch {
      toast.error("Failed to send voice recording")
    }
  }

  useEffect(() => {
    if (!isRecording) return
    recordingDurationRef.current = 0
    setRecordingDuration(0)
    const interval = setInterval(() => {
      recordingDurationRef.current += 1
      setRecordingDuration(recordingDurationRef.current)
    }, 1000)
    return () => clearInterval(interval)
  }, [isRecording])

  const formatDuration = (secs: number) => {
    const m = Math.floor(secs / 60)
    const s = secs % 60
    return `${m}:${s.toString().padStart(2, "0")}`
  }

  const formatFileSize = (bytes: number) => {
    if (bytes < 1024) return bytes + " B"
    if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB"
    return (bytes / (1024 * 1024)).toFixed(1) + " MB"
  }

  const isImageFile = (file: File) => file.type.startsWith("image/")

  const getDisplayContent = (content: string) => {
    try {
      const parsed = JSON.parse(content)
      if (parsed.text !== undefined) return parsed.text
    } catch {}
    return content
  }

  const fileToDataURL = (file: File): Promise<string> => new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onload = () => resolve(reader.result as string)
    reader.onerror = reject
    reader.readAsDataURL(file)
  })

  return (
    <div className="flex h-[calc(100dvh-4rem)] -m-4 lg:-m-6 rounded-lg border bg-card overflow-hidden">
      {/* Conversations list - left panel */}
      <div
        className="flex flex-col border-r shrink-0 overflow-hidden"
        style={{ width: panelWidth }}
      >
        <div className="p-4 border-b space-y-3">
          <h2 className="text-lg font-semibold">Chats</h2>
          <div className="relative">
            <Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
            <Input value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} placeholder="Search conversations..." className="h-9 pl-9" />
          </div>
        </div>
        <ScrollArea className="flex-1">
          {filteredConversations.map((conv) => {
            const person = otherParticipant(conv)
            const isActive = conv.id === activeChat
            return (
                <button
                  key={conv.id}
                  onClick={() => {
                    setActiveChat(conv.id)
                    setUnreadMap((prev) => { const m = new Map(prev); m.set(conv.id, 0); return m })
                    setConversations((prev) => {
                      const idx = prev.findIndex((c) => c.id === conv.id)
                      if (idx > 0) {
                        const u = [...prev]
                        const [item] = u.splice(idx, 1)
                        u.unshift(item)
                        return u
                      }
                      return prev
                    })
                  }}
                className={cn(
                  "w-full flex items-start gap-3 p-4 text-left transition-colors hover:bg-muted/50 relative",
                  isActive && "bg-muted"
                )}
              >
                <Avatar className="h-10 w-10 shrink-0">
                  <AvatarImage src={person.avatar} />
                  <AvatarFallback>{person.name?.charAt(0) || "?"}</AvatarFallback>
                </Avatar>
                <div className="flex-1 min-w-0">
                  <div className="flex items-center justify-between gap-2">
                    <span className="text-sm font-medium truncate">{person.name}</span>
                    <span className="text-xs text-muted-foreground shrink-0">{conv.lastMessageTime}</span>
                  </div>
                  <p className="text-xs text-muted-foreground truncate mt-0.5">{formatPreviewContent(conv.lastMessage)}</p>
                </div>
                {!isActive && (unreadMap.get(conv.id) || 0) > 0 && (
                  <div className="shrink-0 h-3 w-3 rounded-full bg-red-500 animate-pulse shadow-[0_0_10px_#ef4444] self-center" />
                )}
              </button>
            )
          })}
          {searchResults.length > 0 && (
            <>
              {searchQuery && <div className="px-4 py-2 text-xs font-medium text-muted-foreground">New conversation</div>}
              {searchResults.map((person: any) => (
                <button
                  key={person.id}
                  onClick={async () => {
                    try {
                      const res = await fetch("/api/conversations", {
                        method: "POST",
                        headers: { "Content-Type": "application/json" },
                        body: JSON.stringify({ userId: person.id }),
                      })
                      if (res.ok) {
                        const data = await res.json()
                        const conv = data.conversation || conversations.find((c) => c.id === data.conversationId)
                        if (conv) {
                          setConversations((prev) => [conv, ...prev])
                          setUnreadMap((prev) => { const m = new Map(prev); m.set(conv.id, 0); return m })
                          setActiveChat(conv.id)
                          setSearchQuery("")
                        }
                      }
                    } catch { console.warn("Failed to create conversation in chats page") }
                  }}
                  className="w-full flex items-center gap-3 p-4 text-left transition-colors hover:bg-muted/50"
                >
                  <div className="relative">
                    <Avatar className="h-10 w-10 shrink-0">
                      <AvatarImage src={person.avatar} />
                      <AvatarFallback>{person.name?.charAt(0) || "?"}</AvatarFallback>
                    </Avatar>
                    <span className="absolute -bottom-0.5 -right-0.5 flex h-5 w-5 items-center justify-center rounded-full bg-primary text-[10px] text-primary-foreground font-bold">+</span>
                  </div>
                  <div className="flex-1 min-w-0">
                    <span className="text-sm font-medium truncate block">{person.name}</span>
                    <span className="text-xs text-muted-foreground truncate block">{person.email}</span>
                  </div>
                </button>
              ))}
            </>
          )}
          {filteredConversations.length === 0 && searchResults.length === 0 && searchQuery && !searchingUsers && (
            <div className="p-4 text-center text-sm text-muted-foreground">No conversations found</div>
          )}
        </ScrollArea>
      </div>

      {/* Resize handle */}
      <div
        className="w-1.5 cursor-col-resize shrink-0 relative group hover:bg-primary/20 transition-colors"
        onMouseDown={handleResizeStart}
      >
        <div className="absolute inset-y-0 -left-1 -right-1" />
      </div>

      {/* Chat area - right panel */}
      {conversation ? (
        <div className="flex-1 flex flex-col min-w-0">
          {/* Chat header */}
          <div className="flex items-center justify-between gap-4 px-6 h-16 border-b shrink-0">
            <div className="flex items-center gap-3 min-w-0">
              <Avatar className="h-9 w-9 shrink-0 cursor-pointer" onClick={() => setPreviewAvatarUrl(otherParticipant(conversation).avatar)}>
                <AvatarImage src={otherParticipant(conversation).avatar} />
                <AvatarFallback>{otherParticipant(conversation).name?.charAt(0) || "?"}</AvatarFallback>
              </Avatar>
              <div className="min-w-0">
                <p className="text-sm font-medium truncate">{otherParticipant(conversation).name}</p>
                <p className="text-xs text-muted-foreground truncate">{otherParticipant(conversation).role}</p>
              </div>
            </div>
            <div className="flex items-center gap-1 shrink-0">
              <Button variant="ghost" size="icon" className="h-8 w-8" onClick={() => setIsCallModalOpen(true)}>
                <Phone className="h-4 w-4" />
              </Button>
              <Button variant="ghost" size="icon" className="h-8 w-8" onClick={() => setScheduleDialogOpen(true)}>
                <CalendarDays className="h-4 w-4" />
              </Button>
              <DropdownMenu>
                <DropdownMenuTrigger asChild>
                  <Button variant="ghost" size="icon" className="h-8 w-8">
                    <MoreHorizontal className="h-4 w-4" />
                  </Button>
                </DropdownMenuTrigger>
                <DropdownMenuContent align="end" className="w-44">
                  <DropdownMenuLabel>Actions</DropdownMenuLabel>
                  <DropdownMenuSeparator />
                  <DropdownMenuItem onClick={() => setReportDialogOpen(true)}>
                    <Flag className="mr-2 h-4 w-4" /> Report
                  </DropdownMenuItem>
                  <DropdownMenuItem onClick={() => toast.info("Blocked")}>
                    <Ban className="mr-2 h-4 w-4" /> Block
                  </DropdownMenuItem>
                  <DropdownMenuSeparator />
                  <DropdownMenuItem className="text-destructive" onClick={() => toast.info("Conversation deleted")}>
                    <Trash2 className="mr-2 h-4 w-4" /> Delete
                  </DropdownMenuItem>
                </DropdownMenuContent>
              </DropdownMenu>
            </div>
          </div>

          {/* Messages */}
          <div className="flex-1 overflow-y-auto p-6" style={{ scrollbarWidth: "thin", scrollbarColor: "hsl(var(--muted-foreground) / 0.3) transparent" }}>
            <div className="space-y-4 min-h-0">
              {messages.map((msg) => {
                const isMe = msg.senderId === user?.id
                let voiceUrl = voiceMessages.get(msg.id)
                let gifData: { url: string; w: number; h: number } | null = null
                let stickerData: { url: string; w: number; h: number; emoji?: string } | null = null
                if (msg.content?.startsWith("{")) {
                  try {
                    const p = JSON.parse(msg.content)
                    if (p.v && p.u) voiceUrl = { url: p.u, duration: p.d || 0 }
                    else if (p.gif) gifData = { url: p.gif, w: p.w || 320, h: p.h || 240 }
                    else if (p.sticker) stickerData = { url: p.sticker, w: p.w || 200, h: p.h || 200, emoji: p.id ? undefined : p.sticker }
                  } catch {}
                }
                return (
                  <div key={msg.id} className={cn("group flex gap-3", isMe && "flex-row-reverse")}>
                    <Avatar className="h-8 w-8 mt-0.5 shrink-0 cursor-pointer" onClick={() => setPreviewAvatarUrl(msg.senderAvatar)}>
                      <AvatarImage src={msg.senderAvatar} />
                      <AvatarFallback className={cn("text-xs", isMe && "bg-primary text-primary-foreground")}>
                        {msg.senderName?.charAt(0) || "?"}
                      </AvatarFallback>
                    </Avatar>
                    <div className={cn("max-w-[70%]", isMe && "items-end flex flex-col")}>
                      <div
                        className={cn(
                          "rounded-2xl px-5 py-3 text-base relative",
                          isMe ? "bg-primary text-primary-foreground rounded-tr-sm" : "bg-muted rounded-tl-sm"
                        )}
                      >
                        {!isMe && (
                          <DropdownMenu>
                            <DropdownMenuTrigger asChild>
                              <button type="button" className="absolute -right-8 top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-100 transition-opacity h-6 w-6 flex items-center justify-center rounded-full hover:bg-sky-400/20">
                                <MoreHorizontal className="h-3.5 w-3.5 text-sky-400" />
                              </button>
                            </DropdownMenuTrigger>
                            <DropdownMenuContent align="start" side="top" className="w-32">
                              <DropdownMenuItem onClick={() => setReplyingTo(msg)}>
                                <CornerDownRight className="mr-2 h-4 w-4" /> Reply
                              </DropdownMenuItem>
                              <DropdownMenuItem onClick={() => { setForwardMessage(msg); setForwardDialogOpen(true) }}>
                                <Forward className="mr-2 h-4 w-4" /> Forward
                              </DropdownMenuItem>
                            </DropdownMenuContent>
                          </DropdownMenu>
                        )}
                        {isMe && (
                          <DropdownMenu>
                            <DropdownMenuTrigger asChild>
                              <button type="button" className="absolute -left-8 top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-100 transition-opacity h-6 w-6 flex items-center justify-center rounded-full hover:bg-sky-400/20">
                                <MoreHorizontal className="h-3.5 w-3.5 text-sky-400" />
                              </button>
                            </DropdownMenuTrigger>
                             <DropdownMenuContent align="end" side="top" className="w-32">
                              <DropdownMenuItem onClick={() => { setEditingMessage(msg); setMessageInput(msg.content) }}>
                                <Pencil className="mr-2 h-4 w-4" /> Edit
                              </DropdownMenuItem>
                              <DropdownMenuItem onClick={() => setReplyingTo(msg)}>
                                <CornerDownRight className="mr-2 h-4 w-4" /> Reply
                              </DropdownMenuItem>
                              <DropdownMenuItem onClick={() => { setForwardMessage(msg); setForwardDialogOpen(true) }}>
                                <Forward className="mr-2 h-4 w-4" /> Forward
                              </DropdownMenuItem>
                              <DropdownMenuSeparator />
                              <DropdownMenuItem className="text-destructive" onClick={() => handleDeleteMessage(msg.id)}>
                                <Trash2 className="mr-2 h-4 w-4" /> Delete
                              </DropdownMenuItem>
                            </DropdownMenuContent>
                          </DropdownMenu>
                        )}
                        {(() => {
                          const replyInfo = replyMap.get(msg.id)
                          return (
                            <>
                              {replyInfo && (
                                <div className={cn("mb-1.5 pl-2 border-l-2 overflow-hidden bg-black/70 rounded-sm text-white", isMe ? "border-white/40" : "border-primary/40")}>
                                  <p className="text-[11px] font-medium truncate">{replyInfo.repliedToSender}</p>
                                  <p className="text-[11px] text-white/60 truncate">{replyInfo.repliedToContent}</p>
                                </div>
                              )}
                              {gifData ? (
                                <div className="max-w-[280px]">
                                  <img src={gifData.url} alt="GIF" className="w-full rounded-lg" style={{ aspectRatio: `${gifData.w}/${gifData.h}` }} loading="lazy" />
                                </div>
                              ) : stickerData ? (
                                <div className="max-w-[200px]">
                                  {stickerData.emoji ? (
                                    <span className="text-7xl block text-center">{stickerData.emoji}</span>
                                  ) : (
                                    <div className="w-full" dangerouslySetInnerHTML={{ __html: stickerData.url.replace(/<svg /, '<svg style="width:100%;height:auto;max-height:200px" ') }} />
                                  )}
                                </div>
                              ) : voiceUrl ? (
                                <div>
                                  <VoiceMessagePlayer src={voiceUrl.url} initialDuration={voiceUrl.duration} isOwn={isMe} />
                                </div>
                              ) : (
                                <>
                                  {(() => {
                                    const files = messageAttachments.get(msg.id)
                                    return files && files.length > 0 ? (
                                      <div className="space-y-1.5 mb-1.5">
                                        {files.map((file, i) =>
                                          file.type.startsWith("image/") ? (
                                            <div key={i} className="relative group">
                                              <img src={file.url} alt={file.name} className="max-w-full rounded-lg max-h-60 object-cover cursor-pointer" onClick={() => setPreviewImageUrl(file.url)} />
                                              <a href={file.url} download={file.name} className="absolute top-2 right-2 h-7 w-7 rounded-full bg-black/50 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity">
                                                <Download className="h-3.5 w-3.5 text-white" />
                                              </a>
                                            </div>
                                          ) : (
                                            <div key={i} className="flex items-center gap-2 rounded-lg border bg-muted/50 px-3 py-2 text-sm hover:bg-muted/80 transition-colors">
                                              <button type="button" className="flex items-center gap-2 flex-1 min-w-0 text-left" onClick={() => window.open(file.url, "_blank")} title="Open">
                                                <FileIcon className="h-4 w-4 shrink-0 text-muted-foreground" />
                                                <span className="flex-1 min-w-0 truncate">{file.name}</span>
                                              </button>
                                              <a href={file.url} download={file.name} className="shrink-0 text-muted-foreground hover:text-foreground" title="Download">
                                                <Download className="h-3.5 w-3.5" />
                                              </a>
                                            </div>
                                          )
                                        )}
                                      </div>
                                    ) : null
                                  })()}
                                  {isOnlyEmoji(getDisplayContent(msg.content)) ? (
                                    <span className="text-4xl leading-none">{getDisplayContent(msg.content).trim()}</span>
                                  ) : (
                                    getDisplayContent(msg.content)
                                  )}
                                </>
                              )}
                            </>
                          )
                        })()}
                      </div>
                      <span className="flex items-center gap-1 text-xs text-muted-foreground mt-1.5 px-1">
                        {msg.timestamp}
                        {isMe && (
                          msg.read
                            ? <CheckCheck className="h-3 w-3 text-blue-400" />
                            : <Check className="h-3 w-3 text-muted-foreground/60" />
                        )}
                      </span>
                    </div>
                  </div>
                )
              })}
            <div ref={messagesEndRef} />
            </div>
          </div>

          {/* Input */}
          <div className="p-4 border-t shrink-0 space-y-2">
            {attachments.length > 0 && (
              <div className="flex flex-wrap gap-2">
                {attachments.map((file, i) => (
                  <div key={i} className="flex items-center gap-2 rounded-lg border bg-muted/50 px-3 py-1.5 text-sm max-w-[200px]">
                    {isImageFile(file) ? (
                      <Image className="h-4 w-4 shrink-0 text-muted-foreground" />
                    ) : (
                      <FileIcon className="h-4 w-4 shrink-0 text-muted-foreground" />
                    )}
                    <span className="truncate">{file.name}</span>
                    <span className="text-xs text-muted-foreground shrink-0">{formatFileSize(file.size)}</span>
                    <Button variant="ghost" size="icon" className="h-5 w-5 -mr-1 shrink-0" onClick={() => removeAttachment(i)}>
                      <X className="h-3 w-3" />
                    </Button>
                  </div>
                ))}
              </div>
            )}
            {/* Reply bar */}
            {replyingTo && (
              <div className="flex items-center gap-2 rounded-lg border-l-4 border-primary bg-muted/50 px-3 py-2 text-sm">
                <div className="flex-1 min-w-0">
                  <p className="text-xs font-medium text-primary">
                    Replying to {replyingTo.senderId === user?.id ? "yourself" : otherParticipant(conversation).name}
                  </p>
                  <p className="text-xs text-muted-foreground truncate">{replyingTo.content}</p>
                </div>
                <Button variant="ghost" size="icon" className="h-6 w-6 shrink-0" onClick={() => setReplyingTo(null)}>
                  <X className="h-3 w-3" />
                </Button>
              </div>
            )}
            {editingMessage && (
              <div className="flex items-center gap-2 rounded-lg bg-muted/50 px-3 py-2 text-sm">
                <Pencil className="h-4 w-4 text-muted-foreground shrink-0" />
                <span className="text-xs text-muted-foreground">Editing message</span>
                <Button variant="ghost" size="icon" className="h-6 w-6 shrink-0 ml-auto" onClick={() => { setEditingMessage(null); setMessageInput(""); setTimeout(() => autoResizeTextarea(), 0) }}>
                  <X className="h-3 w-3" />
                </Button>
              </div>
            )}
            <form onSubmit={handleSend} className="flex items-center gap-2">
              <input ref={fileInputRef} type="file" multiple accept="image/*,.pdf,.doc,.docx,.xls,.xlsx,.txt" className="hidden" onChange={handleFileSelect} />
              <div className="relative">
                <Button type="button" variant="ghost" size="icon" className="h-9 w-9 shrink-0" onClick={() => setShowAttachMenu(!showAttachMenu)}>
                  <Paperclip className="h-4 w-4 text-muted-foreground" />
                </Button>
                {showAttachMenu && (
                  <div ref={attachMenuRef} className="absolute bottom-full left-0 mb-2 z-50 bg-popover border rounded-lg shadow-lg p-1.5 min-w-[140px]">
                    <button type="button" className="flex items-center gap-2 w-full px-2 py-1.5 text-sm rounded-md hover:bg-muted" onClick={() => { fileInputRef.current?.setAttribute("accept", "image/*"); fileInputRef.current?.click(); setShowAttachMenu(false) }}>
                      <Image className="h-4 w-4" /> Photos
                    </button>
                    <button type="button" className="flex items-center gap-2 w-full px-2 py-1.5 text-sm rounded-md hover:bg-muted" onClick={() => { fileInputRef.current?.setAttribute("accept", ".pdf,.doc,.docx,.xls,.xlsx,.txt"); fileInputRef.current?.click(); setShowAttachMenu(false) }}>
                      <FileIcon className="h-4 w-4" /> Documents
                    </button>
                    <button type="button" className="flex items-center gap-2 w-full px-2 py-1.5 text-sm rounded-md hover:bg-muted" onClick={() => { fileInputRef.current?.removeAttribute("accept"); fileInputRef.current?.click(); setShowAttachMenu(false) }}>
                      <FolderOpen className="h-4 w-4" /> Files
                    </button>
                    <button type="button" className="flex items-center gap-2 w-full px-2 py-1.5 text-sm rounded-md hover:bg-muted" onClick={() => { fileInputRef.current?.setAttribute("accept", ".eml,.msg"); fileInputRef.current?.click(); setShowAttachMenu(false) }}>
                      <Mail className="h-4 w-4" /> Emails
                    </button>
                  </div>
                )}
              </div>
              <div className="relative flex-1">
                {isRecording ? (
                  <div className="flex h-9 items-center gap-1 rounded-md border bg-muted/30 px-2">
                    <span className={cn("h-2 w-2 rounded-full", isPaused ? "bg-muted-foreground" : "bg-destructive animate-pulse")} />
                    <span className="text-sm tabular-nums font-medium text-muted-foreground">{formatDuration(recordingDuration)}</span>
                    <div className="flex-1" />
                    <Button type="button" variant="ghost" size="icon" className="h-7 w-7 shrink-0 text-muted-foreground hover:text-muted-foreground" onClick={togglePauseRecording}>
                      {isPaused ? <Play className="h-3.5 w-3.5 fill-current ml-0.5" /> : <Pause className="h-3.5 w-3.5 fill-current" />}
                    </Button>
                    <Button type="button" variant="ghost" size="icon" className="h-7 w-7 shrink-0 text-destructive hover:text-destructive" onClick={discardRecording}>
                      <Trash2 className="h-3.5 w-3.5" />
                    </Button>
                    <Button type="button" variant="ghost" size="icon" className="h-7 w-7 shrink-0 text-destructive hover:text-destructive" onClick={stopRecording}>
                      <Square className="h-3.5 w-3.5 fill-current" />
                    </Button>
                  </div>
                ) : previewUrl ? (
                  <div className="flex h-9 items-center gap-2 rounded-md border bg-muted/30 px-3">
                    <button type="button" onClick={togglePreviewPlay} className="h-6 w-6 shrink-0 rounded-full flex items-center justify-center hover:bg-black/10 transition-colors">
                      {isPreviewPlaying ? <Pause className="h-3.5 w-3.5 fill-current" /> : <Play className="h-3.5 w-3.5 ml-0.5 fill-current" />}
                    </button>
                    <div className="flex-1 h-1 rounded-full bg-muted-foreground/20 relative overflow-hidden">
                      <div className="h-full rounded-full bg-primary transition-all duration-100" style={{ width: `${previewDuration > 0 ? (previewCurrent / previewDuration) * 100 : 0}%` }} />
                    </div>
                    <span className="text-xs tabular-nums text-muted-foreground w-8 text-right">{formatDuration(Math.floor(previewCurrent))}/{formatDuration(previewDuration)}</span>
                    <Button type="button" variant="ghost" size="icon" className="h-6 w-6 shrink-0 text-destructive hover:text-destructive" onClick={cancelVoicePreview}>
                      <Trash2 className="h-3 w-3" />
                    </Button>
                    <Button type="button" variant="ghost" size="icon" className="h-6 w-6 shrink-0 text-primary hover:text-primary" onClick={sendVoiceRecording}>
                      <Send className="h-3 w-3" />
                    </Button>
                  </div>
                ) : (
                  <>
                    <textarea ref={textareaRef} value={messageInput} onChange={(e) => { setMessageInput(e.target.value); autoResizeTextarea() }} onPaste={(e) => { if (!e.clipboardData) return; const items = Array.from(e.clipboardData.items).filter((item) => item.type.startsWith("image/")); if (items.length > 0) { e.preventDefault(); const files = items.map((item) => item.getAsFile()).filter((f): f is File => f !== null); setAttachments((prev) => [...prev, ...filterBlockedFiles(files).allowed]) } }} placeholder={editingMessage ? "Edit message..." : "Type a message..."} className="w-full resize-none overflow-hidden rounded-md border border-input bg-transparent px-3 py-1.5 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 min-h-[36px] max-h-[200px] pr-16" style={{ height: "auto" }} rows={1} />
                    <div className="absolute right-0 top-0 bottom-0 flex items-center pr-1" ref={emojiPickerRef}>
                      <Button type="button" variant="ghost" size="icon" className="h-7 w-7 shrink-0" onClick={() => setShowEmojiPicker(!showEmojiPicker)}>
                        <Smile className="h-4 w-4 text-muted-foreground" />
                      </Button>
                      <Button type="button" variant="ghost" size="icon" className="h-7 w-7 shrink-0" onClick={startRecording}>
                        <Mic className="h-4 w-4 text-muted-foreground" />
                      </Button>
                      {showEmojiPicker && (
                        <div className="absolute bottom-full right-0 mb-2 z-50">
                          <MediaPicker onEmojiSelect={handleEmojiSelect} onMediaSelect={handleMediaSelect} onClose={() => setShowEmojiPicker(false)} theme={theme} />
                        </div>
                      )}
                    </div>
                  </>
                )}
              </div>
              <Button type="submit" size="icon" className="h-9 w-9 shrink-0" disabled={(!messageInput.trim() && attachments.length === 0) || attachments.some(f => hasBlockedCodeExtension(f.name))}>
                {editingMessage ? <Pencil className="h-4 w-4" /> : <Send className="h-4 w-4" />}
              </Button>
            </form>
          </div>
        </div>
      ) : (
        <div className="flex-1 flex items-center justify-center text-muted-foreground">
          <p>Select a conversation to start chatting</p>
        </div>
      )}

      {/* Resize overlay */}
      {isResizing && <div className="fixed inset-0 z-50 cursor-col-resize" />}

      {/* Report dialog */}
      <Dialog open={reportDialogOpen} onOpenChange={setReportDialogOpen}>
        <DialogContent className="sm:max-w-md">
          <DialogHeader>
            <DialogTitle>Report {conversation ? otherParticipant(conversation).name : "User"}</DialogTitle>
            <DialogDescription>Let us know why you're reporting this conversation.</DialogDescription>
          </DialogHeader>
          <div className="space-y-3 py-2">
            <Label htmlFor="reason">Reason</Label>
            <Textarea id="reason" placeholder="Describe the issue..." value={reportReason} onChange={(e) => setReportReason(e.target.value)} rows={4} />
          </div>
          <DialogFooter>
            <DialogClose asChild><Button variant="outline">Cancel</Button></DialogClose>
            <Button onClick={() => { toast.success("Report submitted"); setReportReason(""); setReportDialogOpen(false) }} disabled={!reportReason.trim()}>Submit Report</Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Image preview dialog */}
      <Dialog open={!!previewImageUrl} onOpenChange={(o) => { if (!o) setPreviewImageUrl(null) }}>
        <DialogContent className="sm:max-w-3xl p-0 overflow-hidden bg-transparent border-0 shadow-none">
          <DialogTitle className="sr-only">Image preview</DialogTitle>
          {previewImageUrl && (
            <img
              src={previewImageUrl}
              alt="Image preview"
              className="w-full h-auto max-h-[85vh] object-contain rounded-2xl"
            />
          )}
        </DialogContent>
      </Dialog>

      {/* Avatar preview dialog */}
      <Dialog open={!!previewAvatarUrl} onOpenChange={(o) => { if (!o) setPreviewAvatarUrl(null) }}>
        <DialogContent className="sm:max-w-sm p-0 overflow-hidden bg-transparent border-0 shadow-none">
          {previewAvatarUrl && (
            <img
              src={previewAvatarUrl}
              alt="Profile picture"
              className="w-full h-auto max-h-[80vh] object-contain rounded-2xl"
            />
          )}
        </DialogContent>
      </Dialog>

      {/* Forward dialog */}
      <Dialog open={forwardDialogOpen} onOpenChange={setForwardDialogOpen}>
        <DialogContent className="sm:max-w-sm">
          <DialogHeader>
            <DialogTitle>Forward message</DialogTitle>
            <DialogDescription>Select who to forward this message to.</DialogDescription>
          </DialogHeader>
          <div className="relative">
            <Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
            <Input value={forwardSearch} onChange={(e) => setForwardSearch(e.target.value)} placeholder="Search contacts..." className="h-9 pl-9" />
          </div>
          <ScrollArea className="max-h-64">
            <div className="space-y-0.5">
              {conversations
                .filter((conv) => {
                  const person = otherParticipant(conv)
                  return person.name.toLowerCase().includes(forwardSearch.toLowerCase())
                })
                .map((conv) => {
                  const person = otherParticipant(conv)
                  return (
                    <button
                      key={conv.id}
                      type="button"
                      onClick={async () => {
                        const msg = forwardMessage
                        if (!msg || !user) return
                        const newContent = `📨 Forwarded: ${msg.content}`
                        try {
                          const res = await fetch(`/api/conversations/${conv.id}/messages`, {
                            method: "POST",
                            headers: { "Content-Type": "application/json" },
                            body: JSON.stringify({ content: newContent }),
                          })
                          if (res.ok) {
                            setForwardDialogOpen(false)
                            setForwardSearch("")
                            toast.success("Message forwarded")
                          }
                        } catch {
                          console.warn("Failed to forward message in chats page")
                          toast.error("Failed to forward message")
                        }
                      }}
                      className="w-full flex items-center gap-3 rounded-lg p-2.5 text-left transition-colors hover:bg-muted"
                    >
                      <Avatar className="h-9 w-9 shrink-0">
                        <AvatarFallback>{person.name.charAt(0)}</AvatarFallback>
                      </Avatar>
                      <div className="flex-1 min-w-0">
                        <p className="text-sm font-medium truncate">{person.name}</p>
                        <p className="text-xs text-muted-foreground truncate">{person.email || ""}</p>
                      </div>
                    </button>
                  )
                })}
              {forwardSearch && conversations.filter((conv) => otherParticipant(conv).name.toLowerCase().includes(forwardSearch.toLowerCase())).length === 0 && (
                <p className="text-sm text-muted-foreground text-center py-4">No contacts found</p>
              )}
            </div>
          </ScrollArea>
        </DialogContent>
      </Dialog>
      <VoiceCallModal open={isCallModalOpen} onClose={() => setIsCallModalOpen(false)} />
      {/* Schedule from Chat Dialog */}
      <Dialog open={scheduleDialogOpen} onOpenChange={setScheduleDialogOpen}>
        <DialogContent className="sm:max-w-[440px]">
          <DialogHeader>
            <DialogTitle>Schedule with {conversation ? otherParticipant(conversation).name : "..."}</DialogTitle>
            <DialogDescription>Create an event and notify the participant</DialogDescription>
          </DialogHeader>
          <div className="space-y-4">
            <div>
              <Label htmlFor="sched-title">Title</Label>
              <Input id="sched-title" value={scheduleTitle} onChange={(e) => setScheduleTitle(e.target.value)} placeholder="e.g. Follow-up call" />
            </div>
            <div className="grid grid-cols-2 gap-4">
              <div>
                <Label htmlFor="sched-date">Date</Label>
                <Input id="sched-date" type="date" value={scheduleDate} onChange={(e) => setScheduleDate(e.target.value)} />
              </div>
              <div>
                <Label htmlFor="sched-time">Time</Label>
                <Input id="sched-time" type="time" value={scheduleTime} onChange={(e) => setScheduleTime(e.target.value)} />
              </div>
            </div>
            <div className="grid grid-cols-2 gap-4">
              <div>
                <Label htmlFor="sched-type">Type</Label>
                <Select value={scheduleType} onValueChange={setScheduleType}>
                  <SelectTrigger id="sched-type">
                    <SelectValue />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="meeting">Meeting</SelectItem>
                    <SelectItem value="call">Call</SelectItem>
                    <SelectItem value="follow_up">Follow Up</SelectItem>
                    <SelectItem value="demo">Demo</SelectItem>
                  </SelectContent>
                </Select>
              </div>
              <div>
                <Label htmlFor="sched-duration">Duration</Label>
                <Select value={scheduleDuration} onValueChange={setScheduleDuration}>
                  <SelectTrigger id="sched-duration">
                    <SelectValue />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectItem value="15">15 min</SelectItem>
                    <SelectItem value="30">30 min</SelectItem>
                    <SelectItem value="60">1 hour</SelectItem>
                    <SelectItem value="90">1.5 hours</SelectItem>
                  </SelectContent>
                </Select>
              </div>
            </div>
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setScheduleDialogOpen(false)}>Cancel</Button>
            <Button disabled={scheduleSaving || !scheduleTitle || !scheduleDate || !scheduleTime} onClick={async () => {
              if (!conversation || !user) return
              setScheduleSaving(true)
              try {
                const startTime = new Date(`${scheduleDate}T${scheduleTime}:00`).toISOString()
                const end = new Date(startTime)
                end.setMinutes(end.getMinutes() + parseInt(scheduleDuration))
                const res = await fetch("/api/events", {
                  method: "POST",
                  headers: { "Content-Type": "application/json" },
                  body: JSON.stringify({
                    title: scheduleTitle,
                    eventType: scheduleType,
                    startTime,
                    endTime: end.toISOString(),
                    durationMinutes: parseInt(scheduleDuration),
                    participantId: otherParticipant(conversation).id,
                    conversationId: conversation.id,
                  }),
                })
                if (!res.ok) throw new Error("Failed")
                toast.success("Event scheduled! Notification sent.")
                setScheduleDialogOpen(false)
                setScheduleTitle("")
                setScheduleDate("")
                setScheduleTime("")
              } catch {
                toast.error("Failed to schedule event")
              } finally {
                setScheduleSaving(false)
              }
            }}>
              {scheduleSaving && <Loader2 className="h-4 w-4 animate-spin mr-2" />}
              Schedule
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  )
}
