"use client";

import {
  Activity,
  CheckCircle2,
  ChevronsUpDown,
  ChevronLeft,
  DatabaseZap,
  GitMerge,
  History,
  MapPinned,
  Plus,
  SendHorizontal
} from "lucide-react";
import { AnimatePresence, MotionConfig, motion } from "motion/react";
import { useEffect, useMemo, useRef, useState } from "react";
import { useStickToBottomContext } from "use-stick-to-bottom";
import { Agent, AgentContent } from "@/shared/ai-elements/agent";
import {
  Conversation,
  ConversationContent,
  ConversationScrollButton
} from "@/shared/ai-elements/conversation";
import type { PersonaState } from "@/shared/ai-elements/persona";
import { Message, MessageContent } from "@/shared/ai-elements/message";
import {
  PromptInput,
  PromptInputBody,
  PromptInputFooter,
  PromptInputSubmit,
  PromptInputTextarea
} from "@/shared/ai-elements/prompt-input";
import { Suggestion, Suggestions } from "@/shared/ai-elements/suggestion";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuTrigger
} from "@/shared/ui/dropdown-menu";
import { Button } from "@/shared/ui/button";
import { cn } from "@/lib/utils";
import type { AgentChatSessionSummary } from "../api/client";
import { AgentPersona } from "./agent-persona";
import {
  agentLayoutTransition,
  agentPanelItemVariants,
  agentPanelListVariants,
  agentPanelSectionVariants
} from "./agent-motion";
import { AgentHistoryPanel } from "./agent-history-panel";
import { AgentMessageDetails, AgentMessageProgress } from "./agent-message-details";
import { AgentOperationalBrief } from "./agent-operational-brief";
import { AgentUiEnvelopeRenderer } from "./agent-ui-envelope-renderer";
import { StreamingTokenResponse } from "./streaming-token-response";
import type {
  AgentChatMessage,
  AgentModelOption,
  AgentPermissionReply,
  AgentPermissionRequest,
  AgentQuestionRequest,
  AgentStreamRenderState,
  AgentUiResult
} from "../types";

type AgentCommandPanelProps = {
  collapsing?: boolean;
  personaState?: PersonaState;
  sessionTitle?: string;
  sessionHistory?: AgentChatSessionSummary[];
  sessionHistoryLoading?: boolean;
  activeSessionId?: string | null;
  statusLabel?: string;
  streaming?: boolean;
  messages?: AgentChatMessage[];
  streamRenderState?: AgentStreamRenderState;
  modelOptions?: AgentModelOption[];
  selectedModel?: string;
  uiResults?: AgentUiResult[];
  onCollapse: () => void;
  onRefreshHistory?: () => Promise<void> | void;
  onStartNewSession?: () => Promise<void> | void;
  onLoadHistorySession?: (sessionId: string) => Promise<void> | void;
  onRenameHistorySession?: (sessionId: string, title: string) => Promise<void> | void;
  onDeleteHistorySession?: (sessionId: string) => Promise<void> | void;
  onSelectModel?: (model: string) => void;
  onSubmitPrompt: (prompt: string) => Promise<void> | void;
  onStopPrompt?: () => void;
  onReplyPermission?: (permission: AgentPermissionRequest, reply: AgentPermissionReply) => Promise<void> | void;
  onReplyQuestion?: (request: AgentQuestionRequest, answers: string[][]) => Promise<void> | void;
  onRejectQuestion?: (request: AgentQuestionRequest) => Promise<void> | void;
};

const AGENT_PROMPT_SUGGESTIONS = [
  "当前监测数据质量如何，是否存在缺失、失真或可信度不足的问题？",
  "当前监测数据中有哪些异常问题需要重点关注？",
  "当前管网哪些区域可能存在雨污混接，判断依据是什么？"
] as const;

const AGENT_CAPABILITIES = [
  { icon: DatabaseZap, label: "监测质量诊断" },
  { icon: Activity, label: "异常状态研判" },
  { icon: GitMerge, label: "雨污混接识别" },
  { icon: MapPinned, label: "GIS 地图联动" }
] as const;

