import { createFileRoute, useNavigate } from "@tanstack/react-router";
import { useCallback, useEffect, useRef, useState } from "react";
import {
  FileTextIcon,
  ImageIcon,
  LogOutIcon,
  MenuIcon,
  MoonIcon,
  MessageSquareTextIcon,
  MoreHorizontalIcon,
  PencilIcon,
  PlusIcon,
  SparkleIcon,
  SunIcon,
  Trash2Icon,
  TrendingUpIcon,
  WalletIcon,
  XIcon,
} from "lucide-react";
import {
  Conversation,
  ConversationContent,
  ConversationScrollButton,
} from "@/components/ai-elements/conversation";
import { Message, MessageContent, MessageResponse } from "@/components/ai-elements/message";
import { Shimmer } from "@/components/ai-elements/shimmer";
import type { PromptInputMessage } from "@/components/ai-elements/prompt-input";
import { ChatComposer } from "@/components/chat-composer";
import { AttachmentCard } from "@/components/attachment-card";
import { GlmLogo } from "@/components/glm-logo";
import { ReportIssueDialog } from "@/components/report-issue-dialog";
import { TariffDialog } from "@/components/tariff-dialog";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
  chatTitleFromMessages,
  createId,
  loadChats,
  saveChats,
  type ChatAttachment,
  type ChatMessage,
  type ChatSession,
} from "@/lib/chat-store";
import {
  checkCotizadorAccess,
  closeUnauthorizedSession,
  rememberAccessError,
} from "@/lib/access-control";
import { getSupabaseClient, toGlmUser, type GlmUser } from "@/lib/supabase";
import { useTheme } from "@/lib/theme";
import {
  agentMessageMetadata,
  assistantTextFromAgent,
  callWmcAgent,
  deleteRemoteConversation,
  deleteStoredChatAttachments,
  ensureRemoteConversation,
  getAppSessionId,
  resetAppSessionTracking,
  renameRemoteConversation,
  refreshMessageAttachmentUrls,
  loadRemoteChats,
  saveRemoteMessages,
  trackAppEvent,
  trackAppOpenOnce,
  updateRemoteConversationTitle,
  uploadAttachments,
} from "@/lib/wmc-backend";
import { cn } from "@/lib/utils";

export const Route = createFileRoute("/chat")({
  head: () => ({
    meta: [
      { title: "Cotizador - Walmart Connect" },
      {
        name: "description",
        content:
          "Chatbot interno de GomezLee Marketing para generar cotizaciones de Walmart Connect en segundos.",
      },
      { property: "og:title", content: "Cotizador - Walmart Connect" },
      {
        property: "og:description",
        content: "Genera cotizaciones de Walmart Connect en segundos con el tarifario vigente.",
      },
    ],
  }),
  component: ChatPage,
});

const SUGGESTIONS = [
  {
    icon: WalletIcon,
    title: "Cotizar cabecera de gondola",
    prompt: "Cotiza una cabecera de góndola para Guatemala en 3 tiendas Walmart durante 4 semanas.",
  },
  {
    icon: TrendingUpIcon,
    title: "Actualizar el tarifario",
    prompt: "Actualiza el tarifario: la Impulsadora A Capital de Guatemala pasa a US$40 por día.",
  },
  {
    icon: FileTextIcon,
    title: "Comparar con cotizaciones previas",
    prompt: "Compara esta cotización con cotizaciones históricas similares de Walmart Connect.",
  },
  {
    icon: ImageIcon,
    title: "Generar arte de propuesta",
    prompt: "Genera una referencia visual profesional para una isla promocional de Walmart Connect.",
  },
];

function AttachmentPreview({ attachments }: { attachments: ChatAttachment[] }) {
  if (attachments.length === 0) return null;
  return (
    <div className="flex w-full flex-wrap justify-end gap-2.5">
      {attachments.map((file, index) => (
        <AttachmentCard key={`${file.filename}-${index}`} file={file} />
      ))}
    </div>
  );
}

