"use client"

import { useCallback, useEffect, useMemo, useState } from "react"
import { useAction, useMutation, useQuery } from "convex/react"
import { format, formatDistanceToNow } from "date-fns"
import { ptBR } from "date-fns/locale"
import { Download, FileIcon, MessageCircle, X } from "lucide-react"
import { toast } from "sonner"
import { api } from "@/convex/_generated/api"
import type { Id } from "@/convex/_generated/dataModel"
import { DEFAULT_TENANT_ID } from "@/lib/constants"
import { mapTicketWithDetailsFromServer } from "@/lib/mappers/ticket"
import type { TicketWithDetails } from "@/lib/schemas/ticket"
import { useAuth } from "@/lib/auth-client"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Dialog, DialogClose, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"
import { Dropzone } from "@/components/ui/dropzone"
import { Empty, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "@/components/ui/empty"
import { Skeleton } from "@/components/ui/skeleton"
// removed wrong import; RichTextEditor comes from rich-text-editor
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { sanitizeEditorHtml, RichTextEditor } from "@/components/ui/rich-text-editor"
import { TicketStatusBadge } from "@/components/tickets/status-badge"
import { Spinner } from "@/components/ui/spinner"

const priorityLabel: Record<TicketWithDetails["priority"], string> = {
  LOW: "Baixa",
  MEDIUM: "Média",
  HIGH: "Alta",
  URGENT: "Urgente",
}

const priorityTone: Record<TicketWithDetails["priority"], string> = {
  LOW: "bg-slate-100 text-slate-600",
  MEDIUM: "bg-sky-100 text-sky-700",
  HIGH: "bg-amber-100 text-amber-700",
  URGENT: "bg-rose-100 text-rose-700",
}

function toHtmlFromText(text: string) {
  const escaped = text
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;")
  return `<p>${escaped.replace(/\n/g, "<br />")}</p>`
}

interface PortalTicketDetailProps {
  ticketId: string
}

type ClientTimelineEntry = {
  id: string
  title: string
  description: string | null
  when: Date
}

export function PortalTicketDetail({ ticketId }: PortalTicketDetailProps) {
  const { convexUserId, session, isCustomer, machineContext } = useAuth()
  const addComment = useMutation(api.tickets.addComment)
  const getFileUrl = useAction(api.files.getUrl)
  const [comment, setComment] = useState("")
  const [attachments, setAttachments] = useState<
    Array<{ storageId: string; name: string; size?: number; type?: string; previewUrl?: string }>
  >([])
  const attachmentsTotalBytes = useMemo(
    () => attachments.reduce((acc, item) => acc + (item.size ?? 0), 0),
    [attachments]
  )
  const [previewAttachment, setPreviewAttachment] = useState<{ url: string; name: string; type?: string } | null>(null)
  const isPreviewImage = useMemo(() => {
    if (!previewAttachment) return false
    const type = previewAttachment.type ?? ""
    if (type.startsWith("image/")) return true
    const name = previewAttachment.name ?? ""
    return /\.(png|jpe?g|gif|webp|svg)$/i.test(name)
  }, [previewAttachment])
  const machineInactive = machineContext?.isActive === false

  const ticketRaw = useQuery(
    api.tickets.getById,
    convexUserId
      ? {
          tenantId: session?.user.tenantId ?? DEFAULT_TENANT_ID,
          id: ticketId as Id<"tickets">,
          viewerId: convexUserId as Id<"users">,
        }
      : "skip"
  )

  const ticket = useMemo(() => {
    if (!ticketRaw) return null
    return mapTicketWithDetailsFromServer(ticketRaw)
  }, [ticketRaw])

  const clientTimeline = useMemo(() => {
    if (!ticket) return []
    return ticket.timeline
      .map<ClientTimelineEntry | null>((event) => {
      const payload = (event.payload ?? {}) as Record<string, unknown>
      const actorName = typeof payload.actorName === "string" && payload.actorName.trim().length > 0 ? String(payload.actorName).trim() : null

      if (event.type === "CREATED") {
        const requesterName = typeof payload.requesterName === "string" && payload.requesterName.trim().length > 0
          ? String(payload.requesterName).trim()
          : null
        return {
          id: event.id,
          title: "Chamado criado",
          description: requesterName ? `Aberto por ${requesterName}` : "Chamado registrado",
          when: event.createdAt,
        }
      }

      if (event.type === "QUEUE_CHANGED") {
        const queueNameRaw =
          (typeof payload.queueName === "string" && payload.queueName.trim()) ||
          (typeof payload.toLabel === "string" && payload.toLabel.trim()) ||
          (typeof payload.to === "string" && payload.to.trim()) ||
          null
        if (!queueNameRaw) return null
        const queueName = queueNameRaw.trim()
        const description = actorName ? `Fila ${queueName} • por ${actorName}` : `Fila ${queueName}`
        return {
          id: event.id,
          title: "Fila atualizada",
          description,
          when: event.createdAt,
        }
      }

      if (event.type === "ASSIGNEE_CHANGED") {
        const assigneeName = typeof payload.assigneeName === "string" && payload.assigneeName.trim().length > 0 ? String(payload.assigneeName).trim() : null
        const title = assigneeName ? "Responsável atribuído" : "Responsável atualizado"
        const description = assigneeName ? `Agora com ${assigneeName}` : "Chamado sem responsável no momento"
        return {
          id: event.id,
          title,
          description,
          when: event.createdAt,
        }
      }

      if (event.type === "CATEGORY_CHANGED") {
        const categoryName = typeof payload.categoryName === "string" ? payload.categoryName.trim() : ""
        const subcategoryName = typeof payload.subcategoryName === "string" ? payload.subcategoryName.trim() : ""
        const hasCategory = categoryName.length > 0
        const hasSubcategory = subcategoryName.length > 0
        const description = hasCategory
          ? hasSubcategory
            ? `${categoryName} • ${subcategoryName}`
            : categoryName
          : "Categoria removida"
        return {
          id: event.id,
          title: "Categoria atualizada",
          description,
          when: event.createdAt,
        }
      }

      if (event.type === "COMMENT_ADDED") {
        const matchingComment = ticket.comments.find((comment) => comment.createdAt.getTime() === event.createdAt.getTime())
        if (!matchingComment) {
          return null
        }
        const rawBody = matchingComment.body ?? ""
        const plainBody = rawBody.replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim()
        const summary = plainBody.length > 0 ? (plainBody.length > 140 ? `${plainBody.slice(0, 140)}…` : plainBody) : null
        const author = matchingComment.author.name || actorName || "Equipe"
        const description = summary ?? `Comentário registrado por ${author}`
        return {
          id: event.id,
          title: "Novo comentário",
          description,
          when: event.createdAt,
        }
      }

      if (event.type === "STATUS_CHANGED") {
        const toLabel = typeof payload.toLabel === "string" && payload.toLabel.trim().length > 0 ? String(payload.toLabel).trim() : null
        const toRaw = typeof payload.to === "string" && payload.to.trim().length > 0 ? String(payload.to).trim() : null
        const normalized = (toLabel ?? toRaw ?? "").toUpperCase()
        if (!normalized) return null
        const isFinal = normalized === "RESOLVED" || normalized === "RESOLVIDO" || normalized === "CLOSED" || normalized === "FINALIZADO" || normalized === "FINALIZED"
        if (!isFinal) return null
        const description = `Status alterado para ${toLabel ?? toRaw ?? "Resolvido"}`
        return {
          id: event.id,
          title: normalized === "RESOLVED" || normalized === "RESOLVIDO" ? "Chamado resolvido" : "Chamado finalizado",
          description,
          when: event.createdAt,
        }
      }

      return null
    })
    .filter((entry): entry is ClientTimelineEntry => entry !== null)
    .sort((a, b) => b.when.getTime() - a.when.getTime())
}, [ticket])

  if (ticketRaw === undefined) {
    return (
      <Card className="rounded-2xl border border-slate-200 bg-white shadow-sm">
        <CardHeader className="px-5 py-5">
          <CardTitle className="text-lg font-semibold text-neutral-900">Carregando ticket...</CardTitle>
        </CardHeader>
        <CardContent className="space-y-3 px-5 pb-6">
          <Skeleton className="h-6 w-2/3" />
          <Skeleton className="h-4 w-full" />
          <Skeleton className="h-4 w-5/6" />
        </CardContent>
      </Card>
    )
  }

  if (!ticket) {
    return (
      <Empty>
        <EmptyHeader>
          <EmptyMedia variant="icon">
            <span className="text-2xl">🔍</span>
          </EmptyMedia>
          <EmptyTitle className="text-neutral-900">Ticket não encontrado</EmptyTitle>
          <EmptyDescription className="text-neutral-600">
            Verifique o endereço ou retorne à lista de chamados.
          </EmptyDescription>
        </EmptyHeader>
      </Empty>
    )
  }

  const createdAt = format(ticket.createdAt, "dd 'de' MMMM 'de' yyyy 'às' HH:mm", { locale: ptBR })
  const updatedAgo = formatDistanceToNow(ticket.updatedAt, { addSuffix: true, locale: ptBR })
  async function handleSubmit(event: React.FormEvent) {
    event.preventDefault()
    if (machineInactive) {
      toast.error("Esta máquina está desativada. Reative-a para enviar novas mensagens.")
      return
    }
    if (!convexUserId || !ticket) return
    const trimmed = comment.trim()
    const hasText = trimmed.length > 0
    if (!hasText && attachments.length === 0) {
      toast.error("Adicione uma mensagem ou anexe ao menos um arquivo antes de enviar.")
      return
    }
    const toastId = "portal-add-comment"
    toast.loading("Enviando comentário...", { id: toastId })
    try {
      const htmlBody = hasText ? sanitizeEditorHtml(toHtmlFromText(trimmed)) : "<p></p>"
      await addComment({
        ticketId: ticket.id as Id<"tickets">,
        authorId: convexUserId as Id<"users">,
        visibility: "PUBLIC",
        body: htmlBody,
        attachments: attachments.map((f) => ({
          storageId: f.storageId as Id<"_storage">,
          name: f.name,
          size: f.size,
          type: f.type,
        })),
      })
      setComment("")
      attachments.forEach((file) => {
        if (file.previewUrl?.startsWith("blob:")) {
          try {
            URL.revokeObjectURL(file.previewUrl)
          } catch {
            // ignore revoke issues
          }
        }
      })
      setAttachments([])
      toast.success("Comentário enviado!", { id: toastId })
    } catch (error) {
      console.error(error)
      toast.error("Não foi possível enviar o comentário.", { id: toastId })
    }
  }

  return (
    <div className="space-y-6">
      <Card className="rounded-2xl border border-slate-200 bg-white shadow-sm">
        <CardHeader className="px-5 pb-3 pt-6">
          <div className="flex flex-wrap items-start justify-between gap-4">
            <div>
              <p className="text-sm text-neutral-500">Ticket #{ticket.reference}</p>
              <h1 className="mt-1 text-2xl font-semibold text-neutral-900">{ticket.subject}</h1>
              {ticket.summary ? (
                <p className="mt-2 max-w-3xl text-sm text-neutral-600">{ticket.summary}</p>
              ) : null}
            </div>
            <div className="flex flex-col items-end gap-2 text-sm">
              <TicketStatusBadge status={ticket.status} className="px-3 py-1 text-xs font-semibold uppercase" />
              {!isCustomer ? (
                <Badge className={`rounded-full px-3 py-1 text-xs font-semibold uppercase ${priorityTone[ticket.priority]}`}>
                  {priorityLabel[ticket.priority]}
                </Badge>
              ) : null}
            </div>
          </div>
        </CardHeader>
        <CardContent className="grid gap-4 border-t border-slate-100 px-5 py-5 text-sm text-neutral-700 sm:grid-cols-2">
          {isCustomer ? null : <DetailItem label="Fila" value={ticket.queue ?? "Sem fila"} />}
          <DetailItem label="Categoria" value={ticket.category?.name ?? "Não classificada"} />
          <DetailItem label="Subcategoria" value={ticket.subcategory?.name ?? "—"} />
          <DetailItem label="Solicitante" value={ticket.requester.name} subtitle={ticket.requester.email} />
          {ticket.assignee ? (
            <DetailItem label="Responsável" value={ticket.assignee.name} />
          ) : null}
          <DetailItem label="Criado em" value={createdAt} />
          <DetailItem label="Última atualização" value={updatedAgo} />
        </CardContent>
      </Card>

      <div className="grid gap-6 lg:grid-cols-[minmax(0,2fr)_minmax(0,1fr)]">
        <Card className="rounded-2xl border border-slate-200 bg-white shadow-sm">
          <CardHeader className="flex flex-row items-center justify-between px-5 py-4">
            <CardTitle className="flex items-center gap-2 text-lg font-semibold text-neutral-900">
              <MessageCircle className="size-5 text-neutral-500" /> Conversas
            </CardTitle>
          </CardHeader>
          <CardContent className="space-y-6 px-5 pb-6">
            {machineInactive ? (
              <div className="rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-700">
                Esta máquina está desativada. Ative-a novamente para enviar novas mensagens.
              </div>
            ) : null}
            <form onSubmit={handleSubmit} className="space-y-4">
              <div className="space-y-5">
                <label htmlFor="comment" className="block text-sm font-medium text-neutral-800">
                  Enviar uma mensagem para a equipe
                </label>
                <RichTextEditor
                  value={comment}
                  onChange={(html) => setComment(html)}
                  placeholder="Descreva o que aconteceu, envie atualizações ou compartilhe novas informações."
                  className="mt-3 rounded-2xl border border-slate-200 shadow-sm focus-within:border-neutral-900 focus-within:ring-neutral-900/20"
                  disabled={machineInactive}
                />
              </div>
              <div className="space-y-2">
                <Dropzone
                  onUploaded={(files) => setAttachments((prev) => [...prev, ...files])}
                  className="rounded-xl border border-dashed border-slate-300 bg-slate-50 px-3 py-4 text-sm text-neutral-600 shadow-inner"
                  currentFileCount={attachments.length}
                  currentTotalBytes={attachmentsTotalBytes}
                  disabled={machineInactive}
                />
                {attachments.length > 0 ? (
                  <div className="grid max-w-xl grid-cols-[repeat(auto-fill,minmax(96px,1fr))] gap-3">
                    {attachments.map((attachment, index) => {
                      const isImage =
                        (attachment.type ?? "").startsWith("image/") ||
                        /\.(png|jpe?g|gif|webp|svg)$/i.test(attachment.name)
                      return (
                        <div
                          key={`${attachment.storageId}-${index}`}
                          className="group relative overflow-hidden rounded-lg border border-slate-200 bg-white p-0.5"
                        >
                          {isImage && attachment.previewUrl ? (
                            <div className="block w-full overflow-hidden rounded-md">
                              {/* eslint-disable-next-line @next/next/no-img-element */}
                              <img
                                src={attachment.previewUrl}
                                alt={attachment.name}
                                className="h-24 w-full rounded-md object-cover"
                              />
                            </div>
                          ) : (
                            <div className="flex h-24 w-full flex-col items-center justify-center gap-2 rounded-md bg-slate-50 text-xs text-neutral-600">
                              <FileIcon className="size-4" />
                              <span className="line-clamp-2 px-2 text-center">{attachment.name}</span>
                            </div>
                          )}
                          <button
                            type="button"
                            onClick={() =>
                              setAttachments((prev) => {
                                const next = [...prev]
                                const removed = next.splice(index, 1)[0]
                                if (removed?.previewUrl?.startsWith("blob:")) {
                                  URL.revokeObjectURL(removed.previewUrl)
                                }
                                return next
                              })
                            }
                            className="absolute right-1.5 top-1.5 inline-flex size-7 items-center justify-center rounded-full border border-black bg-black text-white transition hover:bg-[#18181b]/85 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black/30"
                            aria-label={`Remover ${attachment.name}`}
                          >
                            <X className="size-3.5" />
                          </button>
                          <div className="mt-1 line-clamp-1 w-full text-ellipsis text-center text-[11px] text-neutral-500">
                            {attachment.name}
                          </div>
                        </div>
                      )
                    })}
                  </div>
                ) : null}
              </div>
              <div className="flex justify-end">
                <Button type="submit" disabled={machineInactive} className="rounded-full bg-neutral-900 px-6 text-sm font-semibold text-white hover:bg-neutral-900/90 disabled:opacity-60">
                  Enviar comentário
                </Button>
              </div>
            </form>

            <div className="space-y-5">
              {ticket.comments.length === 0 ? (
                <Empty>
                  <EmptyHeader>
                    <EmptyMedia variant="icon">
                      <MessageCircle className="size-5 text-neutral-500" />
                    </EmptyMedia>
                    <EmptyTitle className="text-neutral-900">Nenhum comentário ainda</EmptyTitle>
                    <EmptyDescription className="text-neutral-600">
                      Registre a primeira atualização acima.
                    </EmptyDescription>
                  </EmptyHeader>
                </Empty>
              ) : (
                ticket.comments.map((commentItem) => {
                  const initials = commentItem.author.name
                    .split(" ")
                    .slice(0, 2)
                    .map((part) => part.charAt(0).toUpperCase())
                    .join("")
                  const createdAgo = formatDistanceToNow(commentItem.createdAt, {
                    addSuffix: true,
                    locale: ptBR,
                  })
                  return (
                    <div key={commentItem.id} className="rounded-xl border border-slate-100 bg-slate-50/70 p-4">
                      <div className="flex items-center justify-between gap-3">
                        <div className="flex items-center gap-3">
                          <Avatar className="size-9 border border-slate-200">
                            <AvatarImage src={commentItem.author.avatarUrl} alt={commentItem.author.name} />
                            <AvatarFallback>{initials}</AvatarFallback>
                          </Avatar>
                          <div className="flex flex-col">
                            <span className="text-sm font-semibold text-neutral-900">{commentItem.author.name}</span>
                            <span className="text-xs text-neutral-500">{createdAgo}</span>
                          </div>
                        </div>
                      </div>
                      <div
                        className="prose prose-sm mt-3 max-w-none text-neutral-800"
                        dangerouslySetInnerHTML={{ __html: sanitizeEditorHtml(commentItem.body ?? "") }}
                      />
                      {commentItem.attachments && commentItem.attachments.length > 0 ? (
                        <div className="mt-3 grid grid-cols-[repeat(auto-fill,minmax(120px,1fr))] gap-3">
                          {commentItem.attachments.map((attachment) => (
                            <PortalCommentAttachmentCard
                              key={attachment.id}
                              attachment={attachment}
                              getFileUrl={getFileUrl}
                              onOpenPreview={(payload) => setPreviewAttachment(payload)}
                            />
                          ))}
                        </div>
                      ) : null}
                    </div>
                  )
                })
              )}
            </div>
          </CardContent>
        </Card>

        <Card className="rounded-2xl border border-slate-200 bg-white shadow-sm">
          <CardHeader className="px-5 py-4">
            <CardTitle className="text-lg font-semibold text-neutral-900">Linha do tempo</CardTitle>
          </CardHeader>
          <CardContent className="space-y-5 px-5 pb-6 text-sm text-neutral-700">
            {clientTimeline.length === 0 ? (
              <p className="text-sm text-neutral-500">Nenhum evento registrado ainda.</p>
            ) : (
              clientTimeline.map((event) => {
                const when = formatDistanceToNow(event.when, { addSuffix: true, locale: ptBR })
                return (
                  <div key={event.id} className="flex flex-col gap-1 rounded-xl border border-slate-100 bg-slate-50/50 p-3">
                    <span className="text-sm font-semibold text-neutral-900">{event.title}</span>
                    {event.description ? (
                      <span className="text-xs text-neutral-600">{event.description}</span>
                    ) : null}
                    <span className="text-xs text-neutral-500">{when}</span>
                  </div>
                )
              })
            )}
          </CardContent>
        </Card>
      </div>
      <Dialog open={!!previewAttachment} onOpenChange={(open) => { if (!open) setPreviewAttachment(null) }}>
        <DialogContent className="max-w-3xl border border-slate-200 p-0">
          <DialogHeader className="relative px-4 py-3">
            <DialogTitle className="pr-10 text-base font-semibold text-neutral-800">
              {previewAttachment?.name ?? "Visualização do anexo"}
            </DialogTitle>
            <DialogClose className="absolute right-4 top-3 inline-flex size-7 items-center justify-center rounded-full border border-slate-200 bg-white text-neutral-600 transition hover:bg-slate-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-400/30">
              <X className="size-4" />
            </DialogClose>
          </DialogHeader>
          {previewAttachment ? (
            isPreviewImage ? (
              <div className="rounded-b-2xl bg-neutral-900/5">
                {/* eslint-disable-next-line @next/next/no-img-element */}
                <img src={previewAttachment.url} alt={previewAttachment.name ?? "Anexo"} className="h-auto w-full rounded-b-2xl" />
              </div>
            ) : (
              <div className="space-y-3 px-6 pb-6 text-sm text-neutral-700">
                <p>Não é possível visualizar este tipo de arquivo aqui. Abra em uma nova aba para conferi-lo.</p>
                <a
                  href={previewAttachment.url}
                  target="_blank"
                  rel="noopener noreferrer"
                  className="inline-flex items-center gap-2 rounded-full border border-slate-200 bg-white px-4 py-2 text-sm font-semibold text-neutral-800 transition hover:bg-slate-100"
                >
                  Abrir em nova aba
                </a>
              </div>
            )
          ) : null}
        </DialogContent>
      </Dialog>
    </div>
  )
}

interface DetailItemProps {
  label: string
  value: string
  subtitle?: string | null
}

function DetailItem({ label, value, subtitle }: DetailItemProps) {
  return (
    <div className="rounded-xl border border-dashed border-slate-200 bg-white/60 px-4 py-3 shadow-[0_1px_2px_rgba(15,23,42,0.04)]">
      <p className="text-xs uppercase tracking-wide text-neutral-500">{label}</p>
      <p className="text-sm font-medium text-neutral-900">{value}</p>
      {subtitle ? <p className="text-xs text-neutral-500">{subtitle}</p> : null}
    </div>
  )
}

type CommentAttachment = TicketWithDetails["comments"][number]["attachments"][number]
type GetFileUrlAction = (args: { storageId: Id<"_storage"> }) => Promise<string | null>

function PortalCommentAttachmentCard({
  attachment,
  getFileUrl,
  onOpenPreview,
}: {
  attachment: CommentAttachment
  getFileUrl: GetFileUrlAction
  onOpenPreview: (payload: { url: string; name: string; type?: string }) => void
}) {
  const [url, setUrl] = useState<string | null>(attachment.url ?? null)
  const [loading, setLoading] = useState(false)
  const [errored, setErrored] = useState(false)

  const isImageType = useMemo(() => {
    const name = attachment.name ?? ""
    const type = attachment.type ?? ""
    return type.startsWith("image/") || /\.(png|jpe?g|gif|webp|svg)$/i.test(name)
  }, [attachment.name, attachment.type])

  const ensureUrl = useCallback(async () => {
    if (url) return url
    try {
      setLoading(true)
      const fresh = await getFileUrl({ storageId: attachment.id as Id<"_storage"> })
      if (fresh) {
        setUrl(fresh)
        setErrored(false)
        return fresh
      }
      setErrored(true)
    } catch (error) {
      console.error("Falha ao obter URL do anexo", error)
      setErrored(true)
    } finally {
      setLoading(false)
    }
    return null
  }, [attachment.id, getFileUrl, url])

  useEffect(() => {
    if (attachment.url) {
      setUrl(attachment.url)
      setErrored(false)
      return
    }
    if (isImageType) {
      void ensureUrl()
    }
  }, [attachment.url, ensureUrl, isImageType])

  const handlePreview = useCallback(async () => {
    const target = await ensureUrl()
    if (!target) return
    if (isImageType) {
      onOpenPreview({ url: target, name: attachment.name ?? "Anexo", type: attachment.type ?? undefined })
      return
    }
    window.open(target, "_blank", "noopener,noreferrer")
  }, [attachment.name, attachment.type, ensureUrl, isImageType, onOpenPreview])

  const handleDownload = useCallback(async () => {
    const target = await ensureUrl()
    if (!target) return
    const toastId = `portal-attachment-download-${attachment.id}`
    toast.loading("Baixando anexo...", { id: toastId })
    try {
      const response = await fetch(target, { credentials: "include" })
      if (!response.ok) {
        throw new Error(`Unexpected status ${response.status}`)
      }
      const blob = await response.blob()
      const blobUrl = window.URL.createObjectURL(blob)
      const link = document.createElement("a")
      link.href = blobUrl
      link.download = attachment.name ?? "anexo"
      link.rel = "noopener noreferrer"
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
      window.setTimeout(() => {
        window.URL.revokeObjectURL(blobUrl)
      }, 1000)
      toast.success("Download concluído!", { id: toastId })
    } catch (error) {
      console.error("Falha ao iniciar download do anexo", error)
      window.open(target, "_blank", "noopener,noreferrer")
      toast.error("Não foi possível baixar o anexo automaticamente.", { id: toastId })
    }
  }, [attachment.name, ensureUrl])

  const resolvedUrl = url

  return (
    <div className="group relative overflow-hidden rounded-lg border border-slate-200 bg-white p-0.5 shadow-sm">
      {isImageType && resolvedUrl ? (
        <button
          type="button"
          onClick={handlePreview}
          className="relative block w-full overflow-hidden rounded-md"
        >
          {loading ? (
            <div className="absolute inset-0 flex items-center justify-center bg-white/70">
              <Spinner className="size-5 text-neutral-600" />
            </div>
          ) : null}
          {/* eslint-disable-next-line @next/next/no-img-element */}
          <img src={resolvedUrl} alt={attachment.name ?? "Anexo"} className="h-24 w-full rounded-md object-cover" />
        </button>
      ) : (
        <button
          type="button"
          onClick={handleDownload}
          className="flex h-24 w-full flex-col items-center justify-center gap-2 rounded-md bg-slate-50 text-xs text-neutral-700 transition hover:bg-slate-100"
          disabled={loading}
        >
          {loading ? <Spinner className="size-5 text-neutral-600" /> : <FileIcon className="size-5 text-neutral-600" />}
          <span className="font-medium">
            {errored ? "Gerar link novamente" : "Baixar"}
          </span>
        </button>
      )}
      <button
        type="button"
        onClick={handleDownload}
        className="absolute left-1.5 top-1.5 inline-flex size-7 items-center justify-center rounded-full border border-black bg-black text-white transition hover:bg-[#18181b]/85 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black/30"
        aria-label={`Baixar ${attachment.name ?? "anexo"}`}
      >
        <Download className="size-3.5" />
      </button>
      <div className="mt-1 line-clamp-2 w-full text-ellipsis text-center text-[11px] text-neutral-500">
        {attachment.name}
      </div>
    </div>
  )
}