export function AgentCommandPanel({
  collapsing = false,
  personaState,
  sessionTitle = "新对话",
  sessionHistory = [],
  sessionHistoryLoading = false,
  activeSessionId,
  statusLabel = "Agent 后端连接中",
  streaming = false,
  messages = [],
  streamRenderState = {},
  modelOptions = [],
  selectedModel = "",
  uiResults = [],
  onCollapse,
  onRefreshHistory,
  onStartNewSession,
  onLoadHistorySession,
  onRenameHistorySession,
  onDeleteHistorySession,
  onSelectModel,
  onSubmitPrompt,
  onStopPrompt,
  onReplyPermission,
  onReplyQuestion,
  onRejectQuestion
}: AgentCommandPanelProps) {
  const [prompt, setPrompt] = useState("");
  const [historyOpen, setHistoryOpen] = useState(false);
  const [loadingSessionId, setLoadingSessionId] = useState<string | null>(null);
  const [scrollRequestId, setScrollRequestId] = useState(0);
  const trimmedPrompt = prompt.trim();

  useEffect(() => {
    if (historyOpen) {
      void Promise.resolve(onRefreshHistory?.());
    }
  }, [historyOpen, onRefreshHistory]);

  const submitPrompt = (nextPrompt: string) => {
    if (!nextPrompt || streaming) {
      return;
    }
    setPrompt("");
    setScrollRequestId((requestId) => requestId + 1);
    void Promise.resolve(onSubmitPrompt(nextPrompt)).catch(() => {
      setPrompt(nextPrompt);
    });
  };

  return (
    <MotionConfig reducedMotion="user">
      <aside
        className={cn(
          "pointer-events-auto flex h-full min-h-0 w-full flex-col overflow-hidden",
          "agent-panel-shell",
          "acrylic-panel border",
          "rounded-2xl",
          collapsing ? "agent-panel-collapse" : "agent-panel-enter"
        )}
      >
      <Agent className="flex h-full min-h-0 flex-col border-0 bg-transparent">
        <div className="agent-panel-band border-b border-slate-200">
          <div className="flex min-h-16 items-center justify-between gap-2 px-3 py-2">
            <div className="flex min-w-0 flex-1 items-center gap-2.5 text-slate-900">
              <AgentPersona
                className="h-12 w-12"
                fallbackClassName="h-12 w-12 rounded-xl"
                state={personaState}
                statusLabel={statusLabel}
                streaming={streaming}
              />
              <div className="min-w-0 flex-1">
                <div className="min-w-0">
                  <div className="flex min-w-0 items-center gap-2">
                    <p className="shrink-0 text-xs font-semibold uppercase text-slate-500">对话主题</p>
                    <span className="inline-flex h-6 shrink-0 items-center gap-1.5 rounded-lg border border-slate-200 bg-slate-50 px-2 text-xs font-semibold text-slate-600">
                      <span className={cn("h-1.5 w-1.5 rounded-full", getAgentConnectionClassName(statusLabel))} />
                      {getAgentConnectionLabel(statusLabel)}
                    </span>
                  </div>
                  <p className="truncate text-sm font-semibold text-slate-950" title={sessionTitle}>
                    {sessionTitle}
                  </p>
                </div>
              </div>
            </div>
            <button
              type="button"
              aria-label="新建 Agent 对话"
              title="新建 Agent 对话"
              onClick={() => {
                setHistoryOpen(false);
                setPrompt("");
                void Promise.resolve(onStartNewSession?.());
              }}
              className="agent-panel-icon-button grid h-9 w-9 shrink-0 place-items-center rounded-xl text-slate-600 transition"
            >
              <Plus size={17} aria-hidden="true" />
            </button>
            <button
              type="button"
              aria-label="打开 Agent 历史记录"
              title="打开 Agent 历史记录"
              onClick={() => setHistoryOpen((open) => !open)}
              className={cn(
                "agent-panel-icon-button grid h-9 w-9 shrink-0 place-items-center rounded-xl text-slate-600 transition",
                historyOpen && "border-blue-200 bg-blue-50 text-blue-700"
              )}
            >
              <History size={17} aria-hidden="true" />
            </button>
            <button
              type="button"
              aria-label="折叠 Agent 面板"
              title="折叠 Agent 面板"
              onClick={onCollapse}
              className="agent-panel-icon-button grid h-9 w-9 shrink-0 place-items-center rounded-xl text-slate-600 transition"
            >
              <ChevronLeft size={17} aria-hidden="true" />
            </button>
          </div>
          <AnimatePresence initial={false}>
            {historyOpen ? (
              <motion.div
                key="history"
                initial="initial"
                animate="animate"
                exit="exit"
                variants={agentPanelSectionVariants}
                style={{ overflow: "hidden" }}
              >
                <AgentHistoryPanel
                  activeSessionId={activeSessionId}
                  loadingSessionId={loadingSessionId}
                  loading={sessionHistoryLoading}
                  sessions={sessionHistory}
                  onRefresh={onRefreshHistory}
                  onSelectSession={(nextSessionId) => {
                    setLoadingSessionId(nextSessionId);
                    void Promise.resolve(onLoadHistorySession?.(nextSessionId))
                      .then(() => setHistoryOpen(false))
                      .finally(() => setLoadingSessionId(null));
                  }}
                  onRenameSession={onRenameHistorySession}
                  onDeleteSession={onDeleteHistorySession}
                />
              </motion.div>
            ) : null}
          </AnimatePresence>
          <AnimatePresence initial={false}>
            {messages.length > 0 || streaming ? (
              <motion.div
                key="operational-brief"
                className="space-y-2 px-3 pb-3"
                initial="initial"
                animate="animate"
                exit="exit"
                variants={agentPanelSectionVariants}
                style={{ overflow: "hidden" }}
              >
                <AgentOperationalBrief
                  messages={messages}
                  statusLabel={statusLabel}
                  streaming={streaming}
                  onSubmitCommand={submitPrompt}
                />
              </motion.div>
            ) : null}
          </AnimatePresence>
        </div>

        <AgentContent className="flex min-h-0 flex-1 flex-col gap-0 p-0">
          <Conversation className="agent-panel-conversation min-h-0">
            <ConversationContent className={cn("gap-4 p-3", messages.length === 0 && "min-h-full")}>
              <AnimatePresence mode="popLayout" initial={false}>
                {messages.length > 0 ? (
                  <BackendMessageList
                    key="messages"
                    messages={messages}
                    streaming={streaming}
                    streamRenderState={streamRenderState}
                    onReplyPermission={onReplyPermission}
                    onReplyQuestion={onReplyQuestion}
                    onRejectQuestion={onRejectQuestion}
                  />
                ) : (
                  <motion.div
                    key="empty"
                    className="flex flex-1 items-center justify-center px-4 py-8"
                    initial="initial"
                    animate="animate"
                    exit="exit"
                    variants={agentPanelItemVariants}
                  >
                    <AgentEmptyState />
                  </motion.div>
                )}
              </AnimatePresence>

              <AgentUiEnvelopeRenderer results={uiResults} />
            </ConversationContent>
            <AgentConversationScrollManager
              activeSessionId={activeSessionId}
              messages={messages}
              scrollRequestId={scrollRequestId}
              streaming={streaming}
              uiResults={uiResults}
            />
            <ConversationScrollButton className="bottom-3" />
          </Conversation>
        </AgentContent>

        <div className="agent-panel-band relative border-t border-slate-200 p-3">
          {messages.length === 0 && !streaming ? (
            <div className="agent-panel-conversation pointer-events-none absolute inset-x-0 bottom-full z-10 px-3 pb-2 pt-2">
              <Suggestions aria-label="推荐问题" role="group" className="pointer-events-auto px-0.5">
                {AGENT_PROMPT_SUGGESTIONS.map((suggestion) => (
                  <Suggestion
                    key={suggestion}
                    suggestion={suggestion}
                    onClick={submitPrompt}
                    className="surface-reading max-w-full border border-slate-200 text-slate-600 hover:bg-blue-50 hover:text-blue-700"
                  >
                    <span className="truncate">{suggestion}</span>
                  </Suggestion>
                ))}
              </Suggestions>
            </div>
          ) : null}
          <PromptInput
            className="agent-panel-control overflow-hidden rounded-2xl shadow-sm transition-[border-color,box-shadow] has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-1 has-[[data-slot=input-group-control]:focus-visible]:ring-ring [&>[data-slot=input-group]]:rounded-[inherit] [&>[data-slot=input-group]]:border-0 [&>[data-slot=input-group]]:shadow-none [&>[data-slot=input-group]]:!ring-0"
            onSubmit={(message) => {
              const nextPrompt = message.text.trim();
              if (nextPrompt) {
                submitPrompt(nextPrompt);
              }
            }}
          >
            <PromptInputBody>
              <PromptInputTextarea
                value={prompt}
                onChange={(event) => setPrompt(event.currentTarget.value)}
                className="min-h-14 text-sm"
                placeholder="输入调度问题，Agent 将通过后端会话流式响应"
              />
            </PromptInputBody>
            <PromptInputFooter className="justify-end">
              <div className="flex shrink-0 items-center gap-1.5">
                <AgentModelSelect
                  models={modelOptions}
                  value={selectedModel}
                  onValueChange={onSelectModel}
                />
                <PromptInputSubmit
                  aria-label={streaming ? "停止 Agent 指令" : "发送 Agent 指令"}
                  title={streaming ? "停止 Agent 指令" : "发送 Agent 指令"}
                  className="agent-panel-primary-icon"
                  disabled={!streaming && !trimmedPrompt}
                  status={streaming ? "streaming" : "ready"}
                  onStop={onStopPrompt}
                >
                  {streaming ? undefined : <SendHorizontal size={15} aria-hidden="true" />}
                </PromptInputSubmit>
              </div>
            </PromptInputFooter>
          </PromptInput>
        </div>
      </Agent>
      </aside>
    </MotionConfig>
  );
}

