// @File: frontend/src/components/chat/ChatWidget.tsx
// @Desc: Floating visitor chat widget. Starts a conversation, posts visitor
//        messages, triggers AI replies, polls for new messages so a human
//        handover is received live, and surfaces a simple "talk to human"
//        button. Mounted globally from App.tsx. Reads branding settings from
//        /api/v1/chat/branding and applies them via CSS variables so admin
//        changes go live within seconds.
import React, {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from "react";
import { createClient } from "@metagptx/web-sdk";
import {
  MessageCircle,
  Send,
  X,
  Loader2,
  UserCircle2,
  Sparkles,
  Headset,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Badge } from "@/components/ui/badge";
import { cn } from "@/lib/utils";

interface ChatMessage {
  id: number;
  sender_type: "visitor" | "ai" | "agent" | "system";
  sender_name?: string | null;
  content: string;
  ai_confidence?: number | null;
  created_at?: string | null;
  is_internal_note?: boolean;
}

interface Conversation {
  id: number;
  status: string;
  priority: string;
  assigned_seat_id?: number | null;
  visitor_name?: string;
  linked_ticket_id?: number | null;
}

interface Branding {
  widget_name: string;
  avatar_url: string;
  avatar_fallback_initials: string;
  agent_avatar_url: string;
  primary_color: string;
  accent_color: string;
  bubble_bg_color: string;
  bubble_text_color: string;
  header_bg_color: string;
  header_text_color: string;
  launcher_style: string;
  launcher_icon: string;
  launcher_icon_url: string;
  launcher_position: string;
  welcome_message: string;
  offline_message: string;
  ai_intro_message: string;
  human_handover_message: string;
  input_placeholder: string;
  show_branding_footer: boolean;
  footer_text: string;
  enable_sound: boolean;
  notification_sound: string;
  theme_mode: string;
  rounded: string;
  font_family: string;
}

const DEFAULT_BRANDING: Branding = {
  widget_name: "DoitEasy Support",
  avatar_url: "/logo.svg",
  avatar_fallback_initials: "DE",
  agent_avatar_url: "",
  primary_color: "#059669",
  accent_color: "#10b981",
  bubble_bg_color: "#ffffff",
  bubble_text_color: "#0f172a",
  header_bg_color: "#059669",
  header_text_color: "#ffffff",
  launcher_style: "circle",
  launcher_icon: "chat",
  launcher_icon_url: "",
  launcher_position: "bottom-right",
  welcome_message:
    "Hi {client_name}! {time_of_day} 👋 How can we help you today?",
  offline_message:
    "We're currently offline. Leave a message and we'll reply by email.",
  ai_intro_message:
    "Hi there! I'm the DoitEasy AI assistant. Ask me anything — I'll answer instantly, and hand you to a human when needed.",
  human_handover_message: "Connecting you to a human agent now…",
  input_placeholder: "Type a message…",
  show_branding_footer: true,
  footer_text: "Powered by DoitEasy ✦ AI + Human support",
  enable_sound: true,
  notification_sound: "soft_chime",
  theme_mode: "light",
  rounded: "lg",
  font_family: "Inter",
};

const STORAGE_KEY = "doiteasy_chat_state_v1";
const BRANDING_REFRESH_MS = 60000;

function loadState(): { conversationId?: number; name?: string; email?: string } {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (!raw) return {};
    return JSON.parse(raw);
  } catch {
    return {};
  }
}

function saveState(state: {
  conversationId?: number;
  name?: string;
  email?: string;
}) {
  try {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
  } catch {
    /* ignore quota errors */
  }
}

function resolveTimeOfDay(): string {
  const h = new Date().getHours();
  if (h < 5) return "Good night";
  if (h < 12) return "Good morning";
  if (h < 18) return "Good afternoon";
  return "Good evening";
}

function applyBrandingVariables(text: string, clientName: string): string {
  return (text || "")
    .replaceAll("{client_name}", clientName || "there")
    .replaceAll("{time_of_day}", resolveTimeOfDay());
}

function roundedToClass(r: string): string {
  switch (r) {
    case "none":
      return "rounded-none";
    case "sm":
      return "rounded-md";
    case "md":
      return "rounded-lg";
    case "lg":
      return "rounded-2xl";
    case "xl":
      return "rounded-3xl";
    default:
      return "rounded-2xl";
  }
}