function AccountAvatar({ user }: { user: GlmUser }) {
  const [imageFailed, setImageFailed] = useState(false);

  useEffect(() => {
    setImageFailed(false);
  }, [user.avatarUrl]);

  if (user.avatarUrl && !imageFailed) {
    return (
      <img
        src={user.avatarUrl}
        alt={user.name}
        referrerPolicy="no-referrer"
        onError={() => setImageFailed(true)}
        className="size-full rounded-full object-cover"
      />
    );
  }

  return <span>{user.initials}</span>;
}

function ChatSidebar({
  chats,
  activeChatId,
  open,
  user,
  onClose,
  onNew,
  onSelect,
  onRename,
  onDelete,
  onSignOut,
}: {
  chats: ChatSession[];
  activeChatId: string | null;
  open: boolean;
  user: GlmUser;
  onClose: () => void;
  onNew: () => void;
  onSelect: (chat: ChatSession) => void;
  onRename: (chatId: string, title: string) => void;
  onDelete: (chatId: string) => void;
  onSignOut: () => void;
}) {
  const [renameTarget, setRenameTarget] = useState<ChatSession | null>(null);
  const [renameValue, setRenameValue] = useState("");

  const openRename = (chat: ChatSession) => {
    setRenameTarget(chat);
    setRenameValue(chat.title);
  };

  const confirmRename = () => {
    if (!renameTarget) return;
    const title = renameValue.replace(/\s+/g, " ").trim().slice(0, 80);
    if (!title) return;
    onRename(renameTarget.id, title);
    setRenameTarget(null);
    setRenameValue("");
  };

  return (
    <>
      {open ? (
        <button
          type="button"
          aria-label="Cerrar historial de chats"
          className="fixed inset-0 z-40 bg-foreground/15 backdrop-blur-[1px] md:hidden"
          onClick={onClose}
        />
      ) : null}

      <aside
        className={cn(
          "fixed inset-y-0 left-0 z-50 flex w-[17rem] flex-col border-r border-sidebar-border bg-secondary/70 px-3 py-4 shadow-xl transition-transform duration-200 md:static md:z-auto md:translate-x-0 md:shadow-none",
          open ? "translate-x-0" : "-translate-x-full",
        )}
      >
        <div className="mb-4 flex items-center gap-2">
          <button
            type="button"
            onClick={onNew}
            className="flex h-11 flex-1 items-center gap-2.5 rounded-xl border border-primary/20 bg-card px-3.5 text-sm font-bold text-primary shadow-sm transition-colors hover:bg-primary hover:text-primary-foreground"
          >
            <PlusIcon className="size-4.5" />
            Nuevo chat
          </button>
          <button
            type="button"
            onClick={onClose}
            aria-label="Cerrar historial"
            className="grid size-10 place-items-center rounded-xl text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground md:hidden"
          >
            <XIcon className="size-4.5" />
          </button>
        </div>

        <div className="flex min-h-0 flex-1 flex-col">
          <div className="mb-2 flex items-center gap-2 px-2 text-xs font-bold uppercase tracking-[0.12em] text-primary/80">
            <MessageSquareTextIcon className="size-3.5" />
            Chats
          </div>

          <div className="scrollbar-slim min-h-0 flex-1 space-y-1 overflow-y-auto pr-1">
            {chats.length === 0 ? (
              <p className="px-2 py-3 text-xs leading-relaxed text-muted-foreground">
                Tus conversaciones aparecerán aquí después de enviar el primer mensaje.
              </p>
            ) : (
              chats.map((chat) => {
                const active = chat.id === activeChatId;
                return (
                  <div
                    key={chat.id}
                    className={cn(
                      "group flex min-w-0 items-center rounded-lg transition-colors",
                      active ? "bg-primary/10" : "hover:bg-secondary",
                    )}
                  >
                    <button
                      type="button"
                      onClick={() => onSelect(chat)}
                      title={chat.title}
                      className={cn(
                        "min-w-0 flex-1 truncate px-3 py-2.5 text-left text-sm",
                        active ? "font-bold text-primary" : "font-medium text-sidebar-foreground",
                      )}
                    >
                      {chat.title}
                    </button>

                    <DropdownMenu>
                      <DropdownMenuTrigger asChild>
                        <button
                          type="button"
                          aria-label={`Opciones de ${chat.title}`}
                          onClick={(event) => event.stopPropagation()}
                          className={cn(
                            "mr-1 grid size-8 shrink-0 place-items-center rounded-md text-muted-foreground opacity-0 transition-all hover:bg-card hover:text-foreground group-hover:opacity-100 group-focus-within:opacity-100",
                          )}
                        >
                          <MoreHorizontalIcon className="size-4" />
                        </button>
                      </DropdownMenuTrigger>
                      <DropdownMenuContent align="end" side="right" className="min-w-44">
                        <DropdownMenuItem
                          className="gap-2"
                          onClick={() => openRename(chat)}
                        >
                          <PencilIcon className="size-4" />
                          Cambiar nombre
                        </DropdownMenuItem>
                        <DropdownMenuItem
                          className="gap-2 text-destructive focus:text-destructive"
                          onClick={() => onDelete(chat.id)}
                        >
                          <Trash2Icon className="size-4" />
                          Eliminar chat
                        </DropdownMenuItem>
                      </DropdownMenuContent>
                    </DropdownMenu>
                  </div>
                );
              })
            )}
          </div>
        </div>

        <div className="mt-3 border-t border-sidebar-border pt-3">
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <button
                type="button"
                className="group flex w-full items-center gap-3 rounded-xl px-2.5 py-2 text-left transition-colors hover:bg-secondary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/45"
                aria-label={`Abrir menú de ${user.name}`}
              >
                <div className="grid size-10 shrink-0 place-items-center overflow-hidden rounded-full bg-[image:var(--gradient-brand)] text-xs font-bold text-primary-foreground ring-1 ring-sidebar-border">
                  <AccountAvatar user={user} />
                </div>
                <div className="min-w-0 flex-1">
                  <div className="truncate text-sm font-bold text-sidebar-foreground">{user.name}</div>
                </div>
              </button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="start" side="top" sideOffset={8} className="w-52">
              <DropdownMenuItem
                className="gap-2 text-destructive focus:text-destructive"
                onClick={onSignOut}
              >
                <LogOutIcon className="size-4" />
                Cerrar sesión
              </DropdownMenuItem>
            </DropdownMenuContent>
          </DropdownMenu>
        </div>
      </aside>

      <Dialog
        open={Boolean(renameTarget)}
        onOpenChange={(nextOpen) => {
          if (!nextOpen) {
            setRenameTarget(null);
            setRenameValue("");
          }
        }}
      >
        <DialogContent className="max-w-md rounded-2xl border-border bg-card p-5 shadow-2xl">
          <DialogHeader className="space-y-2">
            <DialogTitle className="text-lg font-bold text-foreground">Cambiar nombre del chat</DialogTitle>
            <DialogDescription>
              Escribe un nombre corto para identificar esta conversación.
            </DialogDescription>
          </DialogHeader>

          <form
            className="space-y-4"
            onSubmit={(event) => {
              event.preventDefault();
              confirmRename();
            }}
          >
            <Input
              value={renameValue}
              onChange={(event) => setRenameValue(event.target.value)}
              maxLength={80}
              autoFocus
              aria-label="Nuevo nombre del chat"
              className="h-11 rounded-xl bg-background px-3.5"
            />
            <div className="text-right text-xs text-muted-foreground">{renameValue.length}/80</div>

            <DialogFooter className="gap-2 sm:space-x-0">
              <button
                type="button"
                onClick={() => {
                  setRenameTarget(null);
                  setRenameValue("");
                }}
                className="inline-flex h-10 items-center justify-center rounded-xl border border-border bg-card px-4 text-sm font-semibold text-foreground transition-colors hover:bg-secondary"
              >
                Cancelar
              </button>
              <button
                type="submit"
                disabled={!renameValue.trim()}
                className="inline-flex h-10 items-center justify-center rounded-xl bg-primary px-4 text-sm font-bold text-primary-foreground transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-45"
              >
                Guardar
              </button>
            </DialogFooter>
          </form>
        </DialogContent>
      </Dialog>
    </>
  );
}