type AgentConversationScrollSnapshot = {
  activeSessionId?: string | null;
  lastUserMessageId: string | null;
  scrollRequestId: number;
  signature: string;
};

function AgentConversationScrollManager({
  activeSessionId,
  messages,
  scrollRequestId,
  streaming,
  uiResults
}: {
  activeSessionId?: string | null;
  messages: AgentChatMessage[];
  scrollRequestId: number;
  streaming: boolean;
  uiResults: AgentUiResult[];
}) {
  const { escapedFromLock, isAtBottom, scrollToBottom, state } = useStickToBottomContext();
  const previousSnapshotRef = useRef<AgentConversationScrollSnapshot | null>(null);
  const wasPinnedToBottom = !escapedFromLock && (isAtBottom || state.isAtBottom || state.isNearBottom);
  const snapshot = useMemo<AgentConversationScrollSnapshot>(
    () => ({
      activeSessionId,
      lastUserMessageId: getLastUserMessageId(messages),
      scrollRequestId,
      signature: createAgentConversationScrollSignature(messages, streaming, uiResults)
    }),
    [activeSessionId, messages, scrollRequestId, streaming, uiResults]
  );

  useEffect(() => {
    const previousSnapshot = previousSnapshotRef.current;
    previousSnapshotRef.current = snapshot;

    const forceScroll =
      !previousSnapshot ||
      previousSnapshot.activeSessionId !== snapshot.activeSessionId ||
      previousSnapshot.scrollRequestId !== snapshot.scrollRequestId ||
      (Boolean(snapshot.lastUserMessageId) && previousSnapshot.lastUserMessageId !== snapshot.lastUserMessageId);
    const contentChanged = !previousSnapshot || previousSnapshot.signature !== snapshot.signature;

    if (!forceScroll && (!contentChanged || !wasPinnedToBottom)) {
      return;
    }

    const animationFrameId = window.requestAnimationFrame(() => {
      void scrollToBottom({
        animation: "instant",
        ignoreEscapes: forceScroll,
        wait: !forceScroll
      });
    });

    return () => window.cancelAnimationFrame(animationFrameId);
  }, [scrollToBottom, snapshot, wasPinnedToBottom]);

  return null;
}

