import { ReactNode, useEffect, useMemo, useRef, useState } from "react";
import {
  PlusOutlined,
  CloseOutlined,
  FieldTimeOutlined,
  RedoOutlined,
  EditOutlined,
  DeleteOutlined,
} from "@ant-design/icons";
import {
  Button,
  Tooltip,
  Typography,
  Space,
  Spin,
  Drawer,
  Divider,
  Modal,
  Input,
  message,
} from "antd";
import { GetProp } from "antd";
import {
  Bubble,
  Sender,
  Suggestion,
  Prompts,
  Conversations,
} from "@ant-design/x";
import MarkdownViewer from "./MarkdownViewer";
import { useChat } from "@/hooks/useChat";
import RenderGraph from "./RenderGraph";
import InfiniteScroll from "react-infinite-scroll-component";
import type { ConversationsProps } from "@ant-design/x";
import { ChangeSessionName, DeleteSession } from "@/api/ai";
import { Conversation } from "@ant-design/x/lib/conversations";

export default function AIChat(props: {
  onClose?: () => void;
  onInsert?: (data: any) => void;
  graphType?: "flow" | "mindmap";
}) {
  const { onClose, onInsert, graphType } = props;
  const [chatStarted, setChatStarted] = useState(false);
  const [inputVal, setInputVal] = useState("");
  const contentRef = useRef<HTMLDivElement>(null);
  const [contentHeight, setContentHeight] = useState(0);
  const [openHistory, setOpenHistory] = useState(false);

  const setHeight = () => {
    setContentHeight(contentRef.current?.clientHeight || 0);
  };
  useEffect(() => {
    setHeight();
    const resizeObserver = new ResizeObserver(() => {
      setHeight();
    });
    resizeObserver.observe(contentRef.current!);
    return () => {
      resizeObserver.disconnect();
    };
  }, []);

  const {
    loading,
    onRequest,
    cancel,
    messages,
    setMessages,
    conversationList,
    changeConversation,
    loadingSession,
    addConversation,
    setConversationList,
    loadMoreConversation,
    hasMoreConversation,
    refreshConversationList,
    activeConversation,
  } = useChat({
    app_name: "system_design",
    onSuccess: (msg) => {
      setMessages((messages) => {
        const arr = [...messages];
        // const query = arr[messages.length - 2].content as string;
        arr[messages.length - 1].status = "done";
        arr[messages.length - 1].footer = <></>;
        return arr;
      });
    },
    onUpdate: (msg) => {
      setMessages((messages) => {
        const arr = [...messages];
        arr[messages.length - 1].content += msg.answer;
        arr[messages.length - 1].id = msg.message_id;
        arr[messages.length - 1].loading = false;
        arr[messages.length - 1].status = "loading";
        return arr;
      });
    },
    onError: (error) => {
      // message.error(error.message);
      setMessages((messages) => {
        const arr = [...messages];
        arr[messages.length - 1].content = (
          <Typography.Text type="danger">{error.message}</Typography.Text>
        );
        arr[messages.length - 1].status = "error";
        arr[messages.length - 1].loading = false;
        return arr;
      });
    },
  });

  const CustomRender = (props: { language: string; code: string }) => {
    const { language, code } = props;
    const children = useMemo(
      () => (
        <RenderGraph
          language={language}
          json={code}
          onInsert={onInsert}
          type={graphType}
        ></RenderGraph>
      ),
      [language, code]
    );

    return <>{children}</>;
  };

  const CustomMessage = (props: { content: string | ReactNode }) => {
    const { content } = props;
    const children = useMemo(
      () =>
        typeof content === "string" ? (
          <Typography className={content?.includes("```") ? "w-full" : ""}>
            <MarkdownViewer
              content={content}
              renderCode={(language, code) => (
                <CustomRender language={language} code={code} />
              )}
            />
          </Typography>
        ) : (
          content
        ),
      [content]
    );

    return children;
  };

  // bubbles角色配置
  const roles: GetProp<typeof Bubble.List, "roles"> = {
    assistant: {
      placement: "start",
      avatar: undefined,
      loadingRender: () => (
        <Space>
          <Spin size="small" />
          思考中...
        </Space>
      ),
      messageRender: (content) => <CustomMessage content={content} />,
      header: (
        <span className="text-12px text-#666">
          <svg className="icon h-16px! w-16px!" aria-hidden="true">
            <use xlinkHref="#icon-AI1"></use>
          </svg>
          <span className="ml-4px">数据模型助手</span>
        </span>
      ),
      styles: {
        content: {
          borderRadius: "0px 8px 8px 8px",
        },
      },
    },
    user: {
      placement: "end",
      avatar: undefined,
      messageRender: (content) => {
        return <div style={{ whiteSpace: "pre-wrap" }}>{content}</div>;
      },
      styles: {
        content: {
          backgroundColor: "#d2e1fb",
          borderRadius: "8px 0 8px 8px",
        },
      },
    },
  };

  const handleChangeConversationName = (conversation: Conversation) => {
    let new_name: string;
    Modal.info({
      title: "修改对话名称",
      okText: "提交",
      closable: true,
      content: (
        <div>
          <Input
            type="text"
            defaultValue={conversation.label + ""}
            onChange={(e) => {
              new_name = e.target.value;
            }}
          />
        </div>
      ),
      onOk: () => {
        return ChangeSessionName({
          app_name: "system_design",
          session_id: conversation.key,
          new_name,
        }).then(() => {
          message.success("修改成功");
          setConversationList((list) =>
            list?.map((item) =>
              item.key === conversation.key
                ? { ...item, label: new_name }
                : item
            )
          );
        });
      },
    });
  };

  const handleDeleteConversation = (conversation: Conversation) => {
    Modal.confirm({
      title: "删除对话",
      content: "是否删除对话？",
      okText: "删除",
      cancelText: "取消",
      onOk: () => {
        return DeleteSession({
          app_name: "system_design",
          session_id: conversation.key,
        }).then(() => {
          message.success("删除成功");
          refreshConversationList();

          addConversation();
        });
      },
    });
  };

  const menuConfig: ConversationsProps["menu"] = (conversation) => {
    if (conversation.key === "1") return undefined;
    return {
      items: [
        {
          label: "修改对话名称",
          key: "edit",
          icon: <EditOutlined />,
        },
        {
          label: "删除对话",
          key: "del",
          icon: <DeleteOutlined />,
          danger: true,
        },
      ],
      onClick: (menuInfo) => {
        // 修改对话名称
        if (menuInfo.key === "edit") {
          handleChangeConversationName(conversation);
        }
        // 删除对话
        if (menuInfo.key === "del") {
          handleDeleteConversation(conversation);
        }
      },
    };
  };

  // 处理提交
  const onSubmit = (val: string) => {
    setInputVal("");
    if (val.trim()) {
      if (!chatStarted) setChatStarted(true);
    }
    if (val.trim()) {
      setMessages((prev) => [
        ...(prev || []),
        {
          id: Date.now() + "",
          role: "user",
          content: val.trim(),
          status: "done",
        },
        {
          id: Date.now() + "1",
          content: "",
          status: "loading",
          role: "assistant",
          loading: true,
        },
      ]);

      onRequest(val.trim());
    }
  };

  // 开启新的对话
  const onNewChat = () => {
    addConversation();
    setChatStarted(false);
  };

  const onStop = () => {
    cancel();
  };

  const bubble = useMemo(() => {
    return (
      <Bubble.List
        style={{ maxHeight: contentHeight, padding: "0 10px" }}
        autoScroll
        items={messages}
        roles={roles}
      />
    );
  }, [messages]);

  return (
    <div
      className="flex-1 h-full flex flex-col"
      style={{
        backgroundImage: "linear-gradient(137deg, #e5f4ff 0%, #efe7ff 100%)",
      }}
    >
      <div className="chat-head w-full h-40px px-10px color-#333 flex items-center justify-between">
        <span className="text-14px">
          <svg className="icon h-32px w-32px mr-4px" aria-hidden="true">
            <use xlinkHref="#icon-AI1"></use>
          </svg>
          <span>AI对话</span>
        </span>
        <span>
          <Tooltip title="新建会话">
            <Button
              type="text"
              size="small"
              icon={<PlusOutlined />}
              onClick={onNewChat}
            ></Button>
          </Tooltip>
          <Tooltip title="历史记录">
            <Button
              type="text"
              size="small"
              icon={<FieldTimeOutlined />}
              onClick={() => setOpenHistory(true)}
            ></Button>
          </Tooltip>
          <Button
            type="text"
            size="small"
            icon={<CloseOutlined />}
            onClick={() => onClose?.()}
          ></Button>
        </span>
      </div>

      <div
        className="chat-content flex-1 overflow-hidden mt-12px"
        ref={contentRef}
        style={{ height: contentHeight }}
      >
        {!messages.length ? (
          <>
            <div className="text-center pt-200px">
              <svg className="icon h-40px! w-40px!" aria-hidden="true">
                <use xlinkHref="#icon-AI1"></use>
              </svg>
            </div>
            <h2 className="text-center">询问AI助手</h2>
            <p className="text-center">我是AI助手，有什么可以帮您的吗？</p>
          </>
        ) : (
          <div className="overflow-y-auto h-full">{bubble}</div>
        )}
      </div>

      <div className="px-12px py-16px">
        <Sender
          placeholder="开始探索..."
          loading={loading}
          value={inputVal}
          onChange={setInputVal}
          onSubmit={onSubmit}
          onCancel={onStop}
        />
      </div>
      <Drawer
        title="历史记录"
        open={openHistory}
        onClose={() => setOpenHistory(false)}
        placement="right"
        getContainer={false}
        width={280}
        styles={{ body: { padding: '0 12px' } }}
      >
        <div id="scrollableDiv" className="w-full h-full overflow-auto">
          <InfiniteScroll
            dataLength={conversationList?.length || 0}
            next={loadMoreConversation}
            hasMore={hasMoreConversation}
            loader={
              <div style={{ textAlign: "center" }}>
                <Spin indicator={<RedoOutlined spin />} size="small" />
              </div>
            }
            endMessage={
              <Divider plain>
                <span className="text-12px text-text-secondary">
                  无更多会话~
                </span>
              </Divider>
            }
            scrollableTarget="scrollableDiv"
            style={{ overflow: "hidden" }}
          >
            <Spin spinning={loadingSession} className="flex-col">
              <Conversations
                groupable
                style={{ width: 200, padding: 0, margin: 0 }}
                activeKey={activeConversation}
                onActiveChange={changeConversation}
                menu={menuConfig}
                items={conversationList}
              />
            </Spin>
          </InfiniteScroll>
        </div>
      </Drawer>
    </div>
  );
}
