import type { JSONSchema7 } from 'json-schema';
import type { ZodType } from 'zod';

import type { AgentMessage } from './message';
import type { BuiltTelemetry } from '../telemetry';
import type { JSONObject } from '../utils/json';

export interface ToolExecutionContext {
	/** Agent run ID for the current execution. */
	runId?: string;
	/**
	 * Current persisted thread scope when the run is backed by memory.
	 * The runtime owns these IDs so tools can read/update data tied to the
	 * current agent thread without asking the model for thread identifiers.
	 * Integration tools use it for message context and the latest response target.
	 */
	persistence?: {
		threadId: string;
		resourceId: string;
	};
}

export interface ToolContext {
	/** AI SDK tool call ID for the current local tool execution. */
	toolCallId?: string;
	/** Agent run ID and persistence scope for the current execution. */
	runId?: string;
	/** Current persisted thread scope when the run is backed by memory. */
	persistence?: ToolExecutionContext['persistence'];
	/** Telemetry config from the parent agent, for sub-agent propagation. */
	parentTelemetry?: BuiltTelemetry;
}

export interface InterruptibleToolContext<S = unknown, R = unknown> {
	/**
	 * Suspend execution and send a payload to the consumer.
	 * Must be used with `return await` — the branded return type signals
	 * the execution engine to halt. Code after `return await ctx.suspend()` is unreachable.
	 */
	suspend: (payload: S) => Promise<never>;
	/** Data from the consumer after resume. Undefined on first invocation. */
	resumeData: R | undefined;
	/** AI SDK tool call ID for the current local tool execution. */
	toolCallId?: string;
	/** Agent run ID for the current execution. */
	runId?: string;
	/** Current persisted thread scope when the run is backed by memory. */
	persistence?: ToolExecutionContext['persistence'];
	/** Telemetry config from the parent agent, for sub-agent propagation. */
	parentTelemetry?: BuiltTelemetry;
}

export interface BuiltTool {
	readonly name: string;
	readonly description: string;
	/**
	 * Behavioural directive paired with the tool, injected into the agent's
	 * system prompt under a `<built_in_rules>` block when the tool is added.
	 * Use for guidance the LLM needs to *decide whether to call* the tool —
	 * tool descriptions answer "what does this do?" but are weighted lower
	 * than system instructions for usage decisions.
	 */
	readonly systemInstruction?: string;
	readonly suspendSchema?: ZodType | JSONSchema7;
	readonly resumeSchema?: ZodType | JSONSchema7;
	readonly withDefaultApproval?: boolean;
	readonly toMessage?: (output: unknown) => AgentMessage | undefined;
	/**
	 * Transform the handler output before sending it to the LLM as a tool result.
	 * The raw output is stored in history; only the transformed version goes to the model.
	 */
	readonly toModelOutput?: (output: unknown) => unknown;
	readonly handler?: (
		input: unknown,
		ctx: ToolContext | InterruptibleToolContext,
	) => Promise<unknown>;
	/**
	 * Input schema — either a Zod schema (SDK-defined tools) or a raw JSON Schema object
	 * (MCP tools). Use `isZodSchema()` to distinguish between the two at runtime.
	 */
	readonly inputSchema?: ZodType | JSONSchema7;
	readonly outputSchema?: ZodType | JSONSchema7;
	/** True for tools sourced from an MCP server. */
	readonly mcpTool?: boolean;
	/** Name of the MCP server this tool belongs to. Set when mcpTool is true. */
	readonly mcpServerName?: string;
	/**
	 * Provider-specific options forwarded to the AI SDK's `tool()` call.
	 * Keyed by provider name (e.g. `anthropic`, `openai`).
	 *
	 * Example: `{ anthropic: { eagerInputStreaming: true } }`
	 */
	readonly providerOptions?: Record<string, JSONObject>;
	/**
	 * Arbitrary platform-specific metadata attached to the tool.
	 */
	readonly metadata?: Record<string, unknown>;
	/**
	 * Whether the tool has source code that can be introspected.
	 * When `false`, the tool is treated as a platform-managed marker (e.g. an
	 * externally-resolved tool) and its source is not introspected.
	 * Defaults to `true` when absent.
	 */
	readonly editable?: boolean;
}

/**
 * A provider-defined tool (e.g. Anthropic web search, OpenAI code interpreter).
 *
 * `name` follows the AI SDK format `<provider-name>.<tool-name>`,
 * e.g. `'anthropic.web_search_20250305'` or `'openai.image_generation'`.
 * It is used as both the unique identifier and the key in the tools record
 * passed to `generateText` / `streamText`.
 */
export interface BuiltProviderTool {
	readonly name: `${string}.${string}`;
	readonly args: Record<string, unknown>;
	inputSchema?: ZodType;
}