function getLastUserMessageId(messages: AgentChatMessage[]) {
  for (let index = messages.length - 1; index >= 0; index -= 1) {
    if (messages[index].role === "user") {
      return messages[index].id;
    }
  }

  return null;
}

function createAgentConversationScrollSignature(
  messages: AgentChatMessage[],
  streaming: boolean,
  uiResults: AgentUiResult[]
) {
  return [
    streaming ? "streaming" : "idle",
    messages.map(createAgentMessageScrollSignature).join("|"),
    uiResults.map((result) => result.id).join("|")
  ].join("#");
}

function createAgentMessageScrollSignature(message: AgentChatMessage) {
  return [
    message.id,
    message.role,
    message.content.length,
    message.progress?.map((item) => `${item.id}:${item.status}:${item.title.length}:${item.detail?.length ?? 0}`).join(",") ?? "",
    message.todos?.todos.map((todo) => `${todo.id}:${todo.status}:${todo.content.length}`).join(",") ?? "",
    message.permissions?.map((permission) => `${permission.requestId}:${permission.status}:${permission.error?.length ?? 0}`).join(",") ?? "",
    message.questions?.map((question) => `${question.requestId}:${question.status}:${question.error?.length ?? 0}`).join(",") ?? ""
  ].join(":");
}

function AgentModelSelect({
  models,
  value,
  onValueChange
}: {
  models: AgentModelOption[];
  value: string;
  onValueChange?: (model: string) => void;
}) {
  const selectedModel = models.find((model) => model.id === value) ?? models[0];

  if (!models.length) {
    return (
      <span className="shrink-0 rounded-md px-2 py-1 text-xs font-medium text-slate-500">
        模型
      </span>
    );
  }

  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <Button
          type="button"
          variant="outline"
          className="h-8 w-24 shrink-0 justify-between gap-1.5 rounded-md border-transparent bg-transparent px-1.5 text-xs text-slate-600 shadow-none hover:bg-slate-50"
          disabled={!onValueChange}
          aria-label="选择 Agent 模型"
        >
          <span className="flex min-w-0 flex-1 items-center gap-1">
            <ModelIcon model={selectedModel} size={selectedModel?.icon === "bolt" ? 15 : 14} />
            <span className="shrink-0">{selectedModel?.label ?? "模型"}</span>
          </span>
          <ChevronsUpDown size={12} className="shrink-0 opacity-50" aria-hidden="true" />
        </Button>
      </DropdownMenuTrigger>
      <DropdownMenuContent
        side="top"
        align="end"
        sideOffset={8}
        className="agent-panel-control w-[230px] rounded-xl p-2 shadow-lg"
      >
        <DropdownMenuLabel className="px-2 pb-2 pt-1 text-xs text-slate-500">
          模型选择
        </DropdownMenuLabel>
        <div className="space-y-1">
          {models.map((model) => {
            const selected = model.id === selectedModel?.id;
            return (
              <DropdownMenuItem
                key={model.id}
                className={cn(
                  "rounded-lg border border-transparent px-2.5 py-2 focus:bg-slate-50",
                  selected && "border-violet-200 bg-violet-50 focus:bg-violet-50"
                )}
                onSelect={() => onValueChange?.(model.id)}
              >
                <span className="ml-0.5 shrink-0 pt-0.5">
                  <ModelIcon model={model} size={model.icon === "bolt" ? 18 : 16} />
                </span>
                <span className="min-w-0 flex-1">
                  <span className="block truncate text-sm font-semibold text-slate-800">{model.label}</span>
                  <span className="block truncate text-xs leading-4 text-slate-500">{model.description}</span>
                </span>
                {selected ? <CheckCircle2 size={15} className="text-violet-600" aria-hidden="true" /> : null}
              </DropdownMenuItem>
            );
          })}
        </div>
      </DropdownMenuContent>
    </DropdownMenu>
  );
}

