import { useEffect } from "react";
import { firstNonEmptyString, nextProtocolId } from "../utils";
import { makeMessage, mergeConversationMessages, messageFromAgentResponse, persistConversation } from "./conversation";
import { mergeTraceResults, snapshotToRunnerTrace, subscribeToTrace, type TraceSnapshot } from "./runner-trace";
import type { Action } from "./workbench-reducer";
import type { WorkbenchState } from "./workbench-state";
import type { AgentChatResultResponse, ChatMessage, WorkspaceRecord } from "../types/domain";

export interface UseTraceReattachConfig {
  enabled: boolean;
  projectId: string;
  activeTraceId: string | null;
  codeAgentTimeoutMs: number;
  chatPending: boolean;
  workspace: WorkbenchState["workspace"];
  messages: ChatMessage[];
  onActivity: () => void;
  onDispatch: (action: Action) => void;
  onPersist: typeof persistConversation;
}

export function useTraceReattach(config: UseTraceReattachConfig): void {
  const { enabled, projectId, activeTraceId, codeAgentTimeoutMs, chatPending, workspace, messages, onActivity, onDispatch, onPersist } = config;
  useEffect(() => {
    if (!enabled || !activeTraceId || chatPending) return;
    const resultUrl = `/v1/agent/chat/result/${encodeURIComponent(activeTraceId)}`;
    const conversationId = firstNonEmptyString(workspace?.selectedConversationId, workspace?.workspace?.selectedConversationId) ?? "";
    const sessionId = workspace?.selectedAgentSessionId ?? workspace?.workspace?.selectedAgentSessionId ?? null;
    const threadId = workspace?.workspace?.threadId ?? null;
    const existing = messages.find((m) => m.traceId === activeTraceId && m.role === "agent");
    const placeholderId = existing?.id ?? nextProtocolId("msg");
    if (!existing) {
      const placeholder = makeMessage("agent", "Re-attaching to running turn…", "running", { traceId: activeTraceId, conversationId, sessionId, threadId, title: "Code Agent 处理中" });
      const user = { ...placeholder, role: "user" as const, text: "(re-attach)", title: "用户" } as ChatMessage;
      onDispatch({ type: "message:pending", user, pending: placeholder, request: { traceId: activeTraceId, conversationId, sessionId, threadId } });
    }
    const controller = new AbortController();
    let lastSnapshot: TraceSnapshot | null = null;
    const ws: WorkspaceRecord | null = workspace;
    void subscribeToTrace({
      traceId: activeTraceId,
      projectId,
      initial: { status: "running", resultUrl, traceId: activeTraceId } as Parameters<typeof subscribeToTrace>[0]["initial"],
      inactivityTimeoutMs: codeAgentTimeoutMs,
      signal: controller.signal,
      onActivity: () => onActivity(),
      onSnapshot: (snapshot) => {
        lastSnapshot = snapshot;
        onDispatch({ type: "message:trace", messageId: placeholderId, trace: snapshotToRunnerTrace(snapshot) });
      },
      onComplete: (result: AgentChatResultResponse) => {
        const stub = messages.find((m) => m.id === placeholderId) ?? ({ id: placeholderId, role: "agent" as const, text: "", status: "running" as const, traceId: activeTraceId, conversationId, sessionId, threadId, createdAt: new Date().toISOString() } as ChatMessage);
        const completed = messageFromAgentResponse(placeholderId, stub, mergeTraceResults(result, lastSnapshot));
        onDispatch({ type: "message:complete", messageId: placeholderId, message: completed, availability: result.availability ?? null, workspace: ws ?? undefined });
        void onPersist({ workspace: ws, projectId, conversationId, sessionId: result.sessionId ?? sessionId, threadId: result.threadId ?? threadId, messages: mergeConversationMessages(messages, [completed]) });
        controller.abort();
      },
      onInfrastructureError: (error) => {
        const failed = makeMessage("agent", `Code Agent re-attach ${codeAgentTimeoutMs}ms 无活动（${error}）`, "failed", { traceId: activeTraceId, conversationId, sessionId, threadId, title: "Code Agent 超时" });
        onDispatch({ type: "message:fail", messageId: placeholderId, message: failed });
        void onPersist({ workspace: ws, projectId, conversationId, sessionId, threadId, messages: mergeConversationMessages(messages, [failed]) });
        controller.abort();
      }
    }).finally(() => controller.abort());
    return () => controller.abort();
  }, [enabled, projectId, activeTraceId, chatPending, codeAgentTimeoutMs, workspace, messages, onActivity, onDispatch, onPersist]);
}
