import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useChat } from "@ai-sdk/react";
import { DefaultChatTransport } from "ai";
import useSWR from "swr";
import useSWRImmutable from "swr/immutable";
import type { PersonaState } from "@/shared/ai-elements/persona";
import { env } from "@/shared/config/env";
import { showMapNotice } from "@/features/map/core";
import {
  FrontendActionExecutor,
  agentBootstrapKey,
  agentSessionsKey,
  createAgentApiClient,
  fetchAgentBootstrap,
  fetchAgentSessions,
  hasPendingAgentInput,
  isUiEnvelopeAllowed,
  parseUiEnvelopePayload,
  type AgentApprovalMode,
  type AgentChatMessage,
  type AgentConnectionStatus,
  type AgentModelOption,
  type AgentPermissionReply,
  type AgentPermissionRequest,
  type AgentQuestionRequest,
  type AgentSessionStreamEvent,
  type AgentStreamRenderState,
  type FrontendActionRequest,
  type UIEnvelopePayload,
  type UIRegistry
} from "@/features/agent";
import {
  applySessionStreamEvent,
  createCompletedStreamRenderState,
  getDataString,
  markLastAssistantStreamDone,
  markStreamRenderPending,
  readBodyString,
  toAgentChatMessages,
  toAgentUiMessages,
  toPermissionStatus,
  type AgentDataPart,
  type AgentUiMessage,
  type PermissionOverride,
  type QuestionOverride
} from "./agent-session-message-state";

const AGENT_PANEL_COLLAPSE_MS = 180;

type UseWorkbenchAgentOptions = {
  onUiEnvelope: (payload: UIEnvelopePayload, sessionId: string) => Promise<void> | void;
  onFrontendAction: (request: FrontendActionRequest, signal: AbortSignal) => Promise<unknown>;
};