function getAgentConnectionLabel(statusLabel: string) {
  return /失败|不可用|错误|降级/.test(statusLabel) ? "离线" : "在线";
}

function getAgentConnectionClassName(statusLabel: string) {
  return /失败|不可用|错误|降级/.test(statusLabel) ? "bg-red-500" : "bg-emerald-500";
}

function ModelIcon({ model, size }: { model?: AgentModelOption; size: number }) {
  return model?.icon === "bolt" ? <FastModelIcon size={size} /> : <ExpertModelIcon size={size} />;
}

function FastModelIcon({ size }: { size: number }) {
  return (
    <svg
      width={size}
      height={size}
      viewBox="0 0 24 24"
      fill="none"
      className="text-sky-600"
      aria-hidden="true"
    >
      <path
        d="M10.67 21c-.35 0-.62-.31-.57-.66L11 14H7.5c-.88 0-.33-.75-.31-.78 1.26-2.23 3.15-5.53 5.65-9.93.1-.18.3-.29.5-.29.35 0 .62.31.57.66l-.9 6.34h3.51c.4 0 .62.19.4.66-3.29 5.74-5.2 9.09-5.75 10.05-.1.18-.29.29-.5.29"
        fill="currentColor"
      />
    </svg>
  );
}

function ExpertModelIcon({ size }: { size: number }) {
  return (
    <svg
      width={size}
      height={size}
      viewBox="0 0 24 24"
      fill="none"
      className="text-violet-600"
      aria-hidden="true"
    >
      <path
        d="m19.46 8 .79-1.75L22 5.46c.39-.18.39-.73 0-.91l-1.75-.79L19.46 2c-.18-.39-.73-.39-.91 0l-.79 1.75-1.76.79c-.39.18-.39.73 0 .91l1.75.79.79 1.76c.18.39.74.39.92 0M11.5 9.5 9.91 6c-.35-.78-1.47-.78-1.82 0L6.5 9.5 3 11.09c-.78.36-.78 1.47 0 1.82l3.5 1.59L8.09 18c.36.78 1.47.78 1.82 0l1.59-3.5 3.5-1.59c.78-.36.78-1.47 0-1.82zm7.04 6.5-.79 1.75-1.75.79c-.39.18-.39.73 0 .91l1.75.79.79 1.76c.18.39.73.39.91 0l.79-1.75 1.76-.79c.39-.18.39-.73 0-.91l-1.75-.79-.79-1.76c-.18-.39-.74-.39-.92 0"
        fill="currentColor"
      />
    </svg>
  );
}

