import { api } from "../services/api/client";
import type { ChatMessage, ConversationRecord, WorkspaceRecord } from "../types/domain";
import { firstNonEmptyString } from "../utils";
import { replayFullTrace, snapshotToRunnerTrace } from "./runner-trace";
import { WORKBENCH_PROJECT_ID, workspaceProjectId } from "./constants";

export interface RunnerActionsOptions {
  activeConversationId: string | null;
  projectId?: string;
  workspace: WorkspaceRecord | null;
  messages: ChatMessage[];
  codeAgentTimeoutMs: number;
  onReplaceMessage(messageId: string, message: ChatMessage): void;
  onTraceStatus(messageId: string, status: string): void;
  onTrace(messageId: string, trace: NonNullable<ChatMessage["runnerTrace"]>): void;
  submitMessage(text: string): Promise<void>;
}

export async function cancelAgentMessageAction(
  messageId: string,
  options: RunnerActionsOptions
): Promise<void> {
  const message = options.messages.find((item) => item.id === messageId);
  if (!message?.traceId) return;
  const response = await api.cancelAgentMessage({
    projectId: workspaceProjectId(options.workspace, options.projectId ?? WORKBENCH_PROJECT_ID),
    traceId: message.traceId,
    conversationId: message.conversationId ?? options.activeConversationId ?? undefined,
    sessionId: message.sessionId
      ?? options.workspace?.selectedAgentSessionId
      ?? options.workspace?.workspace?.selectedAgentSessionId
      ?? null,
    threadId: message.threadId ?? options.workspace?.workspace?.threadId ?? null
  });
  const canceled = response.data?.canceled === true;
  const errorObject = response.data?.error;
  const errorMessageText = typeof errorObject === "object" && errorObject && "message" in errorObject
    ? String((errorObject as { message?: unknown }).message ?? "")
    : "";
  if (canceled) {
    const next: ChatMessage = {
      ...message,
      title: "Code Agent 已取消",
      text: (response.data as { userMessage?: string } | null)?.userMessage ?? "当前 Codex stdio 请求已取消；输入、sessionId、traceId 和最后 trace event 已保留，可重试上一条消息。",
      status: "canceled",
      updatedAt: new Date().toISOString(),
      error: errorObject
        ? { ...(typeof errorObject === "object" ? errorObject : {}), code: "codex_stdio_canceled" }
        : { code: "codex_stdio_canceled", message: "user canceled current Code Agent request" }
    };
    options.onReplaceMessage(messageId, next);
  } else {
    const failure: ChatMessage = {
      ...message,
      title: "Code Agent 取消受阻",
      text: errorMessageText || response.error || "当前请求没有可取消的 in-flight Codex stdio session；输入和 trace 已保留。",
      status: "failed",
      updatedAt: new Date().toISOString(),
      traceReplayStatus: errorMessageText || "取消未确认"
    };
    options.onReplaceMessage(messageId, failure);
  }
}

export async function retryAgentMessageAction(
  messageId: string,
  options: RunnerActionsOptions
): Promise<void> {
  const message = options.messages.find((item) => item.id === messageId);
  if (!message?.retryInput) return;
  await options.submitMessage(message.retryInput);
}

export async function replayAgentTraceAction(
  messageId: string,
  options: RunnerActionsOptions
): Promise<void> {
  const message = options.messages.find((item) => item.id === messageId);
  if (!message?.traceId) return;
  const snapshot = await replayFullTrace(message.traceId, Math.max(8000, options.codeAgentTimeoutMs), workspaceProjectId(options.workspace, options.projectId ?? WORKBENCH_PROJECT_ID));
  if (!snapshot) {
    options.onTraceStatus(messageId, "trace 回放失败");
    return;
  }
  options.onTrace(messageId, snapshotToRunnerTrace(snapshot));
  options.onTraceStatus(messageId, `完整 trace 已回放：${snapshot.events?.length ?? 0} 个原始 event；${snapshot.lastEventLabel ?? ""}`);
}
