/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

import {
  BaseDeclarativeTool,
  Kind,
  type ToolInvocation,
  type ToolResult,
} from '../tools/tools.js';

import { type AgentLoopContext } from '../config/agent-loop-context.js';
import type { AgentDefinition, AgentInputs } from './types.js';
import { LocalSubagentInvocation } from './local-invocation.js';
import { RemoteAgentInvocation } from './remote-invocation.js';
import { BrowserAgentInvocation } from './browser/browserAgentInvocation.js';
import { BROWSER_AGENT_NAME } from './browser/browserAgentDefinition.js';
import type { MessageBus } from '../confirmation-bus/message-bus.js';

/**
 * A tool wrapper that dynamically exposes a subagent as a standard,
 * strongly-typed `DeclarativeTool`.
 */
export class SubagentToolWrapper extends BaseDeclarativeTool<
  AgentInputs,
  ToolResult
> {
  /**
   * Constructs the tool wrapper.
   *
   * The constructor dynamically generates the JSON schema for the tool's
   * parameters based on the subagent's input configuration.
   *
   * @param definition The `AgentDefinition` of the subagent to wrap.
   * @param context The execution context.
   * @param messageBus Optional message bus for policy enforcement.
   */
  constructor(
    private readonly definition: AgentDefinition,
    private readonly context: AgentLoopContext,
    messageBus: MessageBus,
  ) {
    super(
      definition.name,
      definition.displayName ?? definition.name,
      definition.description,
      Kind.Agent,
      definition.inputConfig.inputSchema,
      messageBus,
      /* isOutputMarkdown */ true,
      /* canUpdateOutput */ true,
    );
  }

  /**
   * Creates an invocation instance for executing the subagent.
   *
   * This method is called by the tool framework when the parent agent decides
   * to use this tool.
   *
   * @param params The validated input parameters from the parent agent's call.
   * @returns A `ToolInvocation` instance ready for execution.
   */
  protected createInvocation(
    params: AgentInputs,
    messageBus: MessageBus,
    _toolName?: string,
    _toolDisplayName?: string,
  ): ToolInvocation<AgentInputs, ToolResult> {
    const definition = this.definition;
    const effectiveMessageBus = messageBus;

    if (definition.kind === 'remote') {
      return new RemoteAgentInvocation(
        definition,
        this.context,
        params,
        effectiveMessageBus,
        _toolName,
        _toolDisplayName,
      );
    }

    // Special handling for browser agent - needs async MCP setup
    if (definition.name === BROWSER_AGENT_NAME) {
      return new BrowserAgentInvocation(
        this.context,
        params,
        effectiveMessageBus,
        _toolName,
        _toolDisplayName,
      );
    }

    return new LocalSubagentInvocation(
      definition,
      this.context,
      params,
      effectiveMessageBus,
      _toolName,
      _toolDisplayName,
    );
  }
}
