/**
 * AgentToolsModule — 业务模块接入入口。
 *
 * 用法 (详 docs/standards/21-agent-business-module-integration.md §2):
 *
 *   @Module({
 *     imports: [
 *       AgentToolsModule.forFeature([MyService]),
 *     ],
 *     providers: [MyService],
 *     exports: [MyService],
 *   })
 *   export class MyModule {}
 *
 * 设计 (#410 plan-review Q1.1 = C, 详 forFeature 方法上「约定」段):
 *   - @Global() — AgentToolsCollector 是全局单例,确保多个 forFeature 调用累加进同一收集器
 *   - forFeature(services) — 动态 module:
 *       通过 Symbol() token + useFactory 副作用调用 collector.register(services)
 *       把 service class 引用累加到全局清单 (不创建 useClass 实例, 避免双实例);
 *       业务 module 必须自己在 `providers: [...]` 持有 canonical 实例
 *   - 多次 forFeature(同 service) 由 collector.register 内部 Set 去重保证幂等
 */

import { Global, Module, DynamicModule, Type, Provider } from '@nestjs/common';
import { AgentToolsCollector } from './agent-tools-collector.service';

@Global()
@Module({
  providers: [AgentToolsCollector],
  exports: [AgentToolsCollector],
})
export class AgentToolsModule {
  /**
   * 业务模块在 @Module imports 里调用,显式登记本 module 的 @AgentTool 服务。
   *
   * **约定**: 业务模块**必须**在自己的 `providers: [...]` 数组里 provide 该 service
   * (canonical 实例由业务 module 拥有); forFeature 仅把 service class 引用累加到
   * AgentToolsCollector 全局清单,不创建第二个 useClass 实例 (避免双实例风险)。
   *
   * 业务 module 模板:
   *   @Module({
   *     imports: [AgentToolsModule.forFeature([MyService])],
   *     providers: [MyService],     // ← 业务 module 自己 provide,canonical 实例
   *     exports: [MyService],
   *   })
   *
   * AgentToolBootstrap 在 onApplicationBootstrap 阶段通过 `ModuleRef.get(MyService,
   * { strict: false })` 跨 module 解析到业务 module 的 canonical 实例,无重复实例。
   *
   * @param services - 业务 service class 数组 (每个 class 内可有 1+ 个 @AgentTool 方法)
   */
  static forFeature(services: Type[]): DynamicModule {
    // Symbol token 避免相同字符串后缀在跨包同名 class 上撞 token (NestJS DI 容器键基于值相等性)
    const collectFactoryToken = Symbol(
      `AGENT_TOOLS_FORFEATURE:${services.map((s) => s.name).join(',')}`,
    );

    const collectProvider: Provider = {
      provide: collectFactoryToken,
      inject: [AgentToolsCollector],
      useFactory: (collector: AgentToolsCollector) => {
        collector.register(services);
        return services.length;
      },
    };

    return {
      module: AgentToolsModule,
      providers: [collectProvider],
      // 不 export services — business module 是 canonical owner; 避免本 module
      // export 后被其他 module 误以为可以从这里 inject (双实例风险源)
    };
  }
}
