"use client"

import Image from "next/image"
import { useCallback, useEffect, useRef, useState } from "react"
import { useAction, useMutation, useQuery } from "convex/react"
import type { Id } from "@/convex/_generated/dataModel"
import { api } from "@/convex/_generated/api"
import { useAuth } from "@/lib/auth-client"
import { Button } from "@/components/ui/button"
import { Spinner } from "@/components/ui/spinner"
import { cn } from "@/lib/utils"
import { toast } from "sonner"
import {
  MessageCircle,
  Send,
  X,
  Minimize2,
  User,
  ChevronDown,
  ChevronLeft,
  WifiOff,
  XCircle,
  Paperclip,
  FileText,
  Image as ImageIcon,
  Download,
  ExternalLink,
  Eye,
  Check,
} from "lucide-react"
import { ChatSessionList } from "./chat-session-list"

const MAX_MESSAGE_LENGTH = 4000
const MAX_ATTACHMENT_SIZE = 5 * 1024 * 1024 // 5MB
const MAX_ATTACHMENTS = 5
const STORAGE_KEY = "chat-widget-state"

type ViewMode = "list" | "chat"

type ChatWidgetState = {
  isOpen: boolean
  isMinimized: boolean
  activeTicketId: string | null
  viewMode: ViewMode
}

function formatTime(timestamp: number) {
  return new Date(timestamp).toLocaleTimeString("pt-BR", {
    hour: "2-digit",
    minute: "2-digit",
  })
}

function formatDateSeparator(timestamp: number) {
  const date = new Date(timestamp)
  const today = new Date()
  const yesterday = new Date(today)
  yesterday.setDate(yesterday.getDate() - 1)

  const isToday = date.toDateString() === today.toDateString()
  const isYesterday = date.toDateString() === yesterday.toDateString()

  if (isToday) return "Hoje"
  if (isYesterday) return "Ontem"

  return date.toLocaleDateString("pt-BR", {
    weekday: "long",
    day: "2-digit",
    month: "long",
  })
}

function getDateKey(timestamp: number) {
  return new Date(timestamp).toDateString()
}

// Componente separador de data (estilo WhatsApp)
function DateSeparator({ timestamp }: { timestamp: number }) {
  return (
    <div className="flex items-center justify-center py-2">
      <div className="rounded-full bg-slate-200/80 px-3 py-1 text-xs font-medium text-slate-600">
        {formatDateSeparator(timestamp)}
      </div>
    </div>
  )
}

type ChatSession = {
  ticketId: string
  ticketRef: number
  ticketSubject: string
  sessionId: string
  agentId: string
  unreadCount: number
  lastActivityAt: number
}

type UploadedFile = {
  storageId: string
  name: string
  size: number
  type: string
  previewUrl?: string
}

type ChatAttachment = {
  storageId: Id<"_storage">
  name: string
  size: number | null
  type: string | null
}

type ChatData = {
  ticketId: string
  chatEnabled: boolean
  status: string
  canPost: boolean
  reopenDeadline: number | null
  liveChat?: {
    hasMachine: boolean
    machineOnline: boolean
    machineHostname: string | null
    activeSession: {
      sessionId: Id<"liveChatSessions">
      agentId: Id<"users">
      agentName: string | null
      startedAt: number
      unreadByAgent: number
    } | null
  }
  messages: Array<{
    id: Id<"ticketChatMessages">
    body: string
    createdAt: number
    updatedAt: number
    authorId: string
    authorName: string | null
    authorEmail: string | null
    attachments: ChatAttachment[]
    readBy: Array<{ userId: string; readAt: number }>
  }>
}

