// SPEC: PJ2026-0104010803 Workbench唯一投影 draft-2026-06-24-p1-opencode-message-part-authority.
// Responsibility: AgentRun cancel disposition payloads and cancel trace diagnostics.

export function agentRunCancelTerminalStatus(payload = null) {
  if (!payload || typeof payload !== "object") return null;
  for (const value of [payload.agentRun?.terminalStatus, payload.agentRun?.commandState, payload.agentRun?.commandStatus]) {
    const status = normalizeAgentRunStatus(value);
    if (isAgentRunTerminalStatus(status)) return status;
  }
  return null;
}

export function agentRunAlreadyTerminalCancelPayload({ traceId, payload, terminalStatus, options = {}, traceStore } = {}) {
  const normalizedTerminalStatus = normalizeAgentRunStatus(terminalStatus);
  const agentRun = payload?.agentRun && typeof payload.agentRun === "object" ? payload.agentRun : {};
  traceStore?.append?.(traceId, agentRunCancelTraceEvent({
    type: "cancel",
    status: normalizedTerminalStatus || "completed",
    label: "agentrun:cancel:already-terminal",
    message: "AgentRun command is already terminal; HWLAB did not forward cancel or overwrite the terminal Workbench projection.",
    runId: agentRun.runId,
    commandId: agentRun.commandId,
    terminal: true,
    valuesPrinted: false
  }, agentRun));
  const payloadStatus = normalizeAgentRunStatus(payload?.status);
  const status = isAgentRunTerminalStatus(payloadStatus) ? payloadStatus : normalizedTerminalStatus || payloadStatus || "completed";
  const result = {
    ...payload,
    status,
    canceled: false,
    alreadyTerminal: true,
    cancelStatus: "already_terminal",
    cancelDisposition: {
      status: "already_terminal",
      forwarded: false,
      terminal: true,
      traceId,
      runId: agentRun.runId ?? null,
      commandId: agentRun.commandId ?? null,
      route: "/v1/agent/chat/cancel",
      valuesPrinted: false
    },
    updatedAt: nowIso(options.now),
    runnerTrace: traceStore?.snapshot?.(traceId),
    agentRun: { ...agentRun, terminalStatus: agentRun.terminalStatus ?? normalizedTerminalStatus, valuesPrinted: false },
    valuesPrinted: false
  };
  options.codeAgentChatResults?.set?.(traceId, result);
  return result;
}

export function agentRunCancelBlockedPayload({ traceId, payload, error, cancelPath, options = {}, traceStore } = {}) {
  const agentRun = payload?.agentRun && typeof payload.agentRun === "object" ? payload.agentRun : {};
  const code = firstNonEmpty(error?.code, error?.agentRunError?.failureKind, "agentrun_cancel_failed");
  const statusCode = Number.isFinite(Number(error?.statusCode)) ? Number(error.statusCode) : 502;
  const message = firstNonEmpty(error?.message, error?.agentRunError?.message, "AgentRun command cancel API did not accept the cancel request.");
  const userMessage = "取消请求未被 AgentRun 接受；已保留当前 trace/run/command 证据，页面不能把本轮伪装成已取消。";
  const now = nowIso(options.now);
  const nextAgentRun = { ...agentRun, cancelStatus: "blocked", cancelErrorCode: code, cancelStatusCode: statusCode, updatedAt: now, valuesPrinted: false };
  traceStore?.append?.(traceId, agentRunCancelTraceEvent({
    type: "cancel",
    status: "blocked",
    label: "agentrun:cancel:blocked",
    errorCode: code,
    message: `AgentRun cancel was not accepted by the command cancel API: ${message}`,
    runId: agentRun.runId,
    commandId: agentRun.commandId,
    waitingFor: "agentrun-cancel-disposition",
    terminal: false,
    valuesPrinted: false
  }, nextAgentRun));
  const cancelDisposition = {
    status: "blocked",
    code,
    statusCode,
    message,
    userMessage,
    retryable: true,
    terminal: false,
    route: "/v1/agent/chat/cancel",
    upstreamRoute: cancelPath,
    traceId,
    runId: agentRun.runId ?? null,
    commandId: agentRun.commandId ?? null,
    valuesPrinted: false
  };
  const result = {
    ...payload,
    status: "blocked",
    canceled: false,
    cancelStatus: "blocked",
    cancelDisposition,
    updatedAt: now,
    agentRun: nextAgentRun,
    runnerTrace: traceStore?.snapshot?.(traceId),
    error: { code, layer: "agentrun", category: "cancel-blocked", retryable: true, message, userMessage, traceId, route: "/v1/agent/chat/cancel", upstreamRoute: cancelPath, statusCode, toolName: "agentrun.command.cancel", valuesPrinted: false },
    userMessage,
    valuesPrinted: false
  };
  options.codeAgentChatResults?.set?.(traceId, result);
  return result;
}

function agentRunCancelTraceEvent(event = {}, agentRun = {}) {
  return {
    ...event,
    backend: "agentrun-v01",
    adapter: "agentrun-v01",
    runId: event.runId ?? agentRun.runId ?? null,
    commandId: event.commandId ?? agentRun.commandId ?? null,
    valuesPrinted: false
  };
}

function isAgentRunTerminalStatus(value) {
  return ["completed", "failed", "blocked", "cancelled", "canceled"].includes(normalizeAgentRunStatus(value));
}

function normalizeAgentRunStatus(value) {
  return String(value ?? "").trim().toLowerCase().replace(/_/gu, "-");
}

function firstNonEmpty(...values) {
  for (const value of values) {
    const text = String(value ?? "").trim();
    if (text) return text;
  }
  return null;
}

function nowIso(now) {
  return typeof now === "function" ? now() : new Date().toISOString();
}
