import { AgentManager } from '../tools/agent/index.js';
import { ConfigManager } from '../config/manager.js';
import { ServiceRegistry } from '../config/service-registry.js';
import { UserAuthManager } from '@pellux/goodvibes-sdk/platform/security/user-auth';
import { AutomationDeliveryManager, AutomationManager, } from '../automation/index.js';
import { ApprovalBroker, ControlPlaneGateway, SharedSessionBroker } from '../control-plane/index.js';
import { GatewayMethodCatalog } from '../control-plane/index.js';
import { BuiltinChannelRuntime, ChannelReplyPipeline, ChannelProviderRuntimeManager, ChannelPluginRegistry, ChannelPolicyManager, RouteBindingManager, SurfaceRegistry, } from '../channels/index.js';
import { RuntimeEventBus } from '../runtime/events/index.js';
import { createRuntimeStore } from '../runtime/store/index.js';
import { PlatformServiceManager } from './service-manager.js';
import { WatcherRegistry } from '../watchers/index.js';
import {} from '../runtime/remote/index.js';
import { KnowledgeGraphqlService, KnowledgeService } from '../knowledge/index.js';
import { DaemonControlPlaneHelper } from './control-plane.js';
import { DaemonSurfaceDeliveryHelper } from './surface-delivery.js';
import { DaemonSurfaceActionHelper } from './surface-actions.js';
import { DaemonTransportEventsHelper } from './transport-events.js';
import { DaemonHttpRouter } from './http/router.js';
import { createRuntimeServices } from '../runtime/services.js';
export function resolveDaemonFacadeRuntime(config, fallbackConfigManager) {
    const ownedWorkingDir = config.runtimeServices?.workingDirectory ?? config.workingDir;
    const ownedHomeDirectory = config.runtimeServices?.homeDirectory ?? config.homeDirectory;
    const configManager = config.configManager ?? fallbackConfigManager ?? config.runtimeServices?.configManager;
    if (!config.runtimeServices && !configManager && (!ownedWorkingDir || !ownedHomeDirectory)) {
        throw new Error('DaemonServer requires explicit runtime services or explicit configManager plus workingDir/homeDirectory ownership.');
    }
    if (!config.runtimeServices && !configManager) {
        throw new Error('DaemonServer requires an explicit ConfigManager or runtimeServices.');
    }
    const resolvedConfigManager = configManager ?? config.runtimeServices.configManager;
    const ownedRuntimeBus = config.runtimeServices?.runtimeBus ?? config.runtimeBus ?? new RuntimeEventBus();
    const runtimeServices = config.runtimeServices ?? createRuntimeServices({
        configManager: resolvedConfigManager,
        runtimeBus: ownedRuntimeBus,
        runtimeStore: createRuntimeStore(),
        getConversationTitle: () => 'goodvibes daemon',
        workingDir: ownedWorkingDir,
        homeDirectory: ownedHomeDirectory,
    });
    const runtimeBus = runtimeServices.runtimeBus;
    const runtimeStore = runtimeServices.runtimeStore;
    const controlPlaneGateway = new ControlPlaneGateway({
        runtimeBus,
        runtimeStore,
        server: {
            enabled: false,
            host: config.host ?? String(resolvedConfigManager.get('controlPlane.host') ?? '127.0.0.1'),
            port: config.port ?? Number(resolvedConfigManager.get('controlPlane.port') ?? 3421),
            streamingMode: resolvedConfigManager.get('controlPlane.streamMode') ?? 'sse',
        },
    });
    runtimeServices.knowledgeService.attachRuntimeBus(runtimeBus);
    runtimeServices.routeBindings.attachRuntime({
        runtimeBus,
        runtimeStore,
    });
    runtimeServices.surfaceRegistry.attachRuntime(runtimeStore);
    runtimeServices.watcherRegistry.attachRuntime({
        runtimeBus,
        runtimeStore,
    });
    runtimeServices.automationManager.attachRuntime({
        runtimeBus,
        runtimeStore,
        deliveryManager: runtimeServices.deliveryManager,
    });
    runtimeServices.deliveryManager.setControlPlaneGateway(controlPlaneGateway);
    runtimeServices.approvalBroker.setPublisher(controlPlaneGateway);
    runtimeServices.sessionBroker.setEventPublisher((event, payload) => {
        controlPlaneGateway.publishEvent(event, payload);
    });
    return {
        configManager: resolvedConfigManager,
        runtimeServices,
        integrationHelpers: runtimeServices.integrationHelpers,
        port: config.port ?? Number(resolvedConfigManager.get('controlPlane.port') ?? 3421),
        host: config.host ?? String(resolvedConfigManager.get('controlPlane.host') ?? '127.0.0.1'),
        agentManager: config.agentManager ?? runtimeServices.agentManager,
        userAuth: config.userAuth ?? runtimeServices.localUserAuthManager,
        automationManager: runtimeServices.automationManager,
        runtimeBus,
        runtimeStore,
        runtimeDispatch: runtimeServices.runtimeDispatch,
        controlPlaneGateway,
        gatewayMethods: runtimeServices.gatewayMethods,
        sessionBroker: runtimeServices.sessionBroker,
        approvalBroker: runtimeServices.approvalBroker,
        routeBindings: runtimeServices.routeBindings,
        deliveryManager: runtimeServices.deliveryManager,
        surfaceRegistry: runtimeServices.surfaceRegistry,
        channelPolicy: runtimeServices.channelPolicy,
        channelPlugins: runtimeServices.channelPlugins,
        watcherRegistry: runtimeServices.watcherRegistry,
        platformServiceManager: new PlatformServiceManager(resolvedConfigManager, {
            workingDirectory: runtimeServices.workingDirectory,
            homeDirectory: runtimeServices.homeDirectory,
        }),
        distributedRuntime: runtimeServices.distributedRuntime,
        voiceService: runtimeServices.voiceService,
        webSearchService: runtimeServices.webSearchService,
        knowledgeService: runtimeServices.knowledgeService,
        knowledgeGraphqlService: new KnowledgeGraphqlService(runtimeServices.knowledgeService),
        mediaProviders: runtimeServices.mediaProviders,
        multimodalService: runtimeServices.multimodalService,
        artifactStore: runtimeServices.artifactStore,
        serviceRegistry: runtimeServices.serviceRegistry,
        serveFactory: config.serveFactory ?? Bun.serve,
        githubWebhookSecret: config.githubWebhookSecret ?? process.env.GITHUB_WEBHOOK_SECRET ?? null,
    };
}
export function createDaemonFacadeCollaborators(options) {
    const { runtime } = options;
    const channelReplyPipeline = new ChannelReplyPipeline({
        channelPlugins: runtime.channelPlugins,
        routeBindings: runtime.routeBindings,
        runtimeBus: runtime.runtimeBus,
    });
    const surfaceDeliveryHelper = new DaemonSurfaceDeliveryHelper({
        pendingSurfaceReplies: options.pendingSurfaceReplies,
        channelReplyPipeline,
        configManager: runtime.configManager,
        serviceRegistry: runtime.serviceRegistry,
        agentManager: runtime.agentManager,
        sessionBroker: runtime.sessionBroker,
        routeBindings: runtime.routeBindings,
        channelPlugins: runtime.channelPlugins,
        authToken: options.authToken,
        surfaceDeliveryEnabled: options.surfaceDeliveryEnabled,
    });
    const surfaceActionHelper = new DaemonSurfaceActionHelper({
        serviceRegistry: runtime.serviceRegistry,
        configManager: runtime.configManager,
        routeBindings: runtime.routeBindings,
        sessionBroker: runtime.sessionBroker,
        channelPolicy: runtime.channelPolicy,
        automationManager: runtime.automationManager,
        agentManager: runtime.agentManager,
        trySpawnAgent: options.trySpawnAgent,
        queueSurfaceReplyFromBinding: (binding, input) => surfaceDeliveryHelper.queueSurfaceReplyFromBinding(binding, input),
        queueWebhookReply: (input) => surfaceDeliveryHelper.queueWebhookReply(input),
        surfaceDeliveryEnabled: options.surfaceDeliveryEnabled,
        signWebhookPayload: options.signWebhookPayload,
        handleApprovalAction: options.handleApprovalAction,
    });
    const controlPlaneHelper = new DaemonControlPlaneHelper({
        authToken: options.authToken,
        userAuth: runtime.userAuth,
        agentManager: runtime.agentManager,
        controlPlaneGateway: runtime.controlPlaneGateway,
        gatewayMethods: runtime.gatewayMethods,
        host: runtime.host,
        port: runtime.port,
        distributedRuntime: runtime.distributedRuntime,
        trustProxyEnabled: options.trustProxyEnabled,
        dispatchApiRoutes: options.dispatchApiRoutes,
        parseJsonBody: options.parseJsonBody,
        requireAuthenticatedSession: options.requireAuthenticatedSession,
    });
    const transportEventsHelper = new DaemonTransportEventsHelper({
        runtimeBus: runtime.runtimeBus,
        hookDispatcher: runtime.runtimeServices.hookDispatcher,
        host: runtime.host,
        port: runtime.port,
        tlsState: options.tlsState,
    });
    const httpRouter = new DaemonHttpRouter({
        configManager: runtime.configManager,
        serviceRegistry: runtime.serviceRegistry,
        userAuth: runtime.userAuth,
        agentManager: runtime.agentManager,
        automationManager: runtime.automationManager,
        approvalBroker: runtime.approvalBroker,
        controlPlaneGateway: runtime.controlPlaneGateway,
        gatewayMethods: runtime.gatewayMethods,
        providerRegistry: runtime.runtimeServices.providerRegistry,
        sessionBroker: runtime.sessionBroker,
        routeBindings: runtime.routeBindings,
        channelPolicy: runtime.channelPolicy,
        channelPlugins: runtime.channelPlugins,
        surfaceRegistry: runtime.surfaceRegistry,
        distributedRuntime: runtime.distributedRuntime,
        watcherRegistry: runtime.watcherRegistry,
        voiceService: runtime.voiceService,
        webSearchService: runtime.webSearchService,
        knowledgeService: runtime.knowledgeService,
        knowledgeGraphqlService: runtime.knowledgeGraphqlService,
        mediaProviders: runtime.mediaProviders,
        multimodalService: runtime.multimodalService,
        artifactStore: runtime.artifactStore,
        memoryRegistry: runtime.runtimeServices.memoryRegistry,
        memoryEmbeddingRegistry: runtime.runtimeServices.memoryEmbeddingRegistry,
        platformServiceManager: runtime.platformServiceManager,
        integrationHelpers: runtime.integrationHelpers,
        runtimeBus: runtime.runtimeBus,
        runtimeStore: runtime.runtimeStore,
        runtimeDispatch: runtime.runtimeDispatch,
        githubWebhookSecret: runtime.githubWebhookSecret,
        authToken: options.authToken,
        buildSurfaceAdapterContext: () => surfaceActionHelper.buildSurfaceAdapterContext(),
        buildGenericWebhookAdapterContext: () => surfaceActionHelper.buildGenericWebhookAdapterContext(),
        checkAuth: options.checkAuth,
        extractAuthToken: options.extractAuthToken,
        requireAuthenticatedSession: options.requireAuthenticatedSession,
        requireAdmin: options.requireAdmin,
        requireRemotePeer: options.requireRemotePeer,
        describeAuthenticatedPrincipal: options.describeAuthenticatedPrincipal,
        invokeGatewayMethodCall: options.invokeGatewayMethodCall,
        queueSurfaceReplyFromBinding: (binding, input) => surfaceDeliveryHelper.queueSurfaceReplyFromBinding(binding, input),
        surfaceDeliveryEnabled: options.surfaceDeliveryEnabled,
        syncSpawnedAgentTask: options.syncSpawnedAgentTask,
        syncFinishedAgentTask: options.syncFinishedAgentTask,
        trySpawnAgent: options.trySpawnAgent,
    });
    const providerRuntime = new ChannelProviderRuntimeManager({
        configManager: runtime.configManager,
        serviceRegistry: runtime.serviceRegistry,
        buildSurfaceAdapterContext: () => surfaceActionHelper.buildSurfaceAdapterContext(),
    });
    const builtinChannels = new BuiltinChannelRuntime({
        configManager: runtime.configManager,
        secretsManager: runtime.runtimeServices.secretsManager,
        serviceRegistry: runtime.serviceRegistry,
        routeBindings: runtime.routeBindings,
        channelPolicy: runtime.channelPolicy,
        channelPlugins: runtime.channelPlugins,
        providerRuntime,
        deliveryRouter: runtime.deliveryManager.getDeliveryRouter(),
        surfaceDeliveryEnabled: options.surfaceDeliveryEnabled,
        buildSurfaceAdapterContext: () => surfaceActionHelper.buildSurfaceAdapterContext(),
        buildGenericWebhookAdapterContext: () => surfaceActionHelper.buildGenericWebhookAdapterContext(),
        deliverSurfaceProgress: (pending, progress) => surfaceDeliveryHelper.deliverSurfaceProgress(pending, progress),
        deliverSlackAgentReply: (pending, message) => surfaceDeliveryHelper.deliverSlackAgentReply(pending, message),
        deliverDiscordAgentReply: (pending, message) => surfaceDeliveryHelper.deliverDiscordAgentReply(pending, message),
        deliverNtfyAgentReply: (pending, message) => surfaceDeliveryHelper.deliverNtfyAgentReply(pending, message),
        deliverWebhookAgentReply: (pending, message) => surfaceDeliveryHelper.deliverWebhookAgentReply(pending, message),
        deliverSlackApprovalUpdate: (approval, binding) => surfaceDeliveryHelper.deliverSlackApprovalUpdate(approval, binding),
        deliverDiscordApprovalUpdate: (approval, binding) => surfaceDeliveryHelper.deliverDiscordApprovalUpdate(approval, binding),
        deliverNtfyApprovalUpdate: (approval, binding) => surfaceDeliveryHelper.deliverNtfyApprovalUpdate(approval, binding),
        deliverWebhookApprovalUpdate: (approval, binding) => surfaceDeliveryHelper.deliverWebhookApprovalUpdate(approval, binding),
    });
    builtinChannels.registerPlugins();
    return {
        channelReplyPipeline,
        controlPlaneHelper,
        surfaceDeliveryHelper,
        surfaceActionHelper,
        transportEventsHelper,
        httpRouter,
        providerRuntime,
        builtinChannels,
    };
}
export function configureDaemonSessionContinuation(options) {
    options.sessionBroker.setContinuationRunner(async ({ sessionId, input, task, routeBinding }) => {
        const spawned = options.trySpawnAgent({
            mode: 'spawn',
            task,
            ...(input.routing?.modelId ? { model: input.routing.modelId } : {}),
            ...(input.routing?.providerId ? { provider: input.routing.providerId } : {}),
            ...(input.routing?.tools?.length ? { tools: [...input.routing.tools] } : {}),
            context: `shared-session:${sessionId}`,
        }, 'DaemonServer.sharedSessionFollowUp', sessionId);
        if (spawned instanceof Response) {
            return null;
        }
        options.queueSurfaceReplyFromBinding(routeBinding, {
            agentId: spawned.id,
            task: input.body,
            sessionId,
        });
        return { agentId: spawned.id };
    });
}