// Componente de preview de anexo na mensagem
function MessageAttachment({ attachment }: { attachment: ChatAttachment }) {
  const getFileUrl = useAction(api.files.getUrl)
  const [url, setUrl] = useState<string | null>(null)
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    let cancelled = false
    async function loadUrl() {
      try {
        const fileUrl = await getFileUrl({ storageId: attachment.storageId })
        if (!cancelled && fileUrl) {
          setUrl(fileUrl)
        }
      } catch (error) {
        console.error("Erro ao carregar anexo:", error)
      } finally {
        if (!cancelled) setLoading(false)
      }
    }
    loadUrl()
    return () => { cancelled = true }
  }, [attachment.storageId, getFileUrl])

  const isImage = attachment.type?.startsWith("image/")
  const [downloading, setDownloading] = useState(false)
  const [downloaded, setDownloaded] = useState(false)

  const handleView = () => {
    if (!url) return
    window.open(url, "_blank", "noopener,noreferrer")
  }

  const handleDownload = async () => {
    if (!url || downloading) return
    setDownloading(true)
    try {
      const response = await fetch(url)
      const blob = await response.blob()
      const downloadUrl = URL.createObjectURL(blob)
      const a = document.createElement("a")
      a.href = downloadUrl
      a.download = attachment.name
      document.body.appendChild(a)
      a.click()
      document.body.removeChild(a)
      URL.revokeObjectURL(downloadUrl)
      setDownloaded(true)
      setTimeout(() => setDownloaded(false), 2000)
    } catch (error) {
      toast.error("Erro ao baixar arquivo")
    } finally {
      setDownloading(false)
    }
  }

  if (loading) {
    return (
      <div className="flex size-12 items-center justify-center rounded-lg border border-slate-200 bg-slate-50">
        <Spinner className="size-4 text-slate-400" />
      </div>
    )
  }

  if (isImage && url) {
    return (
      <div className="group relative overflow-hidden rounded-lg border border-slate-200">
        {/* eslint-disable-next-line @next/next/no-img-element */}
        <img
          src={url}
          alt={attachment.name}
          className="size-16 cursor-pointer object-cover"
          onClick={handleView}
        />
        <div className="absolute inset-0 flex items-center justify-center gap-1 bg-black/50 opacity-0 transition-opacity group-hover:opacity-100">
          <button
            onClick={handleView}
            className="flex size-6 items-center justify-center rounded-full bg-white/20 hover:bg-white/30"
          >
            <Eye className="size-3.5 text-white" />
          </button>
          <button
            onClick={handleDownload}
            disabled={downloading}
            className="flex size-6 items-center justify-center rounded-full bg-white/20 hover:bg-white/30"
          >
            {downloading ? (
              <Spinner className="size-3 text-white" />
            ) : downloaded ? (
              <Check className="size-3.5 text-emerald-400" />
            ) : (
              <Download className="size-3.5 text-white" />
            )}
          </button>
        </div>
      </div>
    )
  }

  return (
    <div className="flex items-center gap-1.5 rounded-lg border border-slate-200 bg-slate-50 px-2 py-1.5 text-xs">
      <FileText className="size-4 text-slate-500" />
      <span className="max-w-[80px] truncate text-slate-700">{attachment.name}</span>
      <button
        onClick={handleView}
        className="rounded p-0.5 hover:bg-slate-200"
      >
        <Eye className="size-3 text-slate-400" />
      </button>
      <button
        onClick={handleDownload}
        disabled={downloading}
        className="rounded p-0.5 hover:bg-slate-200"
      >
        {downloading ? (
          <Spinner className="size-3 text-slate-400" />
        ) : downloaded ? (
          <Check className="size-3 text-emerald-500" />
        ) : (
          <Download className="size-3 text-slate-400" />
        )}
      </button>
    </div>
  )
}

