/**
 * Wire format for the agent builder/chat SSE stream. Each SSE `data:` line is
 * exactly one `AgentSseEvent` JSON object.
 *
 * Per-turn events carry the SDK's natural block ids:
 *
 * - `text-*` and `reasoning-*` events carry the SDK's per-block `id`.
 * - `tool-*` events carry the SDK's `toolCallId`.
 * - `start-step` / `finish-step` mark LLM iteration boundaries.
 *
 * The frontend groups deltas by these ids and uses `start-step` / `finish-step`
 * to decide when a new ChatMessage cursor should open. There is no
 * server-minted `messageId` — the FE generates its own UUID per ChatMessage
 * for v-for keys only.
 *
 * `runId` is included on `ToolSuspendedPayload` and echoed back by the
 * frontend on resume. The SDK stores `runId` on each `PendingToolCall` and
 * surfaces it on every suspended-tool chunk; the FE doesn't need to derive it
 * server-side.
 *
 * Note: there is no separate "resumed" event. After the user resumes a
 * suspended tool, the SDK runs the tool's handler (which returns
 * `ctx.resumeData`) and emits a normal `tool-result` event. Consumers see the
 * resume payload as the `output` on that `tool-result`.
 *
 */

import type { AgentPersistedMessageContentPart } from './agents';

export interface ToolSuspendedPayload {
	toolCallId: string;
	/** Run id of the suspended turn; FE echoes this back on `POST /:agentId/chat/:threadId/resume`. */
	runId: string;
	/** Also the discriminator on the wire (no separate interactionType field). */
	toolName: string;
	/** The tool's suspend payload; shape determined by toolName via the shared interaction-contract suspend schemas (`agents/agent-interaction.schema.ts`). */
	input: unknown;
}

/**
 * Custom (sub-agent / app-defined) message envelope. Tool-call and tool-result
 * events ride their own discrete chunk types — only `CustomAgentMessage`-style
 * payloads use this shape.
 */
export interface AgentSseMessage {
	role: string;
	content: AgentPersistedMessageContentPart[];
}

/**
 * Child stream chunks forwarded live while a `delegate_subagent` tool runs.
 * Structural mirror of `@n8n/agents` `ForwardedChildChunk` (api-types cannot
 * import from that package).
 */
export type ForwardedChildChunkWire =
	| { type: 'text-delta'; id: string; delta: string }
	| { type: 'reasoning-start'; id: string }
	| { type: 'reasoning-delta'; id: string; delta: string }
	| { type: 'reasoning-end'; id: string }
	| { type: 'tool-input-start'; toolCallId: string; toolName: string }
	| {
			type: 'tool-execution-start';
			toolCallId: string;
			toolName: string;
			startTime: number;
	  }
	| {
			type: 'tool-execution-end';
			toolCallId: string;
			toolName: string;
			isError: boolean;
			endTime: number;
	  };

export type AgentSseEvent =
	| { type: 'start-step' }
	| { type: 'finish-step' }
	| { type: 'text-start'; id: string }
	| { type: 'text-delta'; id: string; delta: string }
	| { type: 'text-end'; id: string }
	| { type: 'reasoning-start'; id: string }
	| { type: 'reasoning-delta'; id: string; delta: string }
	| { type: 'reasoning-end'; id: string }
	| { type: 'tool-input-start'; toolCallId: string; toolName: string }
	| { type: 'tool-input-delta'; toolCallId: string; delta: string }
	| { type: 'tool-call'; toolCallId: string; toolName: string; input: unknown }
	| {
			/**
			 * Mid-flight indicator: the LLM has finished emitting the tool call and
			 * the runtime has started invoking the handler. Sent between `tool-call`
			 * and the eventual `tool-result` so the FE can flip the indicator from
			 * "pending" (LLM committed) to "running" (handler in flight).
			 */
			type: 'tool-execution-start';
			toolCallId: string;
			toolName: string;
			/** Epoch ms when the handler started, measured on the backend. */
			startTime: number;
	  }
	| {
			/**
			 * Emitted as soon as an individual tool settles, so the FE can flip a
			 * concurrent tool call to its terminal state immediately instead of
			 * waiting for the batched `tool-result` events.
			 */
			type: 'tool-execution-end';
			toolCallId: string;
			toolName: string;
			isError: boolean;
			/** Epoch ms when the handler settled, measured on the backend. */
			endTime: number;
	  }
	| {
			type: 'tool-result';
			toolCallId: string;
			toolName: string;
			output: unknown;
			isError?: boolean;
			canceled?: boolean;
	  }
	| { type: 'tool-call-suspended'; payload: ToolSuspendedPayload }
	| {
			/**
			 * Live progress from a delegated child agent. Correlated to the parent
			 * `delegate_subagent` tool call via `parentToolCallId`. Ephemeral —
			 * not persisted or replayed from history.
			 */
			type: 'subagent-chunk';
			parentToolCallId: string;
			taskPath: string;
			chunk: ForwardedChildChunkWire;
	  }
	| { type: 'message'; message: AgentSseMessage }
	| {
			/** A warning message from the MCP server when it fails to connect or initialize. */
			type: 'warning';
			message: string;
			code?: string;
			source?: 'mcp';
			server?: string;
	  }
	| {
			type: 'error';
			message: string;
			/**
			 * Optional discriminator for distinct error classes.
			 */
			errorCode?: string;
			/** Backend-emitted ids of the missing config slots; only set when `errorCode` is `agent_misconfigured`. */
			missing?: string[];
	  }
	| { type: 'done'; sessionId?: string; executionId?: string };
