"use client";
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
import { useChat } from '@ai-sdk/react';
import { useMemo, useState, useRef, useEffect, useCallback } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { ChatMessage } from './chat-message.mjs';
import { ChatInput } from './chat-input.mjs';
import { StackAttribution } from '../../../../../../ui/src/components/stack-attribution.mjs';
import { ScrollArea } from '../../../../../../ui/src/components/scroll-area.mjs';
import { DefaultChatTransport, lastAssistantMessageIsCompleteWithToolCalls } from 'ai';
import { cn } from '../../../../../../ui/src/lib/utils.mjs';
import { usePluginOverrides, useBasePath } from '@btst/stack/context';
import { AI_CHAT_LOCALIZATION } from '../localization/index.mjs';
import { createApiClient } from '@btst/stack/plugins/client';
import { createAiChatQueryKeys } from '../../../../../../../plugins/ai-chat/query-keys.mjs';
import { useConversation, useConversations } from '../hooks/chat-hooks.mjs';
import { usePageAIContext } from '../../../../../../../plugins/ai-chat/client/context/page-ai-context.mjs';

function ChatInterface({
  apiPath = "/api/chat",
  initialMessages,
  id,
  variant = "full",
  className,
  onMessagesChange
}) {
  const {
    navigate,
    localization: customLocalization,
    apiBaseURL,
    apiBasePath,
    headers,
    mode,
    showAttribution,
    chatSuggestions
  } = usePluginOverrides(
    "ai-chat",
    { showAttribution: true }
  );
  const basePath = useBasePath();
  const isPublicMode = mode === "public";
  const pageAIContext = usePageAIContext();
  const localization = { ...AI_CHAT_LOCALIZATION, ...customLocalization };
  const queryClient = useQueryClient();
  const conversationsListQueryKey = useMemo(() => {
    if (isPublicMode) return ["ai-chat", "disabled"];
    const client = createApiClient({
      baseURL: apiBaseURL,
      basePath: apiBasePath
    });
    const queries = createAiChatQueryKeys(client, headers);
    return queries.conversations.list().queryKey;
  }, [apiBaseURL, apiBasePath, headers, isPublicMode]);
  const [currentConversationId, setCurrentConversationId] = useState(isPublicMode ? void 0 : id);
  const isFirstMessageSentRef = useRef(false);
  const hasNavigatedRef = useRef(false);
  useEffect(() => {
    if (!isPublicMode) {
      setCurrentConversationId(id);
      isFirstMessageSentRef.current = false;
      hasNavigatedRef.current = false;
      isEditInProgressRef.current = false;
    }
  }, [id, isPublicMode]);
  const { conversation, isLoading: isLoadingConversation } = useConversation(
    id,
    { enabled: !!id && !isPublicMode }
  );
  const { conversations } = useConversations({ enabled: !isPublicMode });
  const conversationIdRef = useRef(
    isPublicMode ? void 0 : id
  );
  useEffect(() => {
    if (!isPublicMode) {
      conversationIdRef.current = currentConversationId;
    }
  }, [currentConversationId, isPublicMode]);
  const editMessagesRef = useRef(null);
  const isEditInProgressRef = useRef(false);
  const [isMessagesInitialized, setIsMessagesInitialized] = useState(
    () => (
      // Start as initialized if there are no initialMessages to load
      !initialMessages || initialMessages.length === 0
    )
  );
  const pageAIContextRef = useRef(pageAIContext);
  useEffect(() => {
    pageAIContextRef.current = pageAIContext;
  }, [pageAIContext]);
  const transport = useMemo(
    () => new DefaultChatTransport({
      api: apiPath,
      // In public mode, don't send conversationId
      body: isPublicMode ? void 0 : () => ({ conversationId: conversationIdRef.current }),
      // Handle edit operations and inject page context
      prepareSendMessagesRequest: ({ messages: hookMessages }) => {
        const currentPageContext = pageAIContextRef.current;
        const pageContextBody = currentPageContext?.pageDescription ? {
          pageContext: currentPageContext.pageDescription,
          availableTools: Object.keys(
            currentPageContext.clientTools ?? {}
          ),
          routeName: currentPageContext.routeName
        } : {};
        if (editMessagesRef.current !== null) {
          const newUserMessage = hookMessages[hookMessages.length - 1];
          const messagesToSend = [...editMessagesRef.current];
          if (newUserMessage) {
            messagesToSend.push(newUserMessage);
          }
          editMessagesRef.current = null;
          return {
            body: {
              messages: messagesToSend,
              conversationId: conversationIdRef.current,
              ...pageContextBody
            }
          };
        }
        return {
          body: {
            messages: hookMessages,
            conversationId: conversationIdRef.current,
            ...pageContextBody
          }
        };
      }
    }),
    [apiPath, isPublicMode]
  );
  const addToolOutputRef = useRef(null);
  const {
    messages,
    sendMessage,
    status,
    error,
    setMessages,
    regenerate,
    addToolOutput
  } = useChat({
    transport,
    // Automatically resubmit after all client-side tool results are provided
    sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
    onToolCall: async ({ toolCall }) => {
      const toolName = toolCall.toolName;
      const handler = pageAIContextRef.current?.clientTools?.[toolName];
      if (handler) {
        try {
          const result = await handler(toolCall.input);
          addToolOutputRef.current?.({
            tool: toolName,
            toolCallId: toolCall.toolCallId,
            output: result
          });
        } catch (err) {
          addToolOutputRef.current?.({
            tool: toolName,
            toolCallId: toolCall.toolCallId,
            state: "output-error",
            errorText: err instanceof Error ? err.message : "Tool execution failed"
          });
        }
      } else {
        addToolOutputRef.current?.({
          tool: toolName,
          toolCallId: toolCall.toolCallId,
          state: "output-error",
          errorText: `No client-side handler registered for tool "${toolName}". The page context may have changed while the response was streaming.`
        });
      }
    },
    onError: (err) => {
      console.error("useChat onError:", err);
      if (!id && !hasNavigatedRef.current) {
        isFirstMessageSentRef.current = false;
      }
    },
    onFinish: async () => {
      if (isPublicMode) return;
      await queryClient.invalidateQueries({
        queryKey: conversationsListQueryKey
      });
      if (isFirstMessageSentRef.current && !id && !hasNavigatedRef.current) {
        hasNavigatedRef.current = true;
        await queryClient.refetchQueries({
          queryKey: conversationsListQueryKey
        });
        const cachedConversations = queryClient.getQueryData(conversationsListQueryKey);
        if (cachedConversations && cachedConversations.length > 0) {
          const newConversation = cachedConversations[0];
          if (newConversation) {
            setCurrentConversationId(newConversation.id);
            conversationIdRef.current = newConversation.id;
            if (variant === "full") {
              const newUrl = `${basePath}/chat/${newConversation.id}`;
              if (typeof window !== "undefined") {
                window.history.replaceState(
                  { ...window.history.state },
                  "",
                  newUrl
                );
              }
            }
          }
        }
      }
    }
  });
  useEffect(() => {
    addToolOutputRef.current = addToolOutput;
  }, [addToolOutput]);
  useEffect(() => {
    if (isEditInProgressRef.current) {
      return;
    }
    if (conversation?.messages && conversation.messages.length > 0 && messages.length === 0) {
      const uiMessages = conversation.messages.filter((m) => m.role !== "data").map((m) => {
        let parts;
        try {
          const parsed = JSON.parse(m.content);
          if (Array.isArray(parsed)) {
            parts = parsed;
          } else {
            parts = [{ type: "text", text: m.content }];
          }
        } catch {
          parts = [{ type: "text", text: m.content }];
        }
        return {
          id: m.id,
          role: m.role,
          parts
        };
      });
      setMessages(uiMessages);
    }
  }, [conversation, messages.length, setMessages]);
  useEffect(() => {
    if (initialMessages && initialMessages.length > 0 && messages.length === 0) {
      setMessages(initialMessages);
      setIsMessagesInitialized(true);
    }
  }, [initialMessages, setMessages, messages.length]);
  const [input, setInput] = useState("");
  const [attachedFiles, setAttachedFiles] = useState([]);
  const scrollRef = useRef(null);
  const userHasScrolledRef = useRef(false);
  const prevStatusRef = useRef(status);
  useEffect(() => {
    if (status !== prevStatusRef.current && (status === "streaming" || status === "submitted")) {
      userHasScrolledRef.current = false;
    }
    prevStatusRef.current = status;
  }, [status]);
  useEffect(() => {
    const viewport = scrollRef.current?.querySelector(
      "[data-radix-scroll-area-viewport]"
    );
    if (!viewport) return;
    const handleScroll = () => {
      const { scrollTop, scrollHeight, clientHeight } = viewport;
      const isNearBottom = scrollHeight - scrollTop - clientHeight < 50;
      userHasScrolledRef.current = !isNearBottom;
    };
    viewport.addEventListener("scroll", handleScroll);
    return () => viewport.removeEventListener("scroll", handleScroll);
  }, []);
  useEffect(() => {
    if (userHasScrolledRef.current) return;
    if (scrollRef.current) {
      const scrollElement = scrollRef.current.querySelector(
        "[data-radix-scroll-area-viewport]"
      );
      if (scrollElement) {
        scrollElement.scrollTop = scrollElement.scrollHeight;
      }
    }
  }, [messages]);
  useEffect(() => {
    if (isPublicMode && onMessagesChange && isMessagesInitialized) {
      onMessagesChange(messages);
    }
  }, [messages, isPublicMode, onMessagesChange, isMessagesInitialized]);
  const handleInputChange = (e) => {
    setInput(e.target.value);
  };
  const handleSubmit = async (e, files) => {
    e.preventDefault();
    const text = input.trim();
    if (!text && (!files || files.length === 0)) return;
    if (!isPublicMode && !id && messages.length === 0) {
      isFirstMessageSentRef.current = true;
    }
    userHasScrolledRef.current = false;
    const savedInput = input;
    const savedFiles = files ? [...files] : [];
    const messageCountBeforeSend = messages.length;
    setInput("");
    setAttachedFiles([]);
    try {
      if (files && files.length > 0) {
        const fileUIParts = files.map((file) => ({
          type: "file",
          mediaType: file.mediaType,
          url: file.url,
          filename: file.filename
        }));
        await sendMessage({
          text: text || "",
          // AI SDK requires text, even if empty
          files: fileUIParts
        });
      } else {
        await sendMessage({ text });
      }
    } catch (error2) {
      setInput(savedInput);
      setAttachedFiles(savedFiles);
      if (isFirstMessageSentRef.current && !hasNavigatedRef.current) {
        isFirstMessageSentRef.current = false;
      }
      setMessages((prev) => prev.slice(0, messageCountBeforeSend));
      console.error("Error sending message:", error2);
    }
  };
  const isLoading = status === "streaming" || status === "submitted";
  const handleRetry = useCallback(() => {
    regenerate();
  }, [regenerate]);
  const [pendingEdit, setPendingEdit] = useState(null);
  useEffect(() => {
    if (pendingEdit && messages.length === pendingEdit.expectedLength) {
      const textToSend = pendingEdit.text;
      setPendingEdit(null);
      isEditInProgressRef.current = false;
      sendMessage({ text: textToSend });
    }
  }, [messages.length, pendingEdit, sendMessage]);
  const handleEditMessage = useCallback(
    (messageId, newText) => {
      const messageIndex = messages.findIndex((m) => m.id === messageId);
      if (messageIndex === -1) return;
      const messageToEdit = messages[messageIndex];
      if (!messageToEdit || messageToEdit.role !== "user") return;
      const truncatedMessages = messages.slice(0, messageIndex);
      isEditInProgressRef.current = true;
      editMessagesRef.current = truncatedMessages;
      setPendingEdit({ text: newText, expectedLength: messageIndex });
      setMessages(truncatedMessages);
    },
    [messages, setMessages]
  );
  const isWidget = variant === "widget";
  return /* @__PURE__ */ jsxs(Fragment, { children: [
    /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(
      "div",
      {
        className: cn(
          "flex flex-col h-full w-full bg-background",
          isWidget && "rounded-xl",
          className
        ),
        "data-testid": "chat-interface",
        "data-chat-status": status,
        children: /* @__PURE__ */ jsx(ScrollArea, { ref: scrollRef, className: "flex-1 h-full", children: /* @__PURE__ */ jsxs(
          "div",
          {
            className: cn(
              "flex flex-col p-4",
              isWidget ? "max-w-full" : "max-w-3xl mx-auto w-full"
            ),
            children: [
              messages.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full min-h-[300px]", children: [
                /* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center text-muted-foreground mb-4", children: /* @__PURE__ */ jsx("p", { children: localization.CHAT_EMPTY_STATE }) }),
                (() => {
                  const pageSuggestions = pageAIContext?.suggestions ?? [];
                  const allSuggestions = [
                    ...pageSuggestions,
                    ...chatSuggestions ?? []
                  ];
                  return allSuggestions.length > 0 ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap justify-center gap-2 pb-4 max-w-md mx-auto", children: allSuggestions.map((suggestion, index) => /* @__PURE__ */ jsx(
                    "button",
                    {
                      type: "button",
                      onClick: () => setInput(suggestion),
                      className: "px-3 py-2 text-sm rounded-lg border border-border bg-background hover:bg-accent hover:text-accent-foreground transition-colors text-foreground",
                      children: suggestion
                    },
                    index
                  )) }) : null;
                })()
              ] }) : messages.map((m, index) => /* @__PURE__ */ jsx(
                ChatMessage,
                {
                  message: m,
                  isStreaming: status === "streaming" && m.id === messages[messages.length - 1]?.id && m.role === "assistant",
                  variant: isWidget ? "compact" : "default",
                  onRetry: (
                    // Only show retry on the last assistant message
                    m.role === "assistant" && index === messages.length - 1 ? handleRetry : void 0
                  ),
                  onEdit: (
                    // Allow editing user messages
                    m.role === "user" ? (newText) => handleEditMessage(m.id, newText) : void 0
                  ),
                  isRetrying: isLoading && m.role === "assistant"
                },
                m.id || `msg-${index}`
              )),
              isLoading && messages[messages.length - 1]?.role !== "assistant" && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 text-muted-foreground text-sm py-4", children: /* @__PURE__ */ jsx("div", { className: "animate-pulse", children: localization.CHAT_LOADING }) }),
              error && /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 text-destructive text-sm py-4 px-3 bg-destructive/10 rounded-md", children: /* @__PURE__ */ jsx("span", { children: localization.CHAT_ERROR }) })
            ]
          }
        ) })
      }
    ) }),
    /* @__PURE__ */ jsx(
      "div",
      {
        className: cn(
          "border-t bg-background p-4",
          isWidget ? "px-3 py-3" : "px-4"
        ),
        children: /* @__PURE__ */ jsxs("div", { className: cn(!isWidget && "max-w-3xl mx-auto"), children: [
          /* @__PURE__ */ jsx(
            ChatInput,
            {
              input,
              handleInputChange,
              handleSubmit,
              isLoading,
              placeholder: localization.CHAT_PLACEHOLDER,
              variant: isWidget ? "compact" : "default",
              onFilesAttached: setAttachedFiles,
              attachedFiles
            }
          ),
          showAttribution && /* @__PURE__ */ jsx(StackAttribution, {})
        ] })
      }
    )
  ] });
}

export { ChatInterface };