export function ChatWidget() {
  // Detectar se esta rodando no Tauri (desktop) - nesse caso, nao renderizar
  // pois o chat nativo do Tauri ja esta disponivel
  const isTauriContext = typeof window !== "undefined" && "__TAURI__" in window

  const { convexUserId, isStaff } = useAuth()
  const viewerId = isStaff ? (convexUserId ?? null) : null

  // Inicializar estado a partir do localStorage (para persistir entre reloads)
  const [isOpen, setIsOpen] = useState(() => {
    if (typeof window === "undefined") return false
    try {
      const saved = localStorage.getItem(STORAGE_KEY)
      if (saved) {
        const state = JSON.parse(saved) as ChatWidgetState
        return state.isOpen
      }
    } catch {}
    return false
  })
  const [isMinimized, setIsMinimized] = useState(() => {
    if (typeof window === "undefined") return false
    try {
      const saved = localStorage.getItem(STORAGE_KEY)
      if (saved) {
        const state = JSON.parse(saved) as ChatWidgetState
        return state.isMinimized
      }
    } catch {}
    return false
  })
  const [activeTicketId, setActiveTicketId] = useState<string | null>(() => {
    if (typeof window === "undefined") return null
    try {
      const saved = localStorage.getItem(STORAGE_KEY)
      if (saved) {
        const state = JSON.parse(saved) as ChatWidgetState
        return state.activeTicketId
      }
    } catch {}
    return null
  })
  const [viewMode, setViewMode] = useState<ViewMode>(() => {
    if (typeof window === "undefined") return "list"
    try {
      const saved = localStorage.getItem(STORAGE_KEY)
      if (saved) {
        const state = JSON.parse(saved) as ChatWidgetState
        return state.viewMode ?? "list"
      }
    } catch {}
    return "list"
  })
  const [draft, setDraft] = useState("")
  const [isSending, setIsSending] = useState(false)
  const [isEndingChat, setIsEndingChat] = useState(false)
  const [attachments, setAttachments] = useState<UploadedFile[]>([])
  const [isUploading, setIsUploading] = useState(false)
  const [isDragging, setIsDragging] = useState(false)

  const messagesEndRef = useRef<HTMLDivElement | null>(null)
  const inputRef = useRef<HTMLTextAreaElement | null>(null)
  const fileInputRef = useRef<HTMLInputElement | null>(null)
  const dropAreaRef = useRef<HTMLDivElement | null>(null)
  const hasInitializedSessionsRef = useRef(false)
  const prevSessionIdsRef = useRef<Set<string>>(new Set())

  // Buscar sessões de chat ativas do agente
  const activeSessions = useQuery(
    api.liveChat.listAgentSessions,
    viewerId ? { agentId: viewerId as Id<"users"> } : "skip"
  ) as ChatSession[] | undefined

  // Buscar mensagens do chat ativo
  const chat = useQuery(
    api.tickets.listChatMessages,
    viewerId && activeTicketId
      ? { ticketId: activeTicketId as Id<"tickets">, viewerId: viewerId as Id<"users"> }
      : "skip"
  ) as ChatData | null | undefined

  const postChatMessage = useMutation(api.tickets.postChatMessage)
  const markChatRead = useMutation(api.tickets.markChatRead)
  const endLiveChat = useMutation(api.liveChat.endSession)
  const generateUploadUrl = useAction(api.files.generateUploadUrl)

  const messages = chat?.messages ?? []
  const totalUnread = activeSessions?.reduce((sum, s) => sum + s.unreadCount, 0) ?? 0
  const liveChat = chat?.liveChat
  const machineOnline = liveChat?.machineOnline ?? false
  const machineHostname = liveChat?.machineHostname

  // Sincronizar estado entre abas usando evento storage do localStorage
  // O evento storage dispara automaticamente em TODAS as outras abas quando localStorage muda
  useEffect(() => {
    if (typeof window === "undefined") return

    const handleStorageChange = (event: StorageEvent) => {
      // Ignorar mudancas em outras chaves
      if (event.key !== STORAGE_KEY) return
      // Ignorar se nao tem valor novo
      if (!event.newValue) return

      try {
        const state = JSON.parse(event.newValue) as ChatWidgetState
        setIsOpen(state.isOpen)
        setIsMinimized(state.isMinimized)
        setViewMode(state.viewMode ?? "list")
        if (state.activeTicketId) {
          setActiveTicketId(state.activeTicketId)
        }
      } catch {}
    }

    window.addEventListener("storage", handleStorageChange)
    return () => window.removeEventListener("storage", handleStorageChange)
  }, [])

  // Salvar estado no localStorage quando muda (dispara evento storage em outras abas)
  useEffect(() => {
    if (typeof window === "undefined") return

    const state: ChatWidgetState = {
      isOpen,
      isMinimized,
      activeTicketId,
      viewMode,
    }

    // Salvar no localStorage (isso dispara evento storage em outras abas automaticamente)
    try {
      localStorage.setItem(STORAGE_KEY, JSON.stringify(state))
    } catch {}
  }, [isOpen, isMinimized, activeTicketId, viewMode])

  // Auto-selecionar modo e sessao baseado na quantidade de sessoes
  useEffect(() => {
    if (!activeSessions) return

    if (activeSessions.length === 0) {
      // Sem sessoes, limpar estado
      setActiveTicketId(null)
      setViewMode("list")
    } else if (activeSessions.length === 1) {
      // Apenas 1 sessao, ir direto para chat
      setActiveTicketId(activeSessions[0].ticketId)
      setViewMode("chat")
    } else if (!activeTicketId) {
      // Multiplas sessoes mas nenhuma selecionada, mostrar lista
      setViewMode("list")
    }
  }, [activeSessions, activeTicketId])

  // Auto-abrir o widget quando ESTE agente iniciar uma nova sessão de chat.
  // Nao roda na montagem inicial para nao sobrescrever o estado do localStorage.
  useEffect(() => {
    if (!activeSessions) return

    const currentIds = new Set(activeSessions.map((s) => s.sessionId))

    if (!hasInitializedSessionsRef.current) {
      prevSessionIdsRef.current = currentIds
      hasInitializedSessionsRef.current = true
      return
    }

    const newSessions = activeSessions.filter((s) => !prevSessionIdsRef.current.has(s.sessionId))
    prevSessionIdsRef.current = currentIds

    if (newSessions.length === 0) return
    if (!viewerId) return

    const mine = newSessions.find((s) => s.agentId === viewerId) ?? null
    if (!mine) return

    setIsOpen(true)
    setIsMinimized(false)
    setActiveTicketId(mine.ticketId)
  }, [activeSessions, viewerId])

  // Scroll para última mensagem
  useEffect(() => {
    if (messagesEndRef.current && isOpen && !isMinimized) {
      messagesEndRef.current.scrollIntoView({ behavior: "smooth" })
    }
  }, [messages.length, isOpen, isMinimized])

  // Ref para rastrear se ja marcamos como lidas nesta abertura do chat
  const hasMarkedReadRef = useRef<boolean>(false)

  // Reset da flag quando fecha ou minimiza o chat
  useEffect(() => {
    if (!isOpen || isMinimized) {
      hasMarkedReadRef.current = false
    }
  }, [isOpen, isMinimized])

  // Marcar mensagens como lidas ao abrir/mostrar chat
  // Usa um pequeno delay para garantir que o chat carregou
  useEffect(() => {
    // So marca quando o widget esta aberto, expandido e a aba esta ativa
    if (!isOpen || isMinimized) return
    if (!viewerId || !activeTicketId) return
    if (typeof document !== "undefined" && document.visibilityState === "hidden") return

    // Se ainda nao temos chat carregado, aguardar
    if (!chat) return

    // Evitar marcar multiplas vezes na mesma abertura
    if (hasMarkedReadRef.current) return

    const unreadIds = chat.messages
      ?.filter((msg) => !msg.readBy?.some((r) => r.userId === viewerId))
      .map((msg) => msg.id) ?? []

    if (unreadIds.length === 0) {
      // Mesmo sem mensagens nao lidas, marcar que ja processamos
      hasMarkedReadRef.current = true
      return
    }

    // Marcar como lidas com pequeno delay para garantir estabilidade
    const timeoutId = setTimeout(() => {
      markChatRead({
        ticketId: activeTicketId as Id<"tickets">,
        actorId: viewerId as Id<"users">,
        messageIds: unreadIds,
      })
        .then(() => {
          hasMarkedReadRef.current = true
        })
        .catch(console.error)
    }, 100)

    return () => clearTimeout(timeoutId)
  }, [viewerId, chat, activeTicketId, isOpen, isMinimized, markChatRead])

  // Upload de arquivos
  const uploadFiles = useCallback(async (files: File[]) => {
    const maxFiles = MAX_ATTACHMENTS - attachments.length
    const validFiles = files
      .filter(f => f.size <= MAX_ATTACHMENT_SIZE)
      .slice(0, maxFiles)

    if (validFiles.length < files.length) {
      toast.error(`Alguns arquivos ignorados (máx. ${MAX_ATTACHMENTS} arquivos, 5MB cada)`)
    }

    if (validFiles.length === 0) return

    setIsUploading(true)
    try {
      for (const file of validFiles) {
        const uploadUrl = await generateUploadUrl()
        const response = await fetch(uploadUrl, {
          method: "POST",
          headers: { "Content-Type": file.type },
          body: file,
        })
        const { storageId } = await response.json()

        const previewUrl = file.type.startsWith("image/")
          ? URL.createObjectURL(file)
          : undefined

        setAttachments(prev => [...prev, {
          storageId,
          name: file.name,
          size: file.size,
          type: file.type,
          previewUrl,
        }])
      }
    } catch (error) {
      console.error("Erro no upload:", error)
      toast.error("Erro ao enviar arquivo")
    } finally {
      setIsUploading(false)
    }
  }, [attachments.length, generateUploadUrl])

  const handleFileSelect = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = Array.from(e.target.files ?? [])
    if (files.length > 0) {
      await uploadFiles(files)
    }
    e.target.value = ""
  }

  const removeAttachment = (index: number) => {
    setAttachments(prev => {
      const removed = prev[index]
      if (removed?.previewUrl) {
        URL.revokeObjectURL(removed.previewUrl)
      }
      return prev.filter((_, i) => i !== index)
    })
  }

  // Drag and drop handlers
  const handleDragOver = (e: React.DragEvent) => {
    e.preventDefault()
    e.stopPropagation()
    setIsDragging(true)
  }

  const handleDragLeave = (e: React.DragEvent) => {
    e.preventDefault()
    e.stopPropagation()
    if (!dropAreaRef.current?.contains(e.relatedTarget as Node)) {
      setIsDragging(false)
    }
  }

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

    const files = Array.from(e.dataTransfer.files)
    if (files.length > 0) {
      await uploadFiles(files)
    }
  }

  const handleSend = async () => {
    if (!viewerId || !activeTicketId) return
    if (!draft.trim() && attachments.length === 0) return
    if (draft.length > MAX_MESSAGE_LENGTH) {
      toast.error(`Mensagem muito longa (máx. ${MAX_MESSAGE_LENGTH} caracteres).`)
      return
    }

    setIsSending(true)
    try {
      await postChatMessage({
        ticketId: activeTicketId as Id<"tickets">,
        actorId: viewerId as Id<"users">,
        body: draft.trim(),
        attachments: attachments.map(a => ({
          storageId: a.storageId as unknown as Id<"_storage">,
          name: a.name,
          size: a.size,
          type: a.type,
        })),
      })
      setDraft("")
      // Limpar previews
      attachments.forEach(a => {
        if (a.previewUrl) URL.revokeObjectURL(a.previewUrl)
      })
      setAttachments([])
      inputRef.current?.focus()
      // Scroll para o final após enviar (com pequeno delay para garantir que a mensagem foi renderizada)
      setTimeout(() => {
        messagesEndRef.current?.scrollIntoView({ behavior: "smooth" })
      }, 100)
    } catch (error) {
      console.error(error)
      toast.error("Não foi possível enviar a mensagem.")
    } finally {
      setIsSending(false)
    }
  }

  const handleEndChat = async () => {
    if (!viewerId || !liveChat?.activeSession?.sessionId || isEndingChat) return
    setIsEndingChat(true)
    toast.dismiss("live-chat")
    try {
      await endLiveChat({
        sessionId: liveChat.activeSession.sessionId,
        actorId: viewerId as Id<"users">,
      })
      toast.success("Chat ao vivo encerrado.", { id: "live-chat" })
      if (activeSessions && activeSessions.length <= 1) {
        setIsOpen(false)
        setActiveTicketId(null)
      } else {
        const nextSession = activeSessions?.find((s) => s.ticketId !== activeTicketId)
        if (nextSession) {
          setActiveTicketId(nextSession.ticketId)
        }
      }
    } catch (error: unknown) {
      const message = error instanceof Error ? error.message : "Não foi possível encerrar o chat"
      toast.error(message, { id: "live-chat" })
    } finally {
      setIsEndingChat(false)
    }
  }

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === "Enter" && !e.shiftKey) {
      e.preventDefault()
      handleSend()
    }
  }

  // Handlers para navegacao lista/chat
  const handleSelectSession = (ticketId: string) => {
    setActiveTicketId(ticketId)
    setViewMode("chat")
  }

  const handleBackToList = () => {
    setViewMode("list")
  }

  // Nao mostrar se esta no Tauri (usa o chat nativo)
  if (isTauriContext) return null

  // Nao mostrar se nao logado ou sem sessoes
  if (!viewerId) return null
  if (!activeSessions || activeSessions.length === 0) {
    // Limpar estado salvo quando nao ha sessoes
    if (typeof window !== "undefined") {
      try {
        localStorage.removeItem(STORAGE_KEY)
      } catch {}
    }
    return null
  }

  const activeSession = activeSessions.find((s) => s.ticketId === activeTicketId)

  return (
    <div className="fixed bottom-4 right-4 z-50 flex flex-col items-end gap-2">
      {/* Widget aberto */}
      {isOpen && !isMinimized && (
        <div className="flex h-[520px] w-[400px] flex-col overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-2xl">
          {/* Modo Lista - mostra quando viewMode === "list" e ha multiplas sessoes */}
          {viewMode === "list" && activeSessions.length > 1 ? (
            <ChatSessionList
              sessions={activeSessions}
              activeTicketId={activeTicketId}
              onSelectSession={handleSelectSession}
              onClose={() => setIsOpen(false)}
              onMinimize={() => setIsMinimized(true)}
            />
          ) : (
            <>
              {/* Header - Modo Chat */}
              <div className="flex items-center justify-between border-b border-slate-200 bg-white px-4 py-3">
                <div className="flex items-center gap-3">
                  {/* Botao voltar para lista (quando ha multiplas sessoes) */}
                  {activeSessions.length > 1 && (
                    <button
                      onClick={handleBackToList}
                      className="flex size-8 items-center justify-center rounded-lg text-slate-500 hover:bg-slate-100"
                    >
                      <ChevronLeft className="size-5" />
                    </button>
                  )}
                  <div>
                    <div className="flex items-center gap-2">
                      <p className="text-sm font-semibold text-slate-900">
                        #{activeSession?.ticketRef ?? activeTicketId?.slice(-4)}
                      </p>
                      {/* Indicador online/offline */}
                      {liveChat?.hasMachine && (
                        machineOnline ? (
                          <span className="flex items-center gap-1.5 text-xs text-emerald-600">
                            <span className="size-2 rounded-full bg-emerald-500 animate-pulse" />
                            Online
                          </span>
                        ) : (
                          <span className="flex items-center gap-1.5 text-xs text-slate-400">
                            <WifiOff className="size-3" />
                            Offline
                          </span>
                        )
                      )}
                    </div>
                    {activeSession && (
                      <div className="flex flex-col">
                        <a
                          href={`/tickets/${activeTicketId}`}
                          target="_blank"
                          rel="noopener noreferrer"
                          className="group flex items-center gap-1 text-xs text-slate-500 hover:text-slate-900 transition-colors"
                        >
                          <span className="max-w-[160px] truncate">{activeSession.ticketSubject}</span>
                          <ExternalLink className="size-3 opacity-0 group-hover:opacity-100 transition-opacity" />
                        </a>
                        {machineHostname && (
                          <span className="max-w-[140px] truncate text-xs text-slate-400" title={machineHostname}>
                            {machineHostname}
                          </span>
                        )}
                      </div>
                    )}
                  </div>
                </div>
                <div className="flex items-center gap-1">
                  {/* Botao encerrar chat */}
                  <Button
                    variant="ghost"
                    size="sm"
                    onClick={handleEndChat}
                    disabled={isEndingChat}
                    className="gap-1.5 border border-red-300 text-red-600 hover:border-red-400 hover:bg-red-50 hover:text-red-700"
                  >
                    {isEndingChat ? (
                      <Spinner className="size-3.5" />
                    ) : (
                      <XCircle className="size-3.5" />
                    )}
                    <span className="hidden sm:inline">Encerrar</span>
                  </Button>
                  <button
                    onClick={() => setIsMinimized(true)}
                    className="ml-2 rounded-md p-1.5 text-slate-500 hover:bg-slate-100"
                  >
                    <Minimize2 className="size-4" />
                  </button>
                  <button
                    onClick={() => setIsOpen(false)}
                    className="rounded-md p-1.5 text-slate-500 hover:bg-slate-100"
                  >
                    <X className="size-4" />
                  </button>
                </div>
              </div>

          {/* Aviso de máquina offline */}
          {liveChat?.hasMachine && !machineOnline && (
            <div className="border-b border-amber-200 bg-amber-50 px-3 py-2">
              <p className="flex items-center gap-2 text-xs text-amber-700">
                <WifiOff className="size-3" />
                A máquina está offline. Mensagens serão entregues quando voltar.
              </p>
            </div>
          )}

          {/* Mensagens */}
          <div className="flex-1 overflow-y-auto bg-slate-50/50 p-4">
            {!chat ? (
              <div className="flex h-full items-center justify-center">
                <Spinner className="size-6 text-slate-400" />
              </div>
            ) : messages.length === 0 ? (
              <div className="flex h-full flex-col items-center justify-center text-center">
                <div className="flex size-12 items-center justify-center rounded-full bg-slate-100">
                  <MessageCircle className="size-6 text-slate-400" />
                </div>
                <p className="mt-3 text-sm font-medium text-slate-600">Nenhuma mensagem</p>
                <p className="mt-1 text-xs text-slate-400">Envie uma mensagem para o cliente</p>
              </div>
            ) : (
              <div className="space-y-3">
                {messages.map((msg, index) => {
                  const isOwn = String(msg.authorId) === String(viewerId)
                  const bodyText = msg.body?.trim() ?? ""
                  const shouldShowBody =
                    bodyText.length > 0 &&
                    !(bodyText === "[Anexo]" && (msg.attachments?.length ?? 0) > 0)
                  
                  // Verificar se precisa mostrar separador de data
                  const prevMsg = index > 0 ? messages[index - 1] : null
                  const showDateSeparator = !prevMsg || getDateKey(msg.createdAt) !== getDateKey(prevMsg.createdAt)
                  
                  return (
                    <div key={msg.id}>
                      {showDateSeparator && <DateSeparator timestamp={msg.createdAt} />}
                      <div
                        className={cn("flex gap-2", isOwn ? "flex-row-reverse" : "flex-row")}
                    >
                      <div
                        className={cn(
                          "flex size-7 shrink-0 items-center justify-center rounded-full",
                          isOwn ? "bg-black text-white" : "bg-slate-200 text-slate-600"
                        )}
                      >
                        {isOwn ? <MessageCircle className="size-3.5" /> : <User className="size-3.5" />}
                      </div>
                      <div
                        className={cn(
                          "max-w-[75%] rounded-2xl px-3 py-2",
                          isOwn
                            ? "rounded-br-md bg-black text-white"
                            : "rounded-bl-md border border-slate-100 bg-white text-slate-900 shadow-sm"
                        )}
                      >
                        {!isOwn && (
                          <p className="mb-0.5 text-xs font-medium text-slate-500">
                            {msg.authorName ?? "Cliente"}
                          </p>
                        )}
                        {shouldShowBody && <p className="whitespace-pre-wrap text-sm">{msg.body}</p>}
                        {/* Anexos da mensagem */}
                        {msg.attachments && msg.attachments.length > 0 && (
                          <div className={cn("mt-2 flex flex-wrap gap-1.5", isOwn && "justify-end")}>
                            {msg.attachments.map((att, i) => (
                              <MessageAttachment key={i} attachment={att} />
                            ))}
                          </div>
                        )}
                        <p className={cn("mt-1 text-right text-xs", isOwn ? "text-white/60" : "text-slate-400")}>
                          {formatTime(msg.createdAt)}
                        </p>
                      </div>
                    </div>
                    </div>
                  )
                })}
                <div ref={messagesEndRef} />
              </div>
            )}
          </div>

          {/* Preview de anexos pendentes */}
          {attachments.length > 0 && (
            <div className="flex flex-wrap gap-2 border-t border-slate-100 bg-slate-50 p-2">
              {attachments.map((file, index) => (
                <div key={index} className="group relative">
                  {file.type?.startsWith("image/") && file.previewUrl ? (
                    /* eslint-disable-next-line @next/next/no-img-element */
                    <img
                      src={file.previewUrl}
                      alt={file.name}
                      className="size-14 rounded-lg border border-slate-200 object-cover"
                    />
                  ) : (
                    <div className="flex size-14 items-center justify-center rounded-lg border border-slate-200 bg-white">
                      <FileText className="size-5 text-slate-400" />
                    </div>
                  )}
                  <button
                    onClick={() => removeAttachment(index)}
                    className="absolute -right-1.5 -top-1.5 flex size-5 items-center justify-center rounded-full bg-red-500 text-white opacity-0 transition-opacity group-hover:opacity-100"
                  >
                    <X className="size-3" />
                  </button>
                  <p className="mt-0.5 max-w-[56px] truncate text-center text-[10px] text-slate-500">
                    {file.name}
                  </p>
                </div>
              ))}
              {isUploading && (
                <div className="flex size-14 items-center justify-center rounded-lg border border-dashed border-slate-300 bg-slate-50">
                  <Spinner className="size-5 text-slate-400" />
                </div>
              )}
            </div>
          )}

          {/* Input com dropzone */}
          <div
            ref={dropAreaRef}
            className="relative border-t border-slate-200 bg-white p-3"
            onDragOver={handleDragOver}
            onDragLeave={handleDragLeave}
            onDrop={handleDrop}
          >
            {/* Overlay de drag */}
            {isDragging && (
              <div className="absolute inset-0 z-10 flex items-center justify-center rounded-b-2xl border-2 border-dashed border-primary bg-primary/5">
                <p className="text-sm font-medium text-primary">Solte os arquivos aqui</p>
              </div>
            )}

            <div className="flex items-end gap-2">
              <textarea
                ref={inputRef}
                value={draft}
                onChange={(e) => setDraft(e.target.value)}
                onKeyDown={handleKeyDown}
                placeholder="Digite sua mensagem..."
                className="max-h-20 min-h-[36px] flex-1 resize-none rounded-lg border border-slate-200 px-3 py-2 text-sm focus:border-slate-400 focus:outline-none focus:ring-1 focus:ring-slate-400"
                rows={1}
                disabled={isSending}
              />
              {/* Botão de anexar */}
              <Button
                type="button"
                variant="ghost"
                size="icon"
                className="size-9 text-slate-500 hover:bg-slate-100 hover:text-slate-700"
                onClick={() => fileInputRef.current?.click()}
                disabled={attachments.length >= MAX_ATTACHMENTS || isUploading}
              >
                {isUploading ? (
                  <Spinner className="size-4" />
                ) : (
                  <Paperclip className="size-4" />
                )}
              </Button>
              {/* Botão de enviar */}
              <Button
                type="button"
                onClick={handleSend}
                disabled={(!draft.trim() && attachments.length === 0) || isSending}
                className="size-9 bg-black text-white hover:bg-black/90"
                size="icon"
              >
                {isSending ? <Spinner className="size-4" /> : <Send className="size-4" />}
              </Button>
            </div>

            <input
              ref={fileInputRef}
              type="file"
              multiple
              className="hidden"
              onChange={handleFileSelect}
              accept="image/*,.pdf,.doc,.docx,.xls,.xlsx,.txt,.csv"
            />
          </div>
            </>
          )}
        </div>
      )}

      {/* Widget minimizado */}
      {isOpen && isMinimized && (
        <button
          onClick={() => setIsMinimized(false)}
          className="flex items-center gap-2 rounded-full bg-black px-4 py-2 text-white shadow-lg hover:bg-black/90"
        >
          <MessageCircle className="size-4" />
          <span className="text-sm font-medium">
            Chat #{activeSession?.ticketRef}
          </span>
          {/* Indicador online no minimizado */}
          {liveChat?.hasMachine && (
            <span
              className={cn(
                "size-2 rounded-full",
                machineOnline ? "bg-emerald-400" : "bg-slate-400"
              )}
            />
          )}
          {totalUnread > 0 && (
            <span className="flex size-5 items-center justify-center rounded-full bg-red-500 text-xs font-bold">
              {totalUnread}
            </span>
          )}
          <ChevronDown className="size-4" />
        </button>
      )}

      {/* Botão flutuante */}
      {!isOpen && (
        <button
          onClick={() => {
            setIsOpen(true)
            setIsMinimized(false)
          }}
          className="relative flex size-14 items-center justify-center rounded-full bg-black text-white shadow-lg transition-transform hover:scale-105 hover:bg-black/90"
        >
          <MessageCircle className="size-6" />
          {totalUnread > 0 && (
            <>
              {/* Anel pulsante externo */}
              <span className="absolute -right-1 -top-1 flex size-6 items-center justify-center">
                <span className="absolute inline-flex size-full animate-ping rounded-full bg-red-400 opacity-75" />
                <span className="relative flex size-6 items-center justify-center rounded-full bg-red-500 text-xs font-bold text-white">
                  {totalUnread > 99 ? "99+" : totalUnread}
                </span>
              </span>
            </>
          )}
        </button>
      )}
    </div>
  )
}
