/**
 * @fileoverview Defines the structure for task-based tool definitions.
 * Task tools support long-running async operations with the MCP Tasks API,
 * enabling "call-now, fetch-later" execution patterns.
 *
 * @experimental These APIs are experimental and may change without notice.
 * @module src/mcp-server/tasks/utils/taskToolDefinition
 */
import type { ZodObject, ZodRawShape } from 'zod';
import type { TaskToolExecution, ToolTaskHandler } from '@/mcp-server/tasks/core/taskTypes.js';
import type { ToolAnnotations } from '@/mcp-server/tools/utils/toolDefinition.js';

/**
 * Represents a task-based tool definition for long-running async operations.
 *
 * Unlike regular tools that execute synchronously and return immediately,
 * task tools create durable task handles that clients can poll for status
 * and retrieve results after completion.
 *
 * Task tools are registered via `server.experimental.tasks.registerToolTask()`
 * and must implement three handlers:
 * - `createTask`: Called when the tool is invoked, creates the task and starts work
 * - `getTask`: Called to poll task status (tasks/get)
 * - `getTaskResult`: Called to retrieve results (tasks/result)
 *
 * @example
 * ```typescript
 * const myTaskTool: TaskToolDefinition<typeof InputSchema, typeof OutputSchema> = {
 *   name: 'long_running_analysis',
 *   description: 'Performs a long-running analysis operation',
 *   input: z.object({ data: z.string() }),
 *   output: z.object({ result: z.string() }),
 *   execution: { taskSupport: 'required' },
 *   taskHandlers: {
 *     createTask: async (args, extra) => {
 *       const task = await extra.taskStore.createTask({ ttl: 300000 }, ...);
 *       startBackgroundWork(task.taskId, args);
 *       return { task };
 *     },
 *     getTask: async (_args, extra) => {
 *       return await extra.taskStore.getTask(extra.taskId);
 *     },
 *     getTaskResult: async (_args, extra) => {
 *       return await extra.taskStore.getTaskResult(extra.taskId);
 *     }
 *   }
 * };
 * ```
 *
 * @experimental
 */
export interface TaskToolDefinition<
  TInputSchema extends ZodObject<ZodRawShape>,
  TOutputSchema extends ZodObject<ZodRawShape>,
> {
  /** Protocol-level metadata (e.g., MCP Apps extension `_meta.ui`). */
  _meta?: Record<string, unknown>;

  /**
   * Optional metadata providing hints about the tool's behavior.
   */
  annotations?: ToolAnnotations;

  /**
   * A clear, concise description of what the tool does.
   * This is sent to the LLM to help it decide when to use the tool.
   */
  description: string;

  /**
   * Task execution configuration.
   *
   * - `taskSupport: 'required'` - Tool MUST be invoked as a task
   * - `taskSupport: 'optional'` - Tool can be invoked normally or as a task
   *
   * Note: `taskSupport: 'forbidden'` is not valid for task tools;
   * use a regular ToolDefinition instead.
   */
  execution: TaskToolExecution;

  /** Zod schema for input validation. All fields need `.describe()`. */
  input: TInputSchema;

  /** Programmatic unique name (snake_case). */
  name: string;

  /** Zod schema for output validation. */
  output?: TOutputSchema;

  /**
   * The task handlers implementing the task lifecycle.
   *
   * These handlers are called by the SDK at different points:
   * - `createTask`: When the tool is first invoked (tools/call with task param)
   * - `getTask`: When polling for status (tasks/get)
   * - `getTaskResult`: When retrieving results (tasks/result)
   */
  taskHandlers: ToolTaskHandler<TInputSchema>;

  /**
   * An optional, human-readable title for the tool.
   * If not provided, derived from `name` or `annotations.title`.
   */
  title?: string;
}

/**
 * Type guard to check if a tool definition is a task tool.
 *
 * @param def - The tool definition to check
 * @returns True if the definition has taskHandlers (is a TaskToolDefinition)
 */
export function isTaskToolDefinition(
  def: unknown,
): def is TaskToolDefinition<ZodObject<ZodRawShape>, ZodObject<ZodRawShape>> {
  return (
    def !== null &&
    typeof def === 'object' &&
    'taskHandlers' in def &&
    def.taskHandlers !== null &&
    typeof def.taskHandlers === 'object'
  );
}
