import type { BubbleItemType } from "@ant-design/x";

import { useChat } from "@ai-sdk/react";
import { Bubble, Sender } from "@ant-design/x";
import { DefaultChatTransport } from "ai";
import { App, Empty, Spin } from "antd";
import { useCallback, useEffect, useRef, useState } from "react";

import { fetchMessages } from "../../../../hooks/use-conversations";
import { MessageBubble } from "./MessageBubble";

interface ChatPanelProps {
  conversationId: null | string;
  onConversationCreated: (id: string) => void;
  projectId: string;
}

export function ChatPanel({ conversationId, projectId }: ChatPanelProps) {
  const { message } = App.useApp();
  const [input, setInput] = useState("");
  const [loadingHistory, setLoadingHistory] = useState(false);
  const fetchRef = useRef(fetchMessages);

  const conversationIdRef = useRef(conversationId);
  useEffect(() => {
    conversationIdRef.current = conversationId;
  });

  const { messages, sendMessage, setMessages, status } = useChat({
    onError: (err) => {
      void message.error(`发送失败：${err.message}`);
    },
    transport: new DefaultChatTransport({
      api: `/api/projects/${projectId}/chat`,
    }),
  });

  const isLoading = status === "submitted" || status === "streaming";

  useEffect(() => {
    if (!conversationId) {
      setMessages([]);
      return;
    }

    let cancelled = false;

    const load = async () => {
      setLoadingHistory(true);
      setMessages([]);
      try {
        const data = await fetchRef.current(projectId, conversationId);
        if (cancelled) return;
        const history = data.items
          .filter((m: { role: string }) => m.role === "user" || m.role === "assistant")
          .reverse()
          .map((m: { content: string; id: string; role: string }) => ({
            id: m.id,
            parts: [{ text: m.content, type: "text" as const }],
            role: m.role as "assistant" | "user",
          }));
        setMessages(history);
      } catch (err: unknown) {
        if (!cancelled) {
          const msg = err instanceof Error ? err.message : String(err);
          void message.error(`加载历史失败：${msg}`);
        }
      } finally {
        if (!cancelled) setLoadingHistory(false);
      }
    };

    void load();

    return () => {
      cancelled = true;
    };
  }, [conversationId, projectId, setMessages, message]);

  const bubbleItems: BubbleItemType[] = messages.map((msg) => ({
    content: msg.parts
      .filter((p): p is { text: string; type: "text" } => p.type === "text")
      .map((p) => p.text)
      .join(""),
    key: msg.id,
    role: msg.role === "user" ? "user" : "ai",
  }));

  const onSubmit = useCallback(
    (nextInput: string) => {
      if (!nextInput.trim()) return;
      setInput("");
      void sendMessage({ text: nextInput }, { body: { conversationId: conversationIdRef.current } });
    },
    [sendMessage],
  );

  if (!conversationId) {
    return (
      <div className="app-chat-panel app-chat-panel-empty">
        <Empty description="选择或创建一个会话开始聊天" />
      </div>
    );
  }

  return (
    <div className="app-chat-panel">
      {loadingHistory ? (
        <div className="app-chat-panel-loading">
          <Spin />
        </div>
      ) : (
        <Bubble.List
          items={bubbleItems}
          role={{
            ai: {
              contentRender: (content: string) => <MessageBubble content={content} />,
              placement: "start",
            },
            user: {
              placement: "end",
            },
          }}
          style={{ flex: 1, overflow: "auto", padding: "16px" }}
        />
      )}
      <div className="app-chat-panel-sender">
        <Sender loading={isLoading} onChange={setInput} onSubmit={onSubmit} placeholder="输入消息..." value={input} />
      </div>
    </div>
  );
}
