import { useEffect, useMemo, useRef, useState } from "react";
import {
  ArrowUpOutlined,
  MenuFoldOutlined,
  MenuUnfoldOutlined,
  MessageOutlined,
  PaperClipOutlined,
  PlusOutlined,
  SearchOutlined,
  SettingOutlined,
  ThunderboltOutlined,
  UserOutlined,
} from "@ant-design/icons";
import { Button, Collapse, Drawer, Input, Layout, Typography } from "antd";
import { isAbortLikeError, streamQwenChat, type ChatMessagePayload } from "../api/qwenChat";
import StreamMessage from "../components/StreamMessage";

const { Header, Sider, Content } = Layout;
const MOBILE_WIDTH = 750;

type UiMessage = {
  id: string;
  role: "user" | "assistant";
  content: string;
  thinking?: string;
};

const INITIAL_MESSAGES: UiMessage[] = [
  {
    id: "init-assistant",
    role: "assistant",
    content: "你好，我是 ChatOne 助手，有什么可以帮你？",
  },
];

const STREAM_TIMEOUT_MS = 90000;
const MAX_STREAM_RETRY = 1;
const CONTEXT_WINDOW_SIZE = 8;

export default function HomePage() {
  const [collapsed, setCollapsed] = useState(false);
  const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
  const [viewportWidth, setViewportWidth] = useState(0);
  const [isMobile, setIsMobile] = useState(false);
  const [inputValue, setInputValue] = useState("");
  const [messages, setMessages] = useState<UiMessage[]>(INITIAL_MESSAGES);
  const [isSending, setIsSending] = useState(false);
  const [deepThink, setDeepThink] = useState(false);
  const [smartSearch, setSmartSearch] = useState(false);
  const messageListRef = useRef<HTMLDivElement | null>(null);
  const abortRef = useRef<AbortController | null>(null);

  const historyGroups = useMemo(
    () => [
      { title: "30 天内", keys: ["前端 CI 工具对比", "Nginx SPA 配置"] },
      { title: "2025-12", keys: ["Gitea Actions 入门"] },
    ],
    [],
  );

  useEffect(() => {
    const updateIsMobile = () => {
      const w = Math.min(
        window.innerWidth,
        document.documentElement.clientWidth || window.innerWidth,
      );
      setViewportWidth(w);
      const mobile = w < MOBILE_WIDTH;
      setIsMobile(mobile);
      if (!mobile) setMobileSidebarOpen(false);
    };
    updateIsMobile();
    window.addEventListener("resize", updateIsMobile);
    window.addEventListener("orientationchange", updateIsMobile);
    return () => {
      window.removeEventListener("resize", updateIsMobile);
      window.removeEventListener("orientationchange", updateIsMobile);
    };
  }, []);

  useEffect(() => {
    const el = messageListRef.current;
    if (!el) return;
    el.scrollTop = el.scrollHeight;
  }, [messages]);

  const sendMessage = async () => {
    const trimmed = inputValue.trim();
    if (!trimmed || isSending) return;

    setInputValue("");
    setIsSending(true);

    const userMessage: UiMessage = {
      id: `user-${Date.now()}`,
      role: "user",
      content: trimmed,
    };
    const assistantMessageId = `assistant-${Date.now() + 1}`;
    const assistantPlaceholder: UiMessage = {
      id: assistantMessageId,
      role: "assistant",
      content: "",
      thinking: deepThink ? "正在思考并生成答案…" : undefined,
    };

    const nextMessages = [...messages, userMessage, assistantPlaceholder];
    setMessages(nextMessages);

    const payloadMessages: ChatMessagePayload[] = nextMessages.map((item) => ({
      role: item.role,
      content: item.content,
    }));

    let assistantText = "";
    let lastError: unknown = null;

    for (let attempt = 0; attempt <= MAX_STREAM_RETRY; attempt += 1) {
      const controller = new AbortController();
      abortRef.current = controller;
      let receivedToken = false;

      const retryMessages =
        attempt === 0
          ? payloadMessages
          : ([
              ...nextMessages
                .slice(-CONTEXT_WINDOW_SIZE)
                .map((item): ChatMessagePayload => ({ role: item.role, content: item.content })),
              {
                role: "user" as const,
                content: `网络抖动导致输出中断。请在不重复已输出内容的前提下继续回答。已输出尾部：${assistantText.slice(-80)}`,
              },
            ] satisfies ChatMessagePayload[]);

      try {
        await streamQwenChat({
          messages: retryMessages,
          signal: controller.signal,
          timeoutMs: STREAM_TIMEOUT_MS,
          onToken: (token) => {
            receivedToken = true;
            assistantText += token;
            setMessages((prev) =>
              prev.map((item) =>
                item.id === assistantMessageId
                  ? { ...item, content: `${item.content}${token}` }
                  : item,
              ),
            );
          },
        });
        lastError = null;
        break;
      } catch (error) {
        lastError = error;
        const isAbortLike = isAbortLikeError(error);
        const canRetry = attempt < MAX_STREAM_RETRY;
        if (!canRetry) break;
        // 网络抖动或超时时自动重连；若已收到部分 token 也保留已输出文本。
        if (isAbortLike || !receivedToken) {
          await new Promise((resolve) => window.setTimeout(resolve, 300));
          continue;
        }
        break;
      } finally {
        abortRef.current = null;
      }
    }

    if (lastError) {
      const message = lastError instanceof Error ? lastError.message : "请求失败，请稍后重试";
      setMessages((prev) =>
        prev.map((item) =>
          item.id === assistantMessageId
            ? {
                ...item,
                content: item.content || `接口调用失败：${message}`,
                thinking: undefined,
              }
            : item,
        ),
      );
    }

    setIsSending(false);
    setMessages((prev) =>
      prev.map((item) =>
        item.id === assistantMessageId ? { ...item, thinking: undefined } : item,
      ),
    );
  };

  const sidebarContent = (
    <div className="flex h-full flex-col bg-[var(--ds-bg-sider)]">
      <div className="shrink-0 px-3 pt-3 pb-2">
        <Button
          block
          className="h-10! rounded-xl! border-[var(--ds-border)]! bg-[var(--ds-bg-main)]! text-[13px]! font-medium shadow-none hover:border-sky-300! hover:text-sky-600!"
          icon={<PlusOutlined />}
        >
          {(!collapsed || isMobile) && "新建会话"}
        </Button>
      </div>

      <div className="min-h-0 flex-1 overflow-auto px-2 py-2">
        {historyGroups.map((group) => (
          <div key={group.title} className="mb-4">
            <Typography.Text
              className="mb-2 block px-2 text-[11px] uppercase tracking-wide"
              style={{ color: "var(--ds-text-secondary)" }}
            >
              {group.title}
            </Typography.Text>
            {group.keys.map((key) => (
              <button
                key={key}
                type="button"
                className="mb-1 flex w-full items-center gap-2 rounded-xl px-3 py-2.5 text-left text-[13px] text-neutral-700 transition-colors hover:bg-black/5"
                style={{
                  background:
                    key === historyGroups[0].keys[0] ? "var(--ds-active-item)" : undefined,
                }}
              >
                <MessageOutlined className="shrink-0 text-neutral-400" />
                {(!collapsed || isMobile) && <span className="truncate">{key}</span>}
              </button>
            ))}
          </div>
        ))}
      </div>

      <div className="shrink-0 border-t border-[var(--ds-border)] p-3">
        <Button
          type="text"
          className="h-10 w-full justify-start! rounded-xl! px-2 text-neutral-600 hover:bg-black/5!"
          icon={<SettingOutlined />}
        >
          {(!collapsed || isMobile) && "设置"}
        </Button>
        <div className="mt-2 flex items-center gap-2 rounded-xl px-2 py-1.5">
          <div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-neutral-200 text-neutral-500">
            <UserOutlined />
          </div>
          {(!collapsed || isMobile) && (
            <Typography.Text className="truncate text-[13px]">用户</Typography.Text>
          )}
        </div>
      </div>
    </div>
  );

  return (
    <Layout
      className="chat-one-shell flex h-dvh max-h-dvh overflow-hidden"
      style={{ background: "var(--ds-bg-main)" }}
    >
      {!isMobile && (
        <Sider
          trigger={null}
          collapsible
          collapsed={collapsed}
          width={260}
          collapsedWidth={72}
          theme="light"
          className="!min-h-0 !overflow-hidden !bg-[var(--ds-bg-sider)] !border-r !border-[var(--ds-border)]"
        >
          <div className="flex h-14 items-center gap-2 border-b border-[var(--ds-border)] px-3">
            <img
              src="/logo.png"
              alt=""
              width={32}
              height={32}
              className="h-8 w-8 shrink-0 object-contain"
              decoding="async"
            />
            {!collapsed && (
              <Typography.Title level={5} className="!m-0 !truncate !text-[15px] !font-semibold">
                ChatOne
              </Typography.Title>
            )}
          </div>
          {sidebarContent}
        </Sider>
      )}

      <Layout
        className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden"
        style={{ background: "var(--ds-bg-main)" }}
      >
        <Header
          className="!flex !h-14 !shrink-0 !items-center !justify-between !border-b !border-[var(--ds-border)] !bg-[var(--ds-bg-main)] !px-5"
          style={{ lineHeight: "56px" }}
        >
          <div className="flex items-center gap-3">
            <Button
              type="text"
              className="text-neutral-500 hover:bg-black/5!"
              icon={
                isMobile ? (
                  <MenuUnfoldOutlined />
                ) : collapsed ? (
                  <MenuUnfoldOutlined />
                ) : (
                  <MenuFoldOutlined />
                )
              }
              onClick={() => {
                if (isMobile) setMobileSidebarOpen(true);
                else setCollapsed((v) => !v);
              }}
            />
            <img
              src="/logo.png"
              alt=""
              width={24}
              height={24}
              className="h-6 w-6 shrink-0 object-contain md:hidden"
              decoding="async"
            />
            <Typography.Text className="text-[15px] font-medium text-neutral-800">
              国内前端主流 CI 工具
            </Typography.Text>
          </div>
          <span className="rounded-full border border-[var(--ds-border)] bg-neutral-50 px-3 py-1 text-xs text-neutral-500">
            快速模式
          </span>
        </Header>

        <Content className="flex min-h-0 flex-1 flex-col overflow-hidden !bg-[var(--ds-bg-main)]">
          <div className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden">
            <div
              ref={messageListRef}
              className="min-h-0 flex-1 overflow-y-auto overflow-x-hidden px-4 pt-6 pb-0 md:px-8 md:pt-6 md:pb-0"
            >
              <div className="mx-auto flex max-w-3xl flex-col gap-5">
                {messages.map((item) => (
                  <div
                    key={item.id}
                    className={`flex ${item.role === "user" ? "justify-end" : "justify-start"}`}
                  >
                    <div
                      className={
                        item.role === "user"
                          ? "max-w-[85%] rounded-2xl border px-4 py-2.5 text-[15px] leading-relaxed text-neutral-800"
                          : "max-w-[85%] space-y-2"
                      }
                      style={
                        item.role === "user"
                          ? {
                              background: "var(--ds-user-bubble)",
                              borderColor: "var(--ds-user-border)",
                            }
                          : undefined
                      }
                    >
                      {item.role === "assistant" && item.thinking && (
                        <Collapse
                          bordered={false}
                          size="small"
                          className="!mb-2 !rounded-xl !bg-neutral-50 !border !border-[var(--ds-border)]"
                          items={[
                            {
                              key: "think",
                              label: (
                                <span className="text-[13px] text-neutral-600">
                                  <ThunderboltOutlined className="mr-1.5" />
                                  已思考（用时约 2 秒）
                                </span>
                              ),
                              children: (
                                <Typography.Text type="secondary" className="text-[13px]">
                                  {item.thinking}
                                </Typography.Text>
                              ),
                            },
                          ]}
                        />
                      )}
                      {item.role === "assistant" && <StreamMessage content={item.content} />}
                      {item.role === "user" && item.content}
                    </div>
                  </div>
                ))}
              </div>
            </div>

            <div className="shrink-0 bg-[var(--ds-bg-main)] px-4 pb-4 pt-0 md:px-8 md:pb-4 md:pt-0">
              <div className="mx-auto max-w-3xl">
                <div className="rounded-2xl border border-[var(--ds-border)] bg-neutral-50/50 p-3 shadow-sm">
                  <Input.TextArea
                    value={inputValue}
                    onChange={(e) => setInputValue(e.target.value)}
                    onPressEnter={(e) => {
                      if (e.shiftKey) return;
                      e.preventDefault();
                      void sendMessage();
                    }}
                    placeholder="给 ChatOne 发送消息"
                    variant="borderless"
                    autoSize={{ minRows: 1, maxRows: 6 }}
                    className="!px-1 !text-[15px] placeholder:text-neutral-400"
                  />
                  <div className="mt-2 flex flex-wrap items-center justify-between gap-2">
                    <div className="flex flex-wrap gap-2">
                      <button
                        type="button"
                        onClick={() => setDeepThink((v) => !v)}
                        className={`inline-flex items-center gap-1.5 rounded-full border px-3 py-1.5 text-xs transition-colors ${
                          deepThink
                            ? "border-sky-300 bg-sky-50 text-sky-700"
                            : "border-[var(--ds-border)] bg-[var(--ds-bg-main)] text-neutral-600 hover:border-neutral-300"
                        }`}
                      >
                        <ThunderboltOutlined />
                        深度思考
                      </button>
                      <button
                        type="button"
                        onClick={() => setSmartSearch((v) => !v)}
                        className={`inline-flex items-center gap-1.5 rounded-full border px-3 py-1.5 text-xs transition-colors ${
                          smartSearch
                            ? "border-sky-300 bg-sky-50 text-sky-700"
                            : "border-[var(--ds-border)] bg-[var(--ds-bg-main)] text-neutral-600 hover:border-neutral-300"
                        }`}
                      >
                        <SearchOutlined />
                        智能搜索
                      </button>
                    </div>
                    <div className="flex items-center gap-2">
                      <Button
                        type="text"
                        icon={<PaperClipOutlined className="text-neutral-400" />}
                        className="text-neutral-400"
                      />
                      <Button
                        type="primary"
                        shape="circle"
                        icon={<ArrowUpOutlined />}
                        loading={isSending}
                        disabled={isSending || !inputValue.trim()}
                        onClick={() => {
                          void sendMessage();
                        }}
                        className="!flex !h-9 !w-9 !items-center !justify-center !border-0 !shadow-none"
                        style={{
                          background: "var(--ds-send)",
                        }}
                      />
                    </div>
                  </div>
                </div>
                {import.meta.env.DEV && (
                  <Typography.Text type="secondary" className="mt-2 block text-center text-[11px]">
                    W:{viewportWidth}px · {isMobile ? "mobile" : "desktop"}
                  </Typography.Text>
                )}
              </div>
            </div>
          </div>
        </Content>
      </Layout>

      <Drawer
        title="ChatOne"
        placement="left"
        closable
        onClose={() => setMobileSidebarOpen(false)}
        open={isMobile && mobileSidebarOpen}
        width={280}
        styles={{ body: { padding: 0, background: "var(--ds-bg-sider)" } }}
      >
        {sidebarContent}
      </Drawer>
    </Layout>
  );
}
