import type { ToolDef } from '../llm/openai-compat.js';
import type { McpRegistry } from './registry.js';
import type { McpTokenManager } from './token-manager.js';
import type { McpToolCache } from './tool-cache.js';
import { buildToolDefsFromCache, parseToolName } from './tool-adapter.js';
import type { ExecuteCtx, ExecuteResult } from './tool-executor.js';
import { isKeyConfigured } from './crypto.js';
import { logger } from '../logger.js';

export interface AggregatorDeps {
  registry: McpRegistry;
  tokenManager: McpTokenManager;
  toolCache: McpToolCache;
  executeCall: (args: {
    serverId: string;
    toolName: string;
    input: Record<string, unknown>;
    ctx: ExecuteCtx;
    accessToken: string;
    serverUrl: string;
  }) => Promise<ExecuteResult>;
}

export interface AggregatorCtx extends ExecuteCtx {
  // Alias to the executor context
}

export function createAggregator(deps: AggregatorDeps) {
  return {
    async getToolDefs(userId: string, allowedPatterns: string[]): Promise<ToolDef[]> {
      if (!isKeyConfigured()) return [];
      const mcpPatterns = allowedPatterns.filter((p) => p.startsWith('mcp__'));
      if (mcpPatterns.length === 0) return [];

      const servers = deps.registry.listEnabledForUser(userId);
      const connected = servers.filter((s) => deps.tokenManager.hasToken(userId, s.id));
      if (connected.length === 0) return [];

      const cache = deps.toolCache.getAllForServers(connected.map((s) => s.id));
      const names = new Map(connected.map((s) => [s.id, s.name]));
      return buildToolDefsFromCache(cache, mcpPatterns, names);
    },

    async executeTool(
      name: string,
      input: Record<string, unknown>,
      ctx: AggregatorCtx,
    ): Promise<ExecuteResult | null> {
      if (!name.startsWith('mcp__')) return null;
      const parsed = parseToolName(name);
      if (!parsed) return { output: `不正な MCP ツール名: ${name}`, isError: true };

      const server = deps.registry.getDecrypted(parsed.serverId);
      if (!server || !server.enabled) {
        return { output: `MCP サーバーが利用不可: ${parsed.serverId}`, isError: true };
      }

      let accessToken: string;
      try {
        accessToken = await deps.tokenManager.getValidToken(ctx.ownerId, parsed.serverId);
      } catch (err) {
        return { output: `MCP 認証が必要: ${(err as Error).message}`, isError: true };
      }

      logger.debug(`[mcp:aggregator] execute server=${parsed.serverId} tool=${parsed.toolName}`);
      return deps.executeCall({
        serverId: parsed.serverId,
        toolName: parsed.toolName,
        input,
        ctx,
        accessToken,
        serverUrl: server.url,
      });
    },
  };
}

export type McpAggregator = ReturnType<typeof createAggregator>;
