import { forwardRef, Module } from '@nestjs/common';
import { CommandsModule } from '../commands/commands.module.js';
import { HarnessModule } from '../harness/harness.module.js';
import { HarnessRegistry } from '../harness/harness.registry.js';
import {
  HARNESS_CONVERSATION_SERVICE,
  HARNESS_REGISTRY,
  type HarnessConversationServiceBinding,
} from '../harness/harness.tokens.js';
import type { HarnessConversationService } from '@mosaicstack/types';
import { ChatGateway } from './chat.gateway.js';
import { ChatController } from './chat.controller.js';
import { ChatRuntimeRouter } from './chat-runtime-router.js';
import { EmbeddedChatRuntime } from './embedded-chat.runtime.js';
import { HarnessChatRuntime } from './harness-chat.runtime.js';

/**
 * Task Five wiring. The exclusive {@link ChatRuntimeRouter} is the single chat-execution
 * authority: the controller and gateway inject only the router, never `AgentService`,
 * `RoutingEngineService`, or a session/`piSession` handle. The router resolves exactly one
 * runtime at module init — {@link EmbeddedChatRuntime} in legacy mode, {@link HarnessChatRuntime}
 * in `pi-rpc` — over the REAL {@link HarnessModule} registry and conversation-service binding.
 *
 * The router and the harness runtime are constructed through factories because their
 * dependencies are interface/union types with no runtime injection token (the registry and
 * conversation-service arrive via the string tokens exported by `HarnessModule`); the embedded
 * runtime injects the class-typed `AgentService` and is provided directly.
 */
@Module({
  imports: [forwardRef(() => CommandsModule), HarnessModule],
  controllers: [ChatController],
  providers: [
    ChatGateway,
    EmbeddedChatRuntime,
    {
      provide: HarnessChatRuntime,
      useFactory: (conversationService: HarnessConversationServiceBinding) =>
        new HarnessChatRuntime(conversationService as HarnessConversationService),
      inject: [HARNESS_CONVERSATION_SERVICE],
    },
    {
      provide: ChatRuntimeRouter,
      useFactory: (
        registry: HarnessRegistry,
        conversationService: HarnessConversationServiceBinding,
        embedded: EmbeddedChatRuntime,
        harness: HarnessChatRuntime,
      ) => new ChatRuntimeRouter(registry, conversationService, embedded, harness),
      inject: [
        HARNESS_REGISTRY,
        HARNESS_CONVERSATION_SERVICE,
        EmbeddedChatRuntime,
        HarnessChatRuntime,
      ],
    },
  ],
  exports: [ChatGateway, ChatRuntimeRouter],
})
export class ChatModule {}
