/**
 * MCP eager-load helper.
 *
 * The Claude Code SDK marks every MCP tool as deferred-by-default: the model
 * cannot invoke an MCP tool until it has first called `ToolSearch` to load
 * the schema, which costs one extra turn per unique schema. The SDK's per-
 * tool override is `_meta["anthropic/alwaysLoad"]: true` on the tool's
 * `tools/list` entry, which `isDeferredTool` reads to flip the default.
 *
 * The MCP SDK exposes that channel only via `server.registerTool(name,
 * config, handler)`; the older `server.tool(name, desc, schema, handler)`
 * has no `_meta` parameter. This helper wraps the registerTool call so
 * every plugin's index.ts can opt a tool into eager-load with one line
 * matching the shape of the existing four-arg `server.tool` overload.
 *
 * Use for every tool that appears in `ADMIN_CORE_TOOLS` — the permission
 * allow-list IS the curation per the CEO review. Tools the
 * admin should not see should be removed from the allow-list, not merely
 * left deferred.
 */
/** Wire-format metadata key the Claude Code SDK reads. */
export const ALWAYS_LOAD_META_KEY = "anthropic/alwaysLoad" as const;

/**
 * Loose structural type for any object exposing a `registerTool` method. The
 * MCP SDK ships dual ESM/CJS packages with conditional exports, so importing
 * the concrete `McpServer` type here would force every consumer to compile
 * under the same resolution mode — they don't. Keep this contract minimal:
 * we only need the method to exist; we cast internally to drive the
 * upstream generic overloads which differ between SDK versions.
 */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type EagerCapableServer = { registerTool: (...args: any[]) => any };

/**
 * Local structural type for a Zod raw shape. We deliberately do NOT import
 * `ZodRawShape` from zod itself — plugin workspaces ship pinned zod v3 in
 * their nested `node_modules/zod`, while `platform/node_modules/zod` is v4,
 * and the two `ZodRawShape` types are structurally incompatible (v4
 * introduced the `_zod` brand on `ZodType`). A typed-by-value `unknown`
 * member is enough: TypeScript treats it as compatible with both v3 and v4
 * shapes, while still constraining the generic to "an object whose values
 * are zod-like" so the caller's destructured handler args stay typed via
 * the SDK's own overload resolution downstream.
 */
type LocalZodRawShape = Record<string, unknown>;

/**
 * Register an MCP tool that the Claude Code SDK eager-loads into the
 * model's prompt at session boot, bypassing the ToolSearch round-trip.
 *
 * Mirrors the four-arg `server.tool(name, description, inputSchema, handler)`
 * call shape — the only overload in use across our plugins — so callers
 * replace `server.tool(` with `eagerTool(server, ` mechanically.
 *
 * The helper deliberately does not constrain handler-arg types itself; the
 * downstream `server.registerTool` invocation inside this function passes
 * the shape through, and the upstream MCP SDK's overload (resolved against
 * the consumer's own zod version) infers the handler args.
 */
export function eagerTool<Args extends LocalZodRawShape>(
  server: EagerCapableServer,
  name: string,
  description: string,
  inputSchema: Args,
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  handler: (...args: any[]) => any,
): void {
  server.registerTool(
    name,
    {
      description,
      inputSchema,
      _meta: { [ALWAYS_LOAD_META_KEY]: true },
    },
    handler,
  );
}