export function useWorkbenchAgent({ onUiEnvelope, onFrontendAction }: UseWorkbenchAgentOptions) {
  const collapseTimerRef = useRef<number | null>(null);
  const mobileCollapseTimerRef = useRef<number | null>(null);
  const sessionStreamAbortRef = useRef<AbortController | null>(null);
  const clientRef = useRef(createAgentApiClient());
  const sessionIdRef = useRef<string | null>(null);
  const approvalModeRef = useRef<AgentApprovalMode>("request");
  const registryRef = useRef<UIRegistry | null>(null);
  const frontendActionEnabledRef = useRef(false);
  const onFrontendActionRef = useRef(onFrontendAction);
  const processedEnvelopeIdsRef = useRef(new Set<string>());
  const [panelOpen, setPanelOpen] = useState(true);
  const [panelCollapsing, setPanelCollapsing] = useState(false);
  const [mobileOpen, setMobileOpen] = useState(false);
  const [mobilePanelCollapsing, setMobilePanelCollapsing] = useState(false);
  const [sessionId, setSessionId] = useState<string | null>(null);
  const [registry, setRegistry] = useState<UIRegistry | null>(null);
  const [sessionTitle, setSessionTitle] = useState("新对话");
  const [statusLabel, setStatusLabel] = useState("Agent 后端连接中");
  const [connectionStatus, setConnectionStatus] =
    useState<AgentConnectionStatus>("connecting");
  const [resumedStreaming, setResumedStreaming] = useState(false);
  const [modelOptions, setModelOptions] = useState<AgentModelOption[]>([]);
  const [selectedModel, setSelectedModel] = useState("");
  const [approvalMode, setApprovalModeState] = useState<AgentApprovalMode>("request");
  const [streamRenderState, setStreamRenderState] = useState<AgentStreamRenderState>({});
  const [permissionOverrides, setPermissionOverrides] = useState<Record<string, PermissionOverride>>({});
  const [questionOverrides, setQuestionOverrides] = useState<Record<string, QuestionOverride>>({});

  useEffect(() => {
    sessionIdRef.current = sessionId;
  }, [sessionId]);

  const setApprovalMode = useCallback((mode: AgentApprovalMode) => {
    approvalModeRef.current = mode;
    setApprovalModeState(mode);
  }, []);

  useEffect(() => {
    registryRef.current = registry;
  }, [registry]);

  useEffect(() => {
    onFrontendActionRef.current = onFrontendAction;
  }, [onFrontendAction]);

  const applySessionId = useCallback((nextSessionId: string | undefined) => {
    if (!nextSessionId || sessionIdRef.current === nextSessionId) {
      return;
    }
    sessionIdRef.current = nextSessionId;
    setSessionId(nextSessionId);
  }, []);

  const clearSessionId = useCallback(() => {
    sessionIdRef.current = null;
    setSessionId(null);
  }, []);

  const resolveRenderRef = useCallback((renderRef: string, nextSessionId: string) => {
    return clientRef.current.resolveRenderRef(renderRef, nextSessionId);
  }, []);

  const frontendActionExecutor = useMemo(
    () => new FrontendActionExecutor(
      (request, signal) => onFrontendActionRef.current(request, signal),
      (nextSessionId, actionId, result) => clientRef.current.submitFrontendActionResult(nextSessionId, actionId, result)
    ),
    []
  );
  const handleFrontendAction = useCallback(
    (value: unknown) => frontendActionExecutor.handle(value, sessionIdRef.current),
    [frontendActionExecutor]
  );

  const claimEnvelope = useCallback((payload: UIEnvelopePayload, activeSessionId: string) => {
    if (payload.session_id !== activeSessionId) return false;
    const key = `${activeSessionId}:${payload.envelope_id}`;
    if (processedEnvelopeIdsRef.current.has(key)) return false;
    processedEnvelopeIdsRef.current.add(key);
    if (processedEnvelopeIdsRef.current.size > 256) {
      const oldest = processedEnvelopeIdsRef.current.values().next().value;
      if (oldest) processedEnvelopeIdsRef.current.delete(oldest);
    }
    return true;
  }, []);

  const handleDataPart = useCallback(
    (part: AgentDataPart) => {
      setConnectionStatus("online");
      const eventSessionId = getDataString(part.data, "session_id");
      if (eventSessionId && sessionIdRef.current && eventSessionId !== sessionIdRef.current) {
        return;
      }
      applySessionId(eventSessionId);

      if (part.type === "data-stream_token") {
        markStreamRenderPending(
          part.data,
          chatRef.current.messages,
          setStreamRenderState
        );
        return;
      }

      if (part.type === "data-progress") {
        const title = getDataString(part.data, "title");
        if (title) {
          setStatusLabel(title);
        }
        return;
      }
      if (part.type === "data-frontend_action") { void handleFrontendAction(part.data); return; }

      if (part.type === "data-session_title") {
        const title = getDataString(part.data, "title");
        if (title) {
          setSessionTitle(title);
        }
        return;
      }

      if (part.type !== "data-ui_envelope") {
        return;
      }

      const payload = parseUiEnvelopePayload(part.data);
      const activeSessionId = getDataString(part.data, "session_id") ?? sessionIdRef.current;
      if (!payload || !activeSessionId || !isUiEnvelopeAllowed(payload.envelope, registryRef.current)) {
        showMapNotice({
          tone: "warning",
          title: "Agent 展示已降级",
          message: "收到的 UIEnvelope 未通过前端白名单校验。"
        });
        return;
      }
      if (!claimEnvelope(payload, activeSessionId)) return;

      void Promise.resolve(onUiEnvelope(payload, activeSessionId)).catch((error) => {
        showMapNotice({
          tone: "error",
          title: "Agent UIEnvelope 处理失败",
          message: error instanceof Error ? error.message : "工作台处理 Agent 展示结果失败。"
        });
      });
    },
    [applySessionId, claimEnvelope, handleFrontendAction, onUiEnvelope]
  );

  const transport = useMemo(
    () =>
      new DefaultChatTransport<AgentUiMessage>({
        api: `${env.TJWATER_AGENT_API_BASE_URL.replace(/\/$/, "")}/api/v1/agent/chat/stream`,
        prepareSendMessagesRequest({ id, messages, body, trigger, messageId }) {
          return {
            body: {
              ...body,
              id,
              messages,
              trigger,
              messageId,
              session_id: readBodyString(body, "session_id") ?? sessionIdRef.current ?? undefined,
              approval_mode: readBodyString(body, "approval_mode") ?? approvalModeRef.current,
              capabilities: frontendActionEnabledRef.current ? ["frontend-action@1"] : []
            }
          };
        }
      }),
    []
  );

  const chat = useChat<AgentUiMessage>({
    transport,
    onData: (part) => handleDataPart(part as AgentDataPart),
    onError: (error) => {
      markLastAssistantStreamDone(chatRef.current.messages, setStreamRenderState);
      setConnectionStatus("offline");
      setStatusLabel("Agent 后端请求失败");
      showMapNotice({
        id: "agent-stream-status",
        tone: "error",
        title: "Agent 请求失败",
        message: error.message || "请确认后端服务已启动。"
      });
    },
    onFinish: () => {
      markLastAssistantStreamDone(chatRef.current.messages, setStreamRenderState);
      setConnectionStatus("online");
      setStatusLabel("Agent 分析完成");
    }
  });
  const chatRef = useRef(chat);

  useEffect(() => {
    chatRef.current = chat;
  }, [chat]);

  const {
    data: backendConnection,
    error: backendConnectionError
  } = useSWRImmutable(agentBootstrapKey, () => fetchAgentBootstrap(clientRef.current), {
    shouldRetryOnError: false
  });
  const {
    data: sessionHistory = [],
    isLoading: sessionHistoryLoading,
    isValidating: sessionHistoryValidating,
    mutate: mutateSessionHistory
  } = useSWR(agentSessionsKey, () => fetchAgentSessions(clientRef.current), {
    revalidateOnFocus: false,
    shouldRetryOnError: false
  });

  const clearCollapseTimer = useCallback(() => {
    if (collapseTimerRef.current !== null) {
      window.clearTimeout(collapseTimerRef.current);
      collapseTimerRef.current = null;
    }
  }, []);

  const clearMobileCollapseTimer = useCallback(() => {
    if (mobileCollapseTimerRef.current !== null) {
      window.clearTimeout(mobileCollapseTimerRef.current);
      mobileCollapseTimerRef.current = null;
    }
  }, []);

  const stopSessionStreamSubscription = useCallback(() => {
    sessionStreamAbortRef.current?.abort();
    sessionStreamAbortRef.current = null;
    setResumedStreaming(false);
  }, []);

  useEffect(() => {
    return () => {
      clearCollapseTimer();
      clearMobileCollapseTimer();
      stopSessionStreamSubscription();
      frontendActionExecutor.cancelAll();
      chatRef.current.stop();
    };
  }, [clearCollapseTimer, clearMobileCollapseTimer, frontendActionExecutor, stopSessionStreamSubscription]);

  useEffect(() => {
    if (!backendConnection) {
      return;
    }

    registryRef.current = backendConnection.registry;
    frontendActionEnabledRef.current = Boolean(backendConnection.frontendActionRegistry);
    setRegistry(backendConnection.registry);
    setModelOptions(backendConnection.models);
    setSelectedModel((current) => current || backendConnection.defaultModel || backendConnection.models[0]?.id || "");
    if (chatRef.current.status === "ready") {
      setConnectionStatus("online");
      setStatusLabel("准备就绪");
    }
  }, [backendConnection]);

  useEffect(() => {
    if (!backendConnectionError) {
      return;
    }

    setConnectionStatus("offline");
    setStatusLabel("Agent 后端不可用");
  }, [backendConnectionError]);

  const collapsePanel = useCallback(() => {
    clearCollapseTimer();

    if (prefersReducedMotion()) {
      setPanelOpen(false);
      setPanelCollapsing(false);
      return;
    }

    setPanelCollapsing(true);
    collapseTimerRef.current = window.setTimeout(() => {
      setPanelOpen(false);
      setPanelCollapsing(false);
      collapseTimerRef.current = null;
    }, AGENT_PANEL_COLLAPSE_MS);
  }, [clearCollapseTimer]);

  const expandPanel = useCallback(() => {
    clearCollapseTimer();
    setPanelCollapsing(false);
    setPanelOpen(true);
  }, [clearCollapseTimer]);

  const openMobilePanel = useCallback(() => {
    clearMobileCollapseTimer();
    setMobilePanelCollapsing(false);
    setMobileOpen(true);
  }, [clearMobileCollapseTimer]);

  const closeMobilePanel = useCallback(() => {
    clearMobileCollapseTimer();

    if (prefersReducedMotion()) {
      setMobileOpen(false);
      setMobilePanelCollapsing(false);
      return;
    }

    setMobilePanelCollapsing(true);
    mobileCollapseTimerRef.current = window.setTimeout(() => {
      setMobileOpen(false);
      setMobilePanelCollapsing(false);
      mobileCollapseTimerRef.current = null;
    }, AGENT_PANEL_COLLAPSE_MS);
  }, [clearMobileCollapseTimer]);

  const streaming = chat.status === "submitted" || chat.status === "streaming" || resumedStreaming;
  const messages = useMemo(
    () => toAgentChatMessages(chat.messages, permissionOverrides, questionOverrides),
    [chat.messages, permissionOverrides, questionOverrides]
  );
  const personaState = useMemo(
    () => deriveAgentPersonaState(messages, {
      chatStatus: chat.status,
      connectionStatus
    }),
    [chat.status, connectionStatus, messages]
  );

  const refreshSessionHistory = useCallback(async () => {
    try {
      await mutateSessionHistory();
    } catch (error) {
      showMapNotice({
        id: "agent-history-status",
        tone: "error",
        title: "Agent 历史记录加载失败",
        message: error instanceof Error ? error.message : "无法获取 Agent 会话历史。"
      });
    }
  }, [mutateSessionHistory]);

  const handleSessionStreamEvent = useCallback(
    (event: AgentSessionStreamEvent, expectedSessionId: string) => {
      if (event.type === "state") {
        if (sessionIdRef.current !== expectedSessionId && sessionIdRef.current !== event.sessionId) {
          return;
        }
        const nextMessages = toAgentUiMessages(event.messages);
        chatRef.current.setMessages(nextMessages);
        setStreamRenderState(createCompletedStreamRenderState(nextMessages));
        setResumedStreaming(event.isStreaming);
        setStatusLabel(event.isStreaming ? "Agent 会话流已恢复" : "Agent 历史会话已打开");
        return;
      }

      const eventSessionId = event.sessionId;
      if (eventSessionId && eventSessionId !== sessionIdRef.current) {
        return;
      }

      if (event.type === "session_title") {
        const title = getDataString(event.data, "title");
        if (title) {
          setSessionTitle(title);
        }
      } else if (event.type === "token") {
        markStreamRenderPending(
          event.data,
          chatRef.current.messages,
          setStreamRenderState
        );
      } else if (event.type === "ui_envelope") {
        const payload = parseUiEnvelopePayload(event.data);
        const activeSessionId = eventSessionId ?? sessionIdRef.current;
        if (!payload || !activeSessionId || !isUiEnvelopeAllowed(payload.envelope, registryRef.current)) {
          showMapNotice({
            tone: "warning",
            title: "Agent 展示已降级",
            message: "收到的 UIEnvelope 未通过前端白名单校验。"
          });
          return;
        }
        if (!claimEnvelope(payload, activeSessionId)) return;
        void Promise.resolve(onUiEnvelope(payload, activeSessionId)).catch((error) => {
          showMapNotice({
            tone: "error",
            title: "Agent UIEnvelope 处理失败",
            message: error instanceof Error ? error.message : "工作台处理 Agent 展示结果失败。"
          });
        });
      } else if (event.type === "frontend_action") {
        void handleFrontendAction(event.data);
      } else if (event.type === "progress") {
        const title = getDataString(event.data, "title");
        if (title) {
          setStatusLabel(title);
        }
      } else if (event.type === "done") {
        setResumedStreaming(false);
        markLastAssistantStreamDone(chatRef.current.messages, setStreamRenderState);
        setStatusLabel("Agent 分析完成");
        void refreshSessionHistory();
      } else if (event.type === "error") {
        setResumedStreaming(false);
        markLastAssistantStreamDone(chatRef.current.messages, setStreamRenderState);
        setStatusLabel("Agent 后端请求失败");
        void refreshSessionHistory();
      }

      chatRef.current.setMessages((current) => applySessionStreamEvent(current, event));
    },
    [claimEnvelope, handleFrontendAction, onUiEnvelope, refreshSessionHistory]
  );

  const startSessionStreamSubscription = useCallback(
    (nextSessionId: string) => {
      stopSessionStreamSubscription();

      const controller = new AbortController();
      sessionStreamAbortRef.current = controller;
      setResumedStreaming(true);

      void clientRef.current
        .streamSession(nextSessionId, {
          signal: controller.signal,
          onEvent: (event) => handleSessionStreamEvent(event, nextSessionId)
        })
        .catch((error) => {
          if (!controller.signal.aborted) {
            setConnectionStatus("offline");
            setStatusLabel("Agent 会话流恢复失败");
            showMapNotice({
              id: "agent-stream-status",
              tone: "error",
              title: "Agent 会话流恢复失败",
              message: error instanceof Error ? error.message : "无法恢复这个运行中的会话。"
            });
          }
        })
        .finally(() => {
          if (sessionStreamAbortRef.current === controller) {
            sessionStreamAbortRef.current = null;
            setResumedStreaming(false);
            void refreshSessionHistory();
          }
        });
    },
    [handleSessionStreamEvent, refreshSessionHistory, stopSessionStreamSubscription]
  );

  const loadHistorySession = useCallback(
    async (nextSessionId: string) => {
      if (streaming) {
        chat.stop();
        stopSessionStreamSubscription();
      }

      try {
        const loadedSession = await clientRef.current.loadSession(nextSessionId);
        if (!loadedSession) {
          showMapNotice({
            id: "agent-history-status",
            tone: "warning",
            title: "Agent 历史记录不可用",
            message: "这个历史会话不存在或已被删除。"
          });
          await refreshSessionHistory();
          return;
        }

        applySessionId(loadedSession.sessionId);
        setSessionTitle(loadedSession.title);
        setStatusLabel("Agent 历史会话已打开");
        setPermissionOverrides({});
        setQuestionOverrides({});
        const nextMessages = toAgentUiMessages(loadedSession.messages);
        chat.setMessages(nextMessages);
        setStreamRenderState(createCompletedStreamRenderState(nextMessages));
        if (loadedSession.runStatus === "running" || loadedSession.isStreaming) {
          startSessionStreamSubscription(loadedSession.sessionId);
        }
        await refreshSessionHistory();
      } catch (error) {
        showMapNotice({
          id: "agent-history-status",
          tone: "error",
          title: "Agent 历史记录打开失败",
          message: error instanceof Error ? error.message : "无法打开这个历史会话。"
        });
      }
    },
    [applySessionId, chat, refreshSessionHistory, startSessionStreamSubscription, stopSessionStreamSubscription, streaming]
  );

  const renameHistorySession = useCallback(
    async (nextSessionId: string, title: string) => {
      const normalizedTitle = title.trim();
      if (!normalizedTitle) {
        showMapNotice({ tone: "warning", message: "对话主题不能为空。" });
        return;
      }

      try {
        await clientRef.current.updateSessionTitle(nextSessionId, normalizedTitle, {
          isTitleManuallyEdited: true
        });
        await mutateSessionHistory(
          (current = []) =>
            current.map((session) =>
              session.id === nextSessionId
                ? {
                    ...session,
                    title: normalizedTitle,
                    updatedAt: Date.now()
                  }
                : session
            ),
          { revalidate: false }
        );
        if (sessionIdRef.current === nextSessionId) {
          setSessionTitle(normalizedTitle);
        }
        await refreshSessionHistory();
      } catch (error) {
        showMapNotice({
          id: "agent-history-status",
          tone: "error",
          title: "Agent 对话重命名失败",
          message: error instanceof Error ? error.message : "无法更新这个对话主题。"
        });
      }
    },
    [mutateSessionHistory, refreshSessionHistory]
  );

  const resetDraftSession = useCallback(
    (nextStatusLabel = "Agent 新对话已准备") => {
      clearSessionId();
      setSessionTitle("新对话");
      setStatusLabel(nextStatusLabel);
      setConnectionStatus("online");
      setPermissionOverrides({});
      setQuestionOverrides({});
      setStreamRenderState({});
      chat.setMessages([]);
    },
    [chat, clearSessionId]
  );

  const deleteHistorySession = useCallback(
    async (nextSessionId: string) => {
      if (streaming) {
        showMapNotice({ tone: "warning", message: "Agent 正在处理上一条指令，完成后再删除会话。" });
        return false;
      }

      try {
        await clientRef.current.deleteSession(nextSessionId);
        await mutateSessionHistory(
          (current = []) => current.filter((session) => session.id !== nextSessionId),
          { revalidate: false }
        );

        if (sessionIdRef.current === nextSessionId) {
          resetDraftSession();
        }

        await refreshSessionHistory();
        return true;
      } catch (error) {
        showMapNotice({
          id: "agent-history-status",
          tone: "error",
          title: "Agent 历史记录删除失败",
          message: error instanceof Error ? error.message : "无法删除这个历史会话。"
        });
        return false;
      }
    },
    [mutateSessionHistory, refreshSessionHistory, resetDraftSession, streaming]
  );

  const startNewSession = useCallback(async () => {
    if (chat.status === "submitted" || chat.status === "streaming") {
      chat.stop();
    }
    stopSessionStreamSubscription();

    resetDraftSession();
  }, [chat, resetDraftSession, stopSessionStreamSubscription]);

  const submitPrompt = useCallback(
    async (prompt: string) => {
      const normalizedPrompt = prompt.trim();
      if (!normalizedPrompt) {
        return;
      }

      if (streaming) {
        showMapNotice({ tone: "warning", message: "Agent 正在处理上一条指令。" });
        return;
      }

      setStatusLabel("Agent 正在分析");

      await chat.sendMessage(
        { text: normalizedPrompt },
        {
          body: {
            session_id: sessionIdRef.current ?? undefined,
            model: selectedModel || undefined,
            approval_mode: approvalMode
          }
        }
      );
    },
    [approvalMode, chat, selectedModel, streaming]
  );

  const stopPrompt = useCallback(() => {
    chat.stop();
    stopSessionStreamSubscription();
    const activeSessionId = sessionIdRef.current;
    if (activeSessionId) {
      void clientRef.current.abort(activeSessionId).catch(() => undefined);
    }
    markLastAssistantStreamDone(chatRef.current.messages, setStreamRenderState);
  }, [chat, stopSessionStreamSubscription]);

  const replyPermission = useCallback(async (permission: AgentPermissionRequest, reply: AgentPermissionReply) => {
    setPermissionOverrides((current) => ({
      ...current,
      [permission.requestId]: { status: "submitting" }
    }));

    try {
      await clientRef.current.replyPermission(permission.requestId, {
        sessionId: permission.sessionId,
        reply
      });
      setPermissionOverrides((current) => ({
        ...current,
        [permission.requestId]: {
          status: toPermissionStatus(reply)
        }
      }));
    } catch (error) {
      const message = error instanceof Error ? error.message : "权限请求提交失败。";
      setPermissionOverrides((current) => ({
        ...current,
        [permission.requestId]: {
          status: "error",
          error: message
        }
      }));
      showMapNotice({
        id: "agent-permission-status",
        tone: "error",
        title: "Agent 权限提交失败",
        message
      });
    }
  }, []);

  const replyQuestion = useCallback(async (question: AgentQuestionRequest, answers: string[][]) => {
    setQuestionOverrides((current) => ({
      ...current,
      [question.requestId]: { status: "submitting" }
    }));

    try {
      await clientRef.current.replyQuestion(question.requestId, {
        sessionId: question.sessionId,
        answers
      });
      setQuestionOverrides((current) => ({
        ...current,
        [question.requestId]: {
          status: "answered",
          answers
        }
      }));
    } catch (error) {
      const message = error instanceof Error ? error.message : "问题回复提交失败。";
      setQuestionOverrides((current) => ({
        ...current,
        [question.requestId]: {
          status: "error",
          error: message
        }
      }));
      showMapNotice({
        id: "agent-question-status",
        tone: "error",
        title: "Agent 问题提交失败",
        message
      });
    }
  }, []);

  const rejectQuestion = useCallback(async (question: AgentQuestionRequest) => {
    setQuestionOverrides((current) => ({
      ...current,
      [question.requestId]: { status: "submitting" }
    }));

    try {
      await clientRef.current.rejectQuestion(question.requestId, {
        sessionId: question.sessionId
      });
      setQuestionOverrides((current) => ({
        ...current,
        [question.requestId]: {
          status: "rejected"
        }
      }));
    } catch (error) {
      const message = error instanceof Error ? error.message : "问题跳过提交失败。";
      setQuestionOverrides((current) => ({
        ...current,
        [question.requestId]: {
          status: "error",
          error: message
        }
      }));
      showMapNotice({
        id: "agent-question-status",
        tone: "error",
        title: "Agent 问题提交失败",
        message
      });
    }
  }, []);

  return {
    approvalMode,
    collapsePanel,
    expandPanel,
    mobileOpen,
    mobilePanelCollapsing,
    messages,
    modelOptions,
    openMobilePanel,
    closeMobilePanel,
    connectionStatus,
    panelCollapsing,
    panelOpen,
    personaState,
    refreshSessionHistory,
    startNewSession,
    loadHistorySession,
    renameHistorySession,
    deleteHistorySession,
    sessionHistory,
    sessionHistoryLoading: sessionHistoryLoading || sessionHistoryValidating,
    sessionId,
    sessionTitle,
    statusLabel,
    streamRenderState,
    selectedModel,
    setApprovalMode,
    setSelectedModel,
    stopPrompt,
    streaming,
    rejectQuestion,
    replyPermission,
    replyQuestion,
    resolveRenderRef,
    submitPrompt
  };
}

function deriveAgentPersonaState(
  messages: AgentChatMessage[],
  {
    chatStatus,
    connectionStatus
  }: {
    chatStatus: string;
    connectionStatus: AgentConnectionStatus;
  }
): PersonaState {
  if (connectionStatus === "offline") {
    return "asleep";
  }

  if (hasPendingAgentInput(messages)) {
    return "listening";
  }

  if (
    chatStatus === "submitted" ||
    chatStatus === "streaming" ||
    hasRunningSessionWork(messages) ||
    connectionStatus === "connecting"
  ) {
    return "thinking";
  }

  return "idle";
}

function hasRunningSessionWork(messages: AgentChatMessage[]) {
  const latestProgress = messages.flatMap((message) => message.progress ?? []).at(-1);
  const latestTodo = messages.flatMap((message) => message.todos?.todos ?? []).at(-1);

  return latestProgress?.status === "running" || latestTodo?.status === "in_progress";
}

function prefersReducedMotion() {
  return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
}