function AgentReadyMark() {
  return (
    <svg viewBox="0 0 1024 1024" className="h-12 w-12 overflow-visible" aria-hidden="true">
      <g className="agent-ready-orbit">
        <path
          d="M384.1536 952.1664a38.4 38.4 0 0 1-49.3568 22.528 498.3808 498.3808 0 0 1-284.928-273.92 38.4 38.4 0 0 1 70.8608-29.6448 421.5808 421.5808 0 0 0 240.896 231.6288 38.4 38.4 0 0 1 22.528 49.408zM952.1152 384.9728a38.4 38.4 0 0 1-49.4592-22.528 421.5296 421.5296 0 0 0-234.1376-241.5104 38.4 38.4 0 0 1 29.184-71.0656 498.3296 498.3296 0 0 1 276.8896 285.696 38.4 38.4 0 0 1-22.528 49.408z"
          fill="#CE75FF"
        />
        <path
          d="M981.248 768.0512a42.6496 42.6496 0 1 1-85.2992 0 42.6496 42.6496 0 0 1 85.2992 0zM127.9488 256.0512a42.6496 42.6496 0 1 1-85.3504 0 42.6496 42.6496 0 0 1 85.3504 0z"
          fill="#F62E76"
        />
        <path
          d="M810.496 938.8544a42.6496 42.6496 0 1 1-85.2992 0 42.6496 42.6496 0 0 1 85.3504 0zM298.496 85.504a42.6496 42.6496 0 1 1-85.2992 0 42.6496 42.6496 0 0 1 85.3504 0z"
          fill="#CD88FF"
        />
      </g>
      <path
        className="agent-ready-core"
        d="M511.9488 276.736l-27.8528 114.7392A126.0544 126.0544 0 0 1 391.3216 484.352l-114.7904 27.8528 114.7904 27.8016a126.0544 126.0544 0 0 1 92.7744 92.8256L512 747.52l27.8016-114.7392a126.0544 126.0544 0 0 1 92.8256-92.8256l114.7392-27.8016-114.7392-27.8528a126.0544 126.0544 0 0 1-92.8256-92.8256L512 276.736z m55.6544-62.1568c-14.1312-58.368-97.1776-58.368-111.36 0L417.28 375.296a57.344 57.344 0 0 1-42.1888 42.1888l-160.6656 38.912c-58.4192 14.1824-58.4192 97.28 0 111.4112l160.6656 38.9632c20.8384 5.12 37.12 21.3504 42.1888 42.1888l38.9632 160.7168c14.1824 58.368 97.2288 58.368 111.36 0l38.9632-160.7168a57.344 57.344 0 0 1 42.1888-42.1888l160.7168-38.912c58.368-14.1824 58.368-97.28 0-111.4112l-160.7168-38.9632a57.344 57.344 0 0 1-42.1888-42.1888l-38.912-160.7168z"
        fill="#F3E2FF"
      />
    </svg>
  );
}