function launcherShapeClass(s: string): string {
  switch (s) {
    case "pill":
      return "rounded-full px-5 h-12 min-w-[3rem]";
    case "square":
      return "rounded-xl h-14 w-14";
    default:
      return "rounded-full h-14 w-14";
  }
}

function LauncherIcon({
  icon,
  iconUrl,
  color,
  open,
}: {
  icon: string;
  iconUrl: string;
  color: string;
  open: boolean;
}) {
  if (open) return <X className="h-6 w-6" style={{ color }} />;
  if (icon === "custom_upload" && iconUrl) {
    return <img src={iconUrl} alt="chat" className="h-6 w-6" />;
  }
  const cls = "h-6 w-6";
  if (icon === "sparkles") return <Sparkles className={cls} style={{ color }} />;
  if (icon === "headset") return <Headset className={cls} style={{ color }} />;
  return <MessageCircle className={cls} style={{ color }} />;
}

export default function ChatWidget() {
  const client = useMemo(() => createClient(), []);
  const [open, setOpen] = useState(false);
  const [stage, setStage] = useState<"prechat" | "chatting">("prechat");
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");
  const [subject, setSubject] = useState("");
  const [firstMessage, setFirstMessage] = useState("");
  const [conv, setConv] = useState<Conversation | null>(null);
  const [messages, setMessages] = useState<ChatMessage[]>([]);
  const [draft, setDraft] = useState("");
  const [sending, setSending] = useState(false);
  const [loadingReply, setLoadingReply] = useState(false);
  const [starting, setStarting] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [branding, setBranding] = useState<Branding>(DEFAULT_BRANDING);
  const [clientName, setClientName] = useState<string>("");
  const scrollerRef = useRef<HTMLDivElement | null>(null);
  const pollRef = useRef<number | null>(null);
  const brandingPollRef = useRef<number | null>(null);
  const introSeededRef = useRef(false);

  // Fetch branding on mount and on a light interval so admin changes appear fast.
  const fetchBranding = useCallback(async () => {
    try {
      const res = await client.apiCall.invoke({
        url: "/api/v1/chat/branding",
        method: "GET",
        data: {},
      });
      if (res?.data?.branding) {
        setBranding({ ...DEFAULT_BRANDING, ...res.data.branding });
      }
    } catch {
      /* silent — keep defaults */
    }
  }, [client]);

  useEffect(() => {
    fetchBranding();
    brandingPollRef.current = window.setInterval(
      fetchBranding,
      BRANDING_REFRESH_MS
    );
    return () => {
      if (brandingPollRef.current) {
        window.clearInterval(brandingPollRef.current);
        brandingPollRef.current = null;
      }
    };
  }, [fetchBranding]);

  // Try to pick up the logged-in client's display name for {client_name}.
  useEffect(() => {
    (async () => {
      try {
        const res = await client.auth.me();
        const u: any = res?.data;
        const n =
          u?.display_name ||
          u?.name ||
          u?.full_name ||
          u?.email?.split?.("@")?.[0] ||
          "";
        if (n) setClientName(n);
      } catch {
        /* guest */
      }
    })();
  }, [client]);

  // Restore on mount: if a conversation id is cached, jump straight to chat mode.
  useEffect(() => {
    const cached = loadState();
    if (cached.name) setName(cached.name);
    if (cached.email) setEmail(cached.email);
    if (cached.conversationId) {
      setStarting(true);
      (async () => {
        try {
          const res = await client.apiCall.invoke({
            url: `/api/v1/chat/conversations/${cached.conversationId}`,
            method: "GET",
            data: {},
          });
          const c: Conversation | undefined = res?.data?.conversation;
          if (c) {
            setConv(c);
            setStage("chatting");
            await refreshMessages(c.id);
          }
        } catch {
          saveState({ name: cached.name, email: cached.email });
        } finally {
          setStarting(false);
        }
      })();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // Poll for new messages when open and in chat mode (simple polling, every 5s).
  useEffect(() => {
    if (!open || stage !== "chatting" || !conv) return;
    pollRef.current = window.setInterval(() => {
      refreshMessages(conv.id).catch(() => undefined);
    }, 5000);
    return () => {
      if (pollRef.current) {
        window.clearInterval(pollRef.current);
        pollRef.current = null;
      }
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open, stage, conv?.id]);

  useEffect(() => {
    if (scrollerRef.current) {
      scrollerRef.current.scrollTop = scrollerRef.current.scrollHeight;
    }
  }, [messages.length, open]);

  async function refreshMessages(convId: number) {
    try {
      const [msgsRes, convRes] = await Promise.all([
        client.apiCall.invoke({
          url: `/api/v1/chat/conversations/${convId}/messages`,
          method: "GET",
          data: { include_internal: false },
        }),
        client.apiCall.invoke({
          url: `/api/v1/chat/conversations/${convId}`,
          method: "GET",
          data: {},
        }),
      ]);
      setMessages(msgsRes?.data?.items || []);
      if (convRes?.data?.conversation) {
        setConv(convRes.data.conversation);
      }
    } catch (err) {
      // Silent — polling failures shouldn't hammer the UI with errors.
    }
  }

  async function startConversation(e?: React.FormEvent) {
    e?.preventDefault();
    setError(null);
    if (!firstMessage.trim()) {
      setError("Please tell us what you need help with.");
      return;
    }
    setStarting(true);
    try {
      const res = await client.apiCall.invoke({
        url: "/api/v1/chat/conversations",
        method: "POST",
        data: {
          visitor_name: name.trim() || clientName || "Guest",
          visitor_email: email.trim() || undefined,
          subject: subject.trim() || undefined,
          initial_message: firstMessage.trim(),
        },
      });
      const c: Conversation | undefined = res?.data?.conversation;
      if (!c) {
        throw new Error("Failed to start conversation.");
      }
      setConv(c);
      saveState({
        conversationId: c.id,
        name: name.trim(),
        email: email.trim(),
      });
      setStage("chatting");
      introSeededRef.current = false;
      await refreshMessages(c.id);
      triggerAIReply(c.id).catch(() => undefined);
    } catch (err: any) {
      setError(
        err?.data?.detail ||
          err?.message ||
          "Unable to start chat right now. Please try again."
      );
    } finally {
      setStarting(false);
    }
  }

  async function triggerAIReply(convId: number) {
    setLoadingReply(true);
    try {
      const res = await client.apiCall.invoke({
        url: `/api/v1/chat/conversations/${convId}/ai-reply`,
        method: "POST",
        data: {},
      });
      if (res?.data?.conversation) setConv(res.data.conversation);
      await refreshMessages(convId);
    } catch {
      /* non-fatal */
    } finally {
      setLoadingReply(false);
    }
  }

  async function sendDraft() {
    if (!draft.trim() || !conv) return;
    const text = draft.trim();
    setDraft("");
    setSending(true);
    const optimistic: ChatMessage = {
      id: Date.now(),
      sender_type: "visitor",
      sender_name: conv.visitor_name || name || "You",
      content: text,
      created_at: new Date().toISOString(),
    };
    setMessages((prev) => [...prev, optimistic]);
    try {
      await client.apiCall.invoke({
        url: `/api/v1/chat/conversations/${conv.id}/messages`,
        method: "POST",
        data: { content: text, sender_type: "visitor" },
      });
      if (conv.status === "ai") {
        triggerAIReply(conv.id).catch(() => undefined);
      } else {
        refreshMessages(conv.id).catch(() => undefined);
      }
    } catch (err: any) {
      setError(
        err?.data?.detail ||
          err?.message ||
          "Message failed to send. Please retry."
      );
    } finally {
      setSending(false);
    }
  }

  async function requestHuman() {
    if (!conv) return;
    try {
      await client.apiCall.invoke({
        url: `/api/v1/chat/conversations/${conv.id}/messages`,
        method: "POST",
        data: {
          content: "I'd like to talk to a human agent please.",
          sender_type: "visitor",
        },
      });
      await triggerAIReply(conv.id);
      await refreshMessages(conv.id);
    } catch {
      setError("Unable to escalate right now.");
    }
  }

  function resetAndClose() {
    setOpen(false);
    setStage("prechat");
    setConv(null);
    setMessages([]);
    setDraft("");
    setFirstMessage("");
    setSubject("");
    saveState({ name, email });
  }

  const statusLabel = conv?.status
    ? conv.status === "ai"
      ? "AI Assistant"
      : conv.status === "queued"
      ? "Waiting for agent"
      : conv.status === "assigned"
      ? "Connected to agent"
      : conv.status === "resolved"
      ? "Resolved"
      : "Closed"
    : "AI Assistant";

  const resolvedWelcome = applyBrandingVariables(
    branding.welcome_message,
    clientName
  );
  const resolvedIntro = applyBrandingVariables(
    branding.ai_intro_message,
    clientName
  );

  const roundedCls = roundedToClass(branding.rounded);
  const launcherSideClass =
    branding.launcher_position === "bottom-left" ? "left-6" : "right-6";
  const panelSideClass =
    branding.launcher_position === "bottom-left"
      ? "left-4 sm:left-6"
      : "right-4 sm:right-6";

  const isDark = branding.theme_mode === "dark";
  const panelBg = isDark ? "#0f172a" : "#ffffff";
  const panelText = isDark ? "#f1f5f9" : "#0f172a";
  const bodyBg = isDark ? "#111827" : "#f8fafc";
  const aiBubbleBg = isDark ? "#1f2937" : "#ffffff";
  const aiBubbleText = isDark ? "#e2e8f0" : "#0f172a";

  const fontFamily =
    branding.font_family && branding.font_family !== "System"
      ? branding.font_family
      : undefined;

  return (
    <>
      {/* Floating button */}
      <button
        type="button"
        onClick={() => setOpen((v) => !v)}
        aria-label="Open chat support"
        className={cn(
          "fixed bottom-6 z-[70] flex items-center justify-center shadow-2xl transition-transform hover:scale-110",
          launcherSideClass,
          launcherShapeClass(branding.launcher_style)
        )}
        style={{ backgroundColor: branding.primary_color }}
      >
        <LauncherIcon
          icon={branding.launcher_icon}
          iconUrl={branding.launcher_icon_url}
          color={branding.header_text_color}
          open={open}
        />
        {!open && branding.launcher_style === "pill" && (
          <span
            className="ml-2 text-sm font-semibold"
            style={{ color: branding.header_text_color }}
          >
            Chat
          </span>
        )}
      </button>

      {/* Widget panel */}
      {open && (
        <div
          className={cn(
            "fixed bottom-24 z-[70] flex w-[360px] max-w-[calc(100vw-2rem)] flex-col border border-border shadow-2xl overflow-hidden",
            panelSideClass,
            roundedCls,
            "h-[560px] max-h-[calc(100vh-8rem)]"
          )}
          style={{ backgroundColor: panelBg, color: panelText, fontFamily }}
        >
          {/* Header */}
          <div
            className="flex items-center justify-between px-4 py-3"
            style={{
              backgroundColor: branding.header_bg_color,
              color: branding.header_text_color,
            }}
          >
            <div className="flex min-w-0 items-center gap-2">
              <div className="h-8 w-8 shrink-0 overflow-hidden rounded-full bg-white/20 flex items-center justify-center text-[11px] font-bold">
                {branding.avatar_url ? (
                  <img
                    src={branding.avatar_url}
                    alt="avatar"
                    className="h-full w-full object-cover"
                  />
                ) : (
                  branding.avatar_fallback_initials || (
                    <UserCircle2 className="h-6 w-6" />
                  )
                )}
              </div>
              <div className="flex min-w-0 flex-col leading-tight">
                <span
                  className="truncate whitespace-nowrap text-sm font-semibold"
                  title={branding.widget_name}
                >
                  {branding.widget_name}
                </span>
                <span className="truncate whitespace-nowrap text-[11px] opacity-90">
                  {statusLabel}
                </span>
              </div>
            </div>
            <div className="flex items-center gap-2">
              {conv?.linked_ticket_id ? (
                <Badge
                  variant="secondary"
                  className="bg-white/20 text-white hover:bg-white/20"
                >
                  Ticket #{conv.linked_ticket_id}
                </Badge>
              ) : null}
              <button
                type="button"
                className="rounded-full p-1 hover:bg-white/20"
                onClick={resetAndClose}
                aria-label="Close chat"
              >
                <X className="h-4 w-4" />
              </button>
            </div>
          </div>

          {/* Body */}
          {stage === "prechat" ? (
            <form
              onSubmit={startConversation}
              className="flex flex-1 flex-col gap-3 overflow-y-auto p-4"
              style={{ backgroundColor: bodyBg }}
            >
              <p className="text-sm" style={{ color: isDark ? "#cbd5e1" : "#475569" }}>
                {resolvedWelcome}
              </p>
              <div className="grid gap-2">
                <Input
                  placeholder="Your name (optional)"
                  value={name}
                  onChange={(e) => setName(e.target.value)}
                />
                <Input
                  type="email"
                  placeholder="Email (optional, for follow-up)"
                  value={email}
                  onChange={(e) => setEmail(e.target.value)}
                />
                <Input
                  placeholder="Subject (optional)"
                  value={subject}
                  onChange={(e) => setSubject(e.target.value)}
                />
                <Textarea
                  placeholder={branding.input_placeholder || "How can we help?"}
                  value={firstMessage}
                  onChange={(e) => setFirstMessage(e.target.value)}
                  rows={4}
                  required
                />
              </div>
              {error ? (
                <p className="text-xs text-red-500">{error}</p>
              ) : null}
              <Button
                type="submit"
                disabled={starting || !firstMessage.trim()}
                className="mt-auto text-white"
                style={{ backgroundColor: branding.primary_color }}
              >
                {starting ? (
                  <>
                    <Loader2 className="mr-2 h-4 w-4 animate-spin" /> Starting…
                  </>
                ) : (
                  "Start chat"
                )}
              </Button>
              {branding.show_branding_footer && branding.footer_text && (
                <div
                  className="text-center text-[10px] pt-1 space-x-1"
                  style={{ color: isDark ? "#94a3b8" : "#64748b" }}
                >
                  <span>{branding.footer_text}</span>
                  <span aria-hidden>·</span>
                  <a
                    href="/privacy-center"
                    target="_blank"
                    rel="noopener noreferrer"
                    className="underline hover:opacity-80"
                    style={{ color: isDark ? "#94a3b8" : "#64748b" }}
                  >
                    Privacy
                  </a>
                </div>
              )}
            </form>
          ) : (
            <>
              <div
                ref={scrollerRef}
                className="flex-1 overflow-y-auto px-3 py-3"
                style={{ backgroundColor: bodyBg }}
              >
                <div className="flex flex-col gap-2">
                  {/* AI intro bubble - injected only when no AI/agent messages exist yet */}
                  {messages.filter((m) => m.sender_type !== "visitor").length ===
                    0 && (
                    <div
                      className="max-w-[85%] self-start rounded-2xl px-3 py-2 text-sm shadow"
                      style={{
                        backgroundColor: aiBubbleBg,
                        color: aiBubbleText,
                      }}
                    >
                      <div
                        className="mb-0.5 text-[11px] font-semibold"
                        style={{ color: branding.primary_color }}
                      >
                        {branding.widget_name}
                        <span className="ml-1 text-[10px] opacity-80">AI</span>
                      </div>
                      {resolvedIntro}
                    </div>
                  )}
                  {messages.map((m) => (
                    <ChatBubble
                      key={m.id}
                      message={m}
                      branding={branding}
                      aiBubbleBg={aiBubbleBg}
                      aiBubbleText={aiBubbleText}
                    />
                  ))}
                  {loadingReply && (
                    <div
                      className="self-start rounded-2xl px-3 py-2 text-xs shadow"
                      style={{
                        backgroundColor: aiBubbleBg,
                        color: aiBubbleText,
                      }}
                    >
                      <Loader2 className="mr-2 inline h-3 w-3 animate-spin" />
                      AI is typing…
                    </div>
                  )}
                </div>
              </div>
              <div
                className="border-t p-2"
                style={{
                  borderColor: isDark ? "#1f2937" : "#e2e8f0",
                  backgroundColor: panelBg,
                }}
              >
                {conv?.status === "ai" && (
                  <div className="mb-2 flex justify-end">
                    <button
                      type="button"
                      onClick={requestHuman}
                      className="text-xs underline hover:opacity-80"
                      style={{ color: branding.primary_color }}
                    >
                      Talk to a human
                    </button>
                  </div>
                )}
                {error && (
                  <p className="mb-2 text-xs text-red-500">{error}</p>
                )}
                <div className="flex items-end gap-2">
                  <Textarea
                    value={draft}
                    onChange={(e) => setDraft(e.target.value)}
                    onKeyDown={(e) => {
                      if (e.key === "Enter" && !e.shiftKey) {
                        e.preventDefault();
                        sendDraft();
                      }
                    }}
                    placeholder={branding.input_placeholder}
                    rows={2}
                    className="min-h-[44px] resize-none text-sm"
                    disabled={sending || conv?.status === "closed"}
                  />
                  <Button
                    type="button"
                    onClick={sendDraft}
                    disabled={
                      sending || !draft.trim() || conv?.status === "closed"
                    }
                    className="h-10 w-10 shrink-0 p-0 text-white"
                    style={{ backgroundColor: branding.primary_color }}
                    aria-label="Send"
                  >
                    {sending ? (
                      <Loader2 className="h-4 w-4 animate-spin" />
                    ) : (
                      <Send className="h-4 w-4" />
                    )}
                  </Button>
                </div>
                {branding.show_branding_footer && branding.footer_text && (
                  <div
                    className="mt-1 text-center text-[10px] space-x-1"
                    style={{ color: isDark ? "#94a3b8" : "#64748b" }}
                  >
                    <span>{branding.footer_text}</span>
                    <span aria-hidden>·</span>
                    <a
                      href="/privacy-center"
                      target="_blank"
                      rel="noopener noreferrer"
                      className="underline hover:opacity-80"
                      style={{ color: isDark ? "#94a3b8" : "#64748b" }}
                    >
                      Privacy
                    </a>
                  </div>
                )}
              </div>
            </>
          )}
        </div>
      )}
    </>
  );
}

function ChatBubble({
  message,
  branding,
  aiBubbleBg,
  aiBubbleText,
}: {
  message: ChatMessage;
  branding: Branding;
  aiBubbleBg: string;
  aiBubbleText: string;
}) {
  const isVisitor = message.sender_type === "visitor";
  const isSystem = message.sender_type === "system";
  const isAgent = message.sender_type === "agent";
  if (isSystem) {
    return (
      <div className="self-center rounded-full bg-amber-100 px-3 py-1 text-center text-[11px] text-amber-800">
        {message.content}
      </div>
    );
  }
  if (isVisitor) {
    return (
      <div
        className="max-w-[80%] self-end rounded-2xl px-3 py-2 text-sm shadow"
        style={{
          backgroundColor: branding.bubble_bg_color,
          color: branding.bubble_text_color,
        }}
      >
        <div className="whitespace-pre-wrap leading-relaxed">
          {message.content}
        </div>
      </div>
    );
  }
  // AI or agent bubble
  const avatarUrl = isAgent
    ? branding.agent_avatar_url || ""
    : branding.avatar_url || "";
  return (
    <div className="flex max-w-[85%] items-start gap-2 self-start">
      <div className="h-7 w-7 shrink-0 overflow-hidden rounded-full bg-slate-200 flex items-center justify-center text-[10px] font-bold text-slate-600">
        {avatarUrl ? (
          <img src={avatarUrl} alt="" className="h-full w-full object-cover" />
        ) : (
          branding.avatar_fallback_initials || (isAgent ? "A" : "AI")
        )}
      </div>
      <div
        className="rounded-2xl px-3 py-2 text-sm shadow"
        style={{ backgroundColor: aiBubbleBg, color: aiBubbleText }}
      >
        {message.sender_name ? (
          <div
            className="mb-0.5 text-[11px] font-semibold"
            style={{ color: branding.primary_color }}
          >
            {message.sender_name}
            {message.sender_type === "ai" && (
              <span className="ml-1 rounded bg-black/5 px-1 py-0.5 text-[10px] font-normal opacity-80">
                AI
              </span>
            )}
          </div>
        ) : null}
        <div className="whitespace-pre-wrap leading-relaxed">
          {message.content}
        </div>
      </div>
    </div>
  );
}