function ChatPage() {
  const navigate = useNavigate();
  const [user, setUser] = useState<GlmUser | null>(null);
  const [messages, setMessages] = useState<ChatMessage[]>([]);
  const [chats, setChats] = useState<ChatSession[]>([]);
  const [activeChatId, setActiveChatId] = useState<string | null>(null);
  const [draft, setDraft] = useState("");
  const [busy, setBusy] = useState(false);
  const [sidebarOpen, setSidebarOpen] = useState(false);
  const [canUseTarifario, setCanUseTarifario] = useState(false);
  const { theme, toggleTheme } = useTheme();
  const chatsRef = useRef<ChatSession[]>([]);
  const abortRef = useRef<AbortController | null>(null);

  useEffect(() => {
    let active = true;
    let validating = false;
    const supabase = getSupabaseClient();

    const denyAccess = async (message: string) => {
      rememberAccessError(message);
      await closeUnauthorizedSession(supabase);
      if (!active) return;
      setUser(null);
      setCanUseTarifario(false);
      void navigate({ to: "/", replace: true });
    };

    const verifyAccess = async (loadInitialState: boolean) => {
      if (validating) return;
      validating = true;

      try {
        const result = await checkCotizadorAccess(supabase);
        if (!active) return;

        if (!result.allowed) {
          if (result.reason === "signed_out") {
            setUser(null);
            setCanUseTarifario(false);
            void navigate({ to: "/", replace: true });
            return;
          }

          await denyAccess(result.message);
          return;
        }

        setCanUseTarifario(result.permissions.canUseTarifario);

        if (!loadInitialState) return;

        const nextUser = toGlmUser(result.user);
        let savedChats: ChatSession[] = [];
        try {
          savedChats = await loadRemoteChats(supabase, nextUser);
        } catch (remoteError) {
          console.warn("No se pudo cargar el historial remoto; se usará el respaldo local:", remoteError);
          savedChats = loadChats(nextUser.id);
        }
        if (savedChats.length === 0) {
          const localBackup = loadChats(nextUser.id);
          if (localBackup.length > 0) savedChats = localBackup;
        }
        setUser(nextUser);
        chatsRef.current = savedChats;
        setChats(savedChats);
        // El historial se conserva en la barra lateral, pero cada entrada a la app
        // comienza siempre en la pantalla principal en lugar de reabrir el último chat.
        setActiveChatId(null);
        setMessages([]);
        setDraft("");
        void trackAppOpenOnce(supabase, nextUser);
      } catch (error) {
        console.error(error);
        if (active) {
          await denyAccess(
            "No se pudo validar tu acceso en este momento. Intenta nuevamente o contacta a IT.",
          );
        }
      } finally {
        validating = false;
      }
    };

    const {
      data: { subscription },
    } = supabase.auth.onAuthStateChange((event) => {
      if (!active) return;
      if (event === "SIGNED_OUT") {
        setUser(null);
        setCanUseTarifario(false);
        setActiveChatId(null);
        setMessages([]);
        setDraft("");
        void navigate({ to: "/", replace: true });
      }
    });

    const revalidateAccess = () => {
      void verifyAccess(false);
    };
    const handleVisibilityChange = () => {
      if (document.visibilityState === "visible") revalidateAccess();
    };

    void verifyAccess(true);
    window.addEventListener("focus", revalidateAccess);
    document.addEventListener("visibilitychange", handleVisibilityChange);
    const accessTimer = window.setInterval(revalidateAccess, 60_000);

    return () => {
      active = false;
      subscription.unsubscribe();
      window.removeEventListener("focus", revalidateAccess);
      document.removeEventListener("visibilitychange", handleVisibilityChange);
      window.clearInterval(accessTimer);
    };
  }, [navigate]);

  const commitChats = useCallback(
    (nextChats: ChatSession[]) => {
      const sorted = [...nextChats].sort((a, b) => b.updatedAt - a.updatedAt);
      chatsRef.current = sorted;
      setChats(sorted);
      if (user) saveChats(user.id, sorted);
    },
    [user],
  );

  const persistMessages = useCallback(
    (chatId: string, nextMessages: ChatMessage[]) => {
      setMessages(nextMessages);
      const now = Date.now();
      const existing = chatsRef.current.find((chat) => chat.id === chatId);
      const nextChat: ChatSession = {
        id: chatId,
        title: existing?.title || chatTitleFromMessages(nextMessages),
        messages: nextMessages,
        createdAt: existing?.createdAt ?? nextMessages[0]?.createdAt ?? now,
        updatedAt: now,
      };
      commitChats([nextChat, ...chatsRef.current.filter((chat) => chat.id !== chatId)]);
    },
    [commitChats],
  );

  const stop = useCallback(() => {
    abortRef.current?.abort();
    abortRef.current = null;
    setBusy(false);
  }, []);

  useEffect(() => stop, [stop]);

  const send = useCallback(
    async (payload: PromptInputMessage) => {
      if (!user || busy) return;

      const supabase = getSupabaseClient();
      const chatId = activeChatId ?? createId();
      const messageId = createId();
      const previewAttachments: ChatAttachment[] = payload.files.slice(0, 8).map((file) => ({
        filename: file.filename ?? "archivo",
        mediaType: file.mediaType ?? "application/octet-stream",
        url: file.url,
        storagePath: null,
      }));
      const userMessage: ChatMessage = {
        id: messageId,
        role: "user",
        text: payload.text.trim(),
        attachments: previewAttachments,
        createdAt: Date.now(),
      };
      const previousMessages = [...messages];
      const withPreview = [...previousMessages, userMessage];

      if (!activeChatId) setActiveChatId(chatId);
      persistMessages(chatId, withPreview);
      setBusy(true);
      const controller = new AbortController();
      abortRef.current = controller;

      try {
        // La conversación y el historial PREVIO se guardan antes de llamar a n8n.
        // El mensaje actual se guarda después para que Gemini no lo reciba duplicado
        // como currentRequest + HISTORIAL.
        const existingChatTitle =
          chatsRef.current.find((chat) => chat.id === chatId)?.title ||
          chatTitleFromMessages(withPreview);
        await ensureRemoteConversation(
          supabase,
          user,
          chatId,
          existingChatTitle,
        );
        if (previousMessages.length > 0) {
          const refreshedHistory = await refreshMessageAttachmentUrls(supabase, previousMessages);
          await saveRemoteMessages(supabase, user, chatId, refreshedHistory);
        }

        const uploadedAttachments = payload.files.length
          ? await uploadAttachments(supabase, user, chatId, messageId, payload.files)
          : [];
        const durableUserMessage: ChatMessage = {
          ...userMessage,
          attachments: uploadedAttachments,
        };
        const withUser = [...previousMessages, durableUserMessage];
        persistMessages(chatId, withUser);

        if (!activeChatId) {
          void trackAppEvent(supabase, user, "chat_created", {}, "conversation", chatId);
        }
        void trackAppEvent(
          supabase,
          user,
          "message_sent",
          {
            hasAttachments: uploadedAttachments.length > 0,
            attachmentCount: uploadedAttachments.length,
          },
          "conversation",
          chatId,
        );

        const result = await callWmcAgent(
          supabase,
          user,
          {
            text: durableUserMessage.text,
            conversationId: chatId,
            messageId,
            attachments: uploadedAttachments,
          },
          controller.signal,
        );

        const reply: ChatMessage = {
          id: createId(),
          role: "assistant",
          text: assistantTextFromAgent(result),
          attachments: [],
          createdAt: Date.now(),
          metadata: agentMessageMetadata(result),
        };
        const completed = [...withUser, reply];
        persistMessages(chatId, completed);

        try {
          await saveRemoteMessages(supabase, user, chatId, [durableUserMessage, reply]);
          await updateRemoteConversationTitle(supabase, user, chatId, completed, chatsRef.current.find((chat) => chat.id === chatId)?.title);
        } catch (persistError) {
          console.warn("La respuesta se generó, pero no se pudo sincronizar el historial remoto:", persistError);
        }
      } catch (error) {
        const aborted = error instanceof DOMException && error.name === "AbortError";
        if (aborted) {
          try {
            const current = chatsRef.current.find((chat) => chat.id === chatId)?.messages ?? withPreview;
            const currentUserMessage = current.find((message) => message.id === messageId) ?? userMessage;
            const safeUserMessage = {
              ...currentUserMessage,
              attachments: currentUserMessage.attachments.filter(
                (attachment) => attachment.storagePath || (!attachment.url.startsWith("data:") && !attachment.url.startsWith("blob:")),
              ),
            };
            await saveRemoteMessages(supabase, user, chatId, [safeUserMessage]);
            await updateRemoteConversationTitle(supabase, user, chatId, current, chatsRef.current.find((chat) => chat.id === chatId)?.title);
          } catch (persistError) {
            console.warn("No se pudo guardar el mensaje detenido:", persistError);
          }
          return;
        }

        console.error("Error al comunicarse con el agente WMC:", error);
        const message = error instanceof Error && error.message
          ? error.message
          : "No se pudo completar la solicitud. Intenta nuevamente.";
        const errorReply: ChatMessage = {
          id: createId(),
          role: "assistant",
          text: `No pude completar la solicitud.\n\n⚠️ ${message}`,
          attachments: [],
          createdAt: Date.now(),
          metadata: { action: "error", error: message },
        };
        const current = chatsRef.current.find((chat) => chat.id === chatId)?.messages ?? withPreview;
        const completed = [...current.filter((item) => item.id !== errorReply.id), errorReply];
        persistMessages(chatId, completed);
        try {
          const currentUserMessage = completed.find((item) => item.id === messageId) ?? userMessage;
          const safeUserMessage = {
            ...currentUserMessage,
            attachments: currentUserMessage.attachments.filter(
              (attachment) => attachment.storagePath || (!attachment.url.startsWith("data:") && !attachment.url.startsWith("blob:")),
            ),
          };
          await saveRemoteMessages(supabase, user, chatId, [safeUserMessage, errorReply]);
          await updateRemoteConversationTitle(supabase, user, chatId, completed, chatsRef.current.find((chat) => chat.id === chatId)?.title);
        } catch (persistError) {
          console.warn("No se pudo persistir el error del agente:", persistError);
        }
        void trackAppEvent(supabase, user, "agent_error", { message }, "conversation", chatId);
      } finally {
        if (abortRef.current === controller) abortRef.current = null;
        setBusy(false);
      }
    },
    [activeChatId, busy, messages, persistMessages, user],
  );

  const focusComposer = useCallback(() => {
    window.requestAnimationFrame(() => {
      document.querySelector<HTMLTextAreaElement>('textarea[name="message"]')?.focus();
    });
  }, []);

  const startNew = useCallback(() => {
    stop();
    setActiveChatId(null);
    setMessages([]);
    setDraft("");
    setSidebarOpen(false);
    focusComposer();
  }, [focusComposer, stop]);

  const selectChat = useCallback(
    (chat: ChatSession) => {
      stop();
      setActiveChatId(chat.id);
      setMessages(chat.messages);
      setDraft("");
      setSidebarOpen(false);
    },
    [stop],
  );

  const renameChat = useCallback(
    (chatId: string, title: string) => {
      const cleanTitle = title.replace(/\s+/g, " ").trim().slice(0, 80);
      if (!cleanTitle) return;

      const current = chatsRef.current.find((chat) => chat.id === chatId);
      if (!current || current.title === cleanTitle) return;

      const renamed: ChatSession = {
        ...current,
        title: cleanTitle,
        updatedAt: Date.now(),
      };
      commitChats([renamed, ...chatsRef.current.filter((chat) => chat.id !== chatId)]);

      if (user) {
        const supabase = getSupabaseClient();
        void (async () => {
          try {
            await renameRemoteConversation(supabase, user, chatId, cleanTitle);
          } catch (error) {
            console.warn("No se pudo sincronizar el nuevo nombre del chat:", error);
          }
        })();
        void trackAppEvent(
          supabase,
          user,
          "chat_renamed",
          { previousTitle: current.title, title: cleanTitle },
          "conversation",
          chatId,
        );
      }
    },
    [commitChats, user],
  );

  const deleteChat = useCallback(
    (chatId: string) => {
      const deletedChat = chatsRef.current.find((chat) => chat.id === chatId);
      const nextChats = chatsRef.current.filter((chat) => chat.id !== chatId);
      commitChats(nextChats);

      if (user) {
        const supabase = getSupabaseClient();
        void (async () => {
          try {
            await deleteStoredChatAttachments(supabase, deletedChat);
            await deleteRemoteConversation(supabase, user, chatId);
          } catch (error) {
            console.warn("No se pudo eliminar completamente el chat remoto:", error);
          }
        })();
        void trackAppEvent(supabase, user, "chat_deleted", {}, "conversation", chatId);
      }

      if (activeChatId === chatId) {
        stop();
        setActiveChatId(null);
        setMessages([]);
        setDraft("");
      }
    },
    [activeChatId, commitChats, stop, user],
  );

  const chooseSuggestion = useCallback(
    (prompt: string) => {
      setDraft(prompt);
      focusComposer();
    },
    [focusComposer],
  );

  const signOut = async () => {
    stop();
    const supabase = getSupabaseClient();
    if (user) await trackAppEvent(supabase, user, "logout", { appSessionId: getAppSessionId() });
    resetAppSessionTracking();
    const { error } = await supabase.auth.signOut({ scope: "local" });
    if (error) console.error(error);
    setUser(null);
    setCanUseTarifario(false);
    setActiveChatId(null);
    setMessages([]);
    setDraft("");
    void navigate({ to: "/", replace: true });
  };

  if (!user) {
    return <div className="min-h-[100dvh] bg-background" />;
  }

  const isEmpty = messages.length === 0;

  return (
    <div className="flex h-[100dvh] overflow-hidden bg-background">
      <ChatSidebar
        chats={chats}
        activeChatId={activeChatId}
        open={sidebarOpen}
        user={user}
        onClose={() => setSidebarOpen(false)}
        onNew={startNew}
        onSelect={selectChat}
        onRename={renameChat}
        onDelete={deleteChat}
        onSignOut={() => void signOut()}
      />

      <div className="flex min-w-0 flex-1 flex-col">
        <header className="sticky top-0 z-20 border-b border-border bg-card/85 backdrop-blur">
          <div className="mx-auto grid w-full max-w-4xl grid-cols-[minmax(0,1fr)_auto] items-center gap-3 px-4 py-3">
            <div className="flex min-w-0 items-center gap-3">
              <button
                type="button"
                onClick={() => setSidebarOpen(true)}
                aria-label="Abrir historial de chats"
                className="grid size-9 shrink-0 place-items-center rounded-lg border border-border bg-card text-primary transition-colors hover:bg-secondary md:hidden"
              >
                <MenuIcon className="size-4.5" />
              </button>
              <GlmLogo className="h-6 shrink-0 sm:h-7" />
              <span aria-hidden="true" className="h-6 w-px shrink-0 bg-border" />
              <div className="min-w-0">
                <h1 className="truncate text-sm font-bold leading-tight text-primary sm:text-[0.95rem]">
                  Cotizador Walmart Connect
                </h1>
              </div>
            </div>

            <div className="flex shrink-0 items-center gap-1.5">
              {canUseTarifario ? <TariffDialog user={user} /> : null}

              <button
                type="button"
                onClick={toggleTheme}
                aria-label={theme === "dark" ? "Cambiar a modo claro" : "Cambiar a modo oscuro"}
                title={theme === "dark" ? "Modo claro" : "Modo oscuro"}
                className="inline-flex h-9 items-center gap-1.5 rounded-lg border border-border bg-card px-2.5 text-xs font-bold text-foreground transition-colors hover:bg-secondary sm:px-3"
              >
                {theme === "dark" ? <SunIcon className="size-4" /> : <MoonIcon className="size-4" />}
                <span className="hidden lg:inline">{theme === "dark" ? "Claro" : "Oscuro"}</span>
              </button>

              <ReportIssueDialog user={user} />
            </div>
          </div>
        </header>

        <Conversation className="scrollbar-slim flex-1">
          <ConversationContent className="mx-auto w-full max-w-4xl gap-6 px-4 pb-6 pt-6">
            {isEmpty ? (
              <div className="animate-rise flex flex-col items-center py-8 text-center sm:py-14">
                <h2 className="text-xl font-bold text-primary sm:text-2xl">
                  Hola, {user.firstName}
                </h2>
                <p className="mt-2 max-w-md text-sm leading-relaxed text-muted-foreground">
                  Pídeme una cotización de Walmart Connect y la armo en segundos con el tarifario
                  interno vigente.
                </p>

                <div className="mt-8 grid w-full gap-3 sm:grid-cols-2">
                  {SUGGESTIONS.map((item) => (
                    <button
                      key={item.title}
                      type="button"
                      onClick={() => chooseSuggestion(item.prompt)}
                      className="group flex items-start gap-3 rounded-xl border border-border bg-card p-3.5 text-left transition-all hover:-translate-y-px hover:border-brand hover:shadow-[var(--shadow-soft)]"
                    >
                      <span className="grid size-8 shrink-0 place-items-center rounded-lg bg-brand-soft text-primary transition-colors group-hover:bg-brand group-hover:text-brand-foreground">
                        <item.icon className="size-4" />
                      </span>
                      <span className="min-w-0">
                        <span className="block text-sm font-bold text-foreground">
                          {item.title}
                        </span>
                        <span className="mt-0.5 block text-xs leading-snug text-muted-foreground">
                          {item.prompt}
                        </span>
                      </span>
                    </button>
                  ))}
                </div>
              </div>
            ) : (
              messages.map((message) => (
                <Message key={message.id} from={message.role}>
                  {message.role === "assistant" ? (
                    <div className="flex items-center gap-2 text-[0.7rem] font-bold uppercase tracking-[0.14em] text-brand">
                      <SparkleIcon className="size-3.5" />
                      Cotizador
                    </div>
                  ) : null}
                  <AttachmentPreview attachments={message.attachments} />
                  {message.text ? (
                    <MessageContent>
                      {message.role === "assistant" ? (
                        <MessageResponse>{message.text}</MessageResponse>
                      ) : (
                        <p className="whitespace-pre-wrap">{message.text}</p>
                      )}
                    </MessageContent>
                  ) : null}
                </Message>
              ))
            )}

            {busy ? (
              <Message from="assistant">
                <MessageContent>
                  <Shimmer>Armando la cotización...</Shimmer>
                </MessageContent>
              </Message>
            ) : null}
          </ConversationContent>
          <ConversationScrollButton />
        </Conversation>

        <div className="border-t border-border bg-card/85 backdrop-blur">
          <div className="mx-auto w-full max-w-4xl px-4 pb-[max(1rem,env(safe-area-inset-bottom))] pt-3">
            <p className="mb-2.5 text-center text-xs font-normal text-muted-foreground">
              Para uso interno de GomezLee Marketing · Verifica siempre las tarifas antes de enviar
              al cliente.
            </p>
            <ChatComposer
              onSend={send}
              busy={busy}
              onStop={stop}
              draft={draft}
              onDraftChange={setDraft}
            />
          </div>
        </div>
      </div>
    </div>
  );
}
