import { spawn } from 'node:child_process';
import { AgentExecutorFactory } from '../../services/agents/common/agent-executor-factory.service.js';
import { AgentExecutorProvider } from '../../services/agents/common/agent-executor-provider.service.js';
import { StructuredAgentCallerService } from '../../services/agents/common/structured-agent-caller.service.js';
import { MockAgentExecutorFactory } from '../../services/agents/common/executors/mock-executor-factory.service.js';
import { AgentRegistryService } from '../../services/agents/common/agent-registry.service.js';
import { AgentRunnerService } from '../../services/agents/common/agent-runner.service.js';
import { PhaseTimingContextAdapter } from '../../services/agents/feature-agent/phase-timing-context.adapter.js';
import { FeatureAgentProcessService } from '../../services/agents/feature-agent/feature-agent-process.service.js';
import { SpecInitializerService } from '../../services/spec/spec-initializer.service.js';
import { SpecYamlParserService } from '../../services/spec/spec-yaml-parser.service.js';
import { ClaudeCodeSessionRepository } from '../../services/agents/sessions/claude-code-session.repository.js';
import { CodexCliSessionRepository } from '../../services/agents/sessions/codex-cli-session.repository.js';
import { StubSessionRepository } from '../../services/agents/sessions/stub-session.repository.js';
import { AgentSessionRepositoryRegistry } from '../../services/agents/agent-session-repository.registry.js';
import { AgentType } from '../../../domain/generated/output.js';
import { FeatureAgentLifecyclePublisher } from '../../services/agents/feature-agent/feature-agent-lifecycle-publisher.js';
import { FeatureAgentGateQuestionPublisher } from '../../services/agents/feature-agent/feature-agent-gate-question-publisher.js';
import { FeatureAgentSupervisorGateEvaluator } from '../../services/agents/feature-agent/feature-agent-supervisor-gate-evaluator.js';
import { LangGraphSupervisorAgent } from '../../services/agents/supervisor-agent/langgraph-supervisor-agent.js';
import { SdlcBoardTracker } from '../../services/agents/sdlc-board-tracker.js';
/**
 * Register agent-execution infrastructure: executor factory/provider, runner,
 * registry, phase timing, feature-agent process service, spec services, and
 * per-AgentType session repositories.
 */
export function registerAgents(container) {
    container.registerSingleton('IPhaseTimingContext', PhaseTimingContextAdapter);
    if (process.env.SHEP_MOCK_EXECUTOR === '1') {
        container.register('IAgentExecutorFactory', {
            useFactory: () => new MockAgentExecutorFactory(),
        });
    }
    else {
        container.register('IAgentExecutorFactory', {
            useFactory: () => {
                // Wrap spawn with sensible defaults: stdio piped and windowsHide on Win32.
                // Each executor controls its own `shell` option — cursor needs shell: true
                // for .cmd scripts, but claude-code must NOT use shell (DEP0190 / prompt mangling).
                const spawnWithPipe = (command, args, options) => {
                    return spawn(command, args, {
                        stdio: 'pipe',
                        ...(process.platform === 'win32' ? { windowsHide: true } : {}),
                        ...options,
                    });
                };
                return new AgentExecutorFactory(spawnWithPipe);
            },
        });
    }
    container.register('IAgentExecutorProvider', {
        useFactory: (c) => {
            const factory = c.resolve('IAgentExecutorFactory');
            const settingsRepo = c.resolve('ISettingsRepository');
            return new AgentExecutorProvider(factory, settingsRepo);
        },
    });
    container.register('IStructuredAgentCaller', {
        useFactory: (c) => {
            const provider = c.resolve('IAgentExecutorProvider');
            const factory = c.resolve('IAgentExecutorFactory');
            return new StructuredAgentCallerService(provider, factory);
        },
    });
    container.register('IAgentRegistry', {
        useFactory: () => new AgentRegistryService(),
    });
    container.register('IAgentRunner', {
        useFactory: (c) => {
            const registry = c.resolve('IAgentRegistry');
            const executorProvider = c.resolve('IAgentExecutorProvider');
            const runRepository = c.resolve('IAgentRunRepository');
            // Checkpointer is lazy-loaded to avoid ~240ms startup cost from
            // @langchain/langgraph-checkpoint-sqlite on every CLI invocation.
            return new AgentRunnerService(registry, executorProvider, runRepository);
        },
    });
    container.register('IFeatureAgentProcessService', {
        useFactory: (c) => {
            const runRepository = c.resolve('IAgentRunRepository');
            return new FeatureAgentProcessService(runRepository);
        },
    });
    container.register('ISpecInitializerService', {
        useFactory: () => new SpecInitializerService(),
    });
    container.registerSingleton('ISpecArtifactParser', SpecYamlParserService);
    // Session repositories (per-AgentType string tokens)
    container.register(`IAgentSessionRepository:${AgentType.ClaudeCode}`, {
        useFactory: () => new ClaudeCodeSessionRepository(),
    });
    container.register(`IAgentSessionRepository:${AgentType.Cursor}`, {
        useFactory: () => new StubSessionRepository(AgentType.Cursor),
    });
    container.register(`IAgentSessionRepository:${AgentType.GeminiCli}`, {
        useFactory: () => new StubSessionRepository(AgentType.GeminiCli),
    });
    container.register(`IAgentSessionRepository:${AgentType.CodexCli}`, {
        useFactory: () => new CodexCliSessionRepository(),
    });
    container.register(`IAgentSessionRepository:${AgentType.CopilotCli}`, {
        useFactory: () => new StubSessionRepository(AgentType.CopilotCli),
    });
    container.registerSingleton('IAgentSessionRepositoryRegistry', AgentSessionRepositoryRegistry);
    // Feature-agent worker uses this to broadcast lifecycle messages on the
    // agent message bus (spec 093). Singleton so one publisher per process.
    container.registerSingleton(FeatureAgentLifecyclePublisher);
    // Feature-agent worker emits a parallel AgentQuestion (kind=blocking)
    // on every waiting_approval transition so the unified inbox covers
    // background-mode gates (spec 093, task 20).
    container.registerSingleton(FeatureAgentGateQuestionPublisher);
    // Feature-agent worker consults the configured supervisor on every
    // waiting_approval transition (spec 093, task 29). In autonomous
    // mode the supervisor may close the gate via Approve/Reject; in
    // advisory / co-sign modes the decision is recorded but the gate
    // stays in waiting_approval for the user.
    container.registerSingleton(FeatureAgentSupervisorGateEvaluator);
    // ISupervisorAgent — production adapter behind the supervisor port (spec 093).
    // Tsyringe eagerly resolves the entire constructor tree of every singleton
    // it builds, so AskAgentQuestionUseCase → AgentQuestionSupervisorRouter →
    // EvaluateSupervisorDecisionUseCase needs this token to exist *before* any
    // feature-flag short-circuit can run. Forgetting this registration crashes
    // every feature-agent worker on boot, even when the collaboration flag is off.
    container.registerSingleton('ISupervisorAgent', LangGraphSupervisorAgent);
    // ISdlcBoardTracker — output port through which the feature-agent writes
    // task and sub-task progress onto the SDLC Board (spec sdlc-board, phase 3a).
    // Registered as a singleton (stateless adapter; repos own the state) and
    // aliased under the string token so any worker/use-case can inject it
    // without importing the concrete class.
    container.registerSingleton(SdlcBoardTracker);
    container.register('ISdlcBoardTracker', {
        useFactory: (c) => c.resolve(SdlcBoardTracker),
    });
}