function AgentEmptyState() {
  return (
    <section
      aria-labelledby="agent-empty-state-title"
      className="surface-reading mx-auto w-full max-w-sm rounded-2xl border border-slate-200/80 px-4 pb-4 pt-5 text-center shadow-sm"
    >
      <div className="mx-auto grid h-16 w-16 place-items-center rounded-full border border-violet-100 bg-white shadow-[0_10px_28px_rgba(126,34,206,0.12)]">
        <AgentReadyMark />
      </div>
      <h2 id="agent-empty-state-title" className="mt-4 text-lg font-semibold leading-7 text-slate-900">
        我已就绪，请描述任务
      </h2>
      <p className="mx-auto mt-2 max-w-[30ch] text-sm leading-6 text-slate-500">
        使用自然语言下达指令，我会整理监测与空间证据，并在地图上呈现分析结果。
      </p>
      <ul className="mt-5 grid grid-cols-2 gap-2" aria-label="Agent 分析能力">
        {AGENT_CAPABILITIES.map(({ icon: Icon, label }) => (
          <li
            key={label}
            className="surface-control flex min-h-16 flex-col items-center justify-center gap-1.5 rounded-xl border border-slate-200/70 px-2 py-2.5 text-center shadow-[0_6px_18px_rgba(15,23,42,0.04)] sm:flex-row sm:gap-2 sm:px-2.5 sm:text-left"
          >
            <span className="grid h-8 w-8 shrink-0 place-items-center rounded-lg bg-blue-50 text-blue-700">
              <Icon size={17} strokeWidth={1.9} aria-hidden="true" />
            </span>
            <span className="whitespace-nowrap text-xs font-semibold leading-5 text-slate-800">{label}</span>
          </li>
        ))}
      </ul>
    </section>
  );
}

function BackendMessageList({
  messages,
  streaming,
  streamRenderState,
  onReplyPermission,
  onReplyQuestion,
  onRejectQuestion
}: {
  messages: AgentChatMessage[];
  streaming: boolean;
  streamRenderState: AgentStreamRenderState;
  onReplyPermission?: (permission: AgentPermissionRequest, reply: AgentPermissionReply) => Promise<void> | void;
  onReplyQuestion?: (request: AgentQuestionRequest, answers: string[][]) => Promise<void> | void;
  onRejectQuestion?: (request: AgentQuestionRequest) => Promise<void> | void;
}) {
  return (
    <motion.div className="flex w-full flex-col gap-4" variants={agentPanelListVariants} animate="animate">
      <AnimatePresence initial={false} mode="popLayout">
        {messages.map((message, index) => (
          <motion.div
            key={message.id}
            layout
            className={cn("w-full", message.role === "user" && "flex justify-end")}
            initial="initial"
            animate="animate"
            exit="exit"
            variants={agentPanelItemVariants}
            transition={agentLayoutTransition}
          >
            <Message
              from={message.role}
              className={message.role === "user" ? "max-w-[92%]" : "max-w-full"}
            >
              <MessageContent
                className={cn(
                  message.role === "user" && "bg-blue-600 px-3 py-2 text-white",
                  message.role === "assistant" && "agent-panel-message w-full rounded-2xl p-3 text-sm leading-6 text-slate-700 shadow-sm"
                )}
              >
                <div className="space-y-3">
                  {message.role === "assistant" ? (
                    <AgentMessageProgress
                      progress={message.progress}
                      running={streaming && index === messages.length - 1}
                    />
                  ) : null}
                  {message.content ? (
                    message.role === "assistant" ? (
                      <StreamingTokenResponse
                        className="leading-6"
                        content={message.content}
                        messageId={message.id}
                        streamDone={streamRenderState[message.id]?.done ?? !streaming}
                        streaming={streaming && index === messages.length - 1}
                      />
                    ) : (
                      <p className="whitespace-pre-wrap">{message.content}</p>
                    )
                  ) : streaming && index === messages.length - 1 ? (
                    <span className="text-slate-500">正在生成...</span>
                  ) : null}
                  {message.role === "assistant" ? (
                    <AgentMessageDetails
                      message={message}
                      onReplyPermission={onReplyPermission}
                      onReplyQuestion={onReplyQuestion}
                      onRejectQuestion={onRejectQuestion}
                    />
                  ) : null}
                </div>
              </MessageContent>
            </Message>
          </motion.div>
        ))}
      </AnimatePresence>
    </motion.div>
  );
}
