/**
 * Dispatch Service
 *
 * This service provides the dispatch operation that combines task assignment
 * with agent notification.
 *
 * Key features:
 * - Dispatch tasks to specific agents (assigns task + sends notification)
 * - Support for priority and restart options
 *
 * @module
 */
import { createTimestamp, createDocument, ContentType, ElementType, createMessage, asElementId, } from '@stoneforge/core';
// ============================================================================
// Dispatch Service Implementation
// ============================================================================
/**
 * Implementation of the Dispatch Service.
 */
export class DispatchServiceImpl {
    api;
    taskAssignment;
    agentRegistry;
    constructor(api, taskAssignment, agentRegistry) {
        this.api = api;
        this.taskAssignment = taskAssignment;
        this.agentRegistry = agentRegistry;
    }
    // ----------------------------------------
    // Direct Dispatch
    // ----------------------------------------
    async dispatch(taskId, agentId, options) {
        const dispatchedAt = createTimestamp();
        // Get the task to check if it's already assigned
        const existingTask = await this.api.get(taskId);
        if (!existingTask || existingTask.type !== ElementType.TASK) {
            throw new Error(`Task not found: ${taskId}`);
        }
        const isNewAssignment = !existingTask.assignee;
        // Get the agent
        const agent = await this.agentRegistry.getAgent(agentId);
        if (!agent) {
            throw new Error(`Agent not found: ${agentId}`);
        }
        // Get the agent's channel (check before assignment to avoid orphaned assignments)
        const channel = await this.agentRegistry.getAgentChannel(agentId);
        if (!channel) {
            throw new Error(`Agent channel not found for agent: ${agentId}`);
        }
        // Assign the task using TaskAssignmentService
        const assignOptions = {
            branch: options?.branch,
            worktree: options?.worktree,
            sessionId: options?.sessionId,
            markAsStarted: options?.markAsStarted,
        };
        const updatedTask = await this.taskAssignment.assignToAgent(taskId, agentId, assignOptions);
        // Create notification message
        const messageType = isNewAssignment
            ? 'task-assignment'
            : 'task-reassignment';
        const notificationMetadata = {
            type: messageType,
            taskId,
            priority: options?.priority,
            restart: options?.restart,
            branch: assignOptions.branch,
            worktree: assignOptions.worktree,
            sessionId: assignOptions.sessionId,
            dispatchedAt,
            dispatchedBy: options?.dispatchedBy,
            ...(options?.notificationMetadata ?? {}),
        };
        const messageContent = options?.notificationMessage ??
            this.createNotificationContent(updatedTask, messageType, options);
        const notification = await this.sendNotification(agentId, asElementId(channel.id), messageContent, notificationMetadata, options?.dispatchedBy);
        return {
            task: updatedTask,
            agent,
            notification,
            channel,
            isNewAssignment,
            dispatchedAt,
        };
    }
    async dispatchBatch(taskIds, agentId, options) {
        // For now, dispatch sequentially
        // Future optimization: batch the notifications
        const results = [];
        for (const taskId of taskIds) {
            const result = await this.dispatch(taskId, agentId, options);
            results.push(result);
        }
        return results;
    }
    // ----------------------------------------
    // Notification
    // ----------------------------------------
    async notifyAgent(agentId, messageType, content, metadata) {
        const channel = await this.agentRegistry.getAgentChannel(agentId);
        if (!channel) {
            throw new Error(`Agent channel not found for agent: ${agentId}`);
        }
        const fullMetadata = {
            type: messageType,
            dispatchedAt: createTimestamp(),
            ...(metadata ?? {}),
        };
        return this.sendNotification(agentId, asElementId(channel.id), content, fullMetadata);
    }
    // ----------------------------------------
    // Private Helpers
    // ----------------------------------------
    /**
     * Creates the notification content for a dispatch
     */
    createNotificationContent(task, messageType, options) {
        const priorityStr = options?.priority ? ` [Priority: ${options.priority}]` : '';
        const restartStr = options?.restart ? ' (restart requested)' : '';
        switch (messageType) {
            case 'task-assignment':
                return `Task assigned: ${task.title}${priorityStr}${restartStr}`;
            case 'task-reassignment':
                return `Task reassigned: ${task.title}${priorityStr}${restartStr}`;
            case 'restart-signal':
                return `Restart requested${restartStr}`;
            default:
                return `Notification: ${messageType}`;
        }
    }
    /**
     * Sends a notification message to an agent's channel
     */
    async sendNotification(agentId, channelId, content, metadata, dispatchedBy) {
        const sender = dispatchedBy ?? agentId;
        // Create a document for the message content
        const contentDoc = await createDocument({
            contentType: ContentType.TEXT,
            content,
            createdBy: sender,
            tags: ['dispatch-notification', metadata.type],
            metadata: { dispatchNotification: true },
        });
        // Save the document
        const savedDoc = await this.api.create(contentDoc);
        // Create message for the agent's channel.
        // suppressInbox prevents inbox items from being created for channel members,
        // so dispatch notifications don't clutter the operator/director's inbox.
        const message = await createMessage({
            channelId: channelId,
            sender,
            contentRef: savedDoc.id,
            tags: ['dispatch-notification', metadata.type],
            metadata: { ...metadata, suppressInbox: true },
        });
        // Save the message
        const savedMessage = await this.api.create(message);
        return savedMessage;
    }
}
// ============================================================================
// Factory Function
// ============================================================================
/**
 * Creates a DispatchService instance
 */
export function createDispatchService(api, taskAssignment, agentRegistry) {
    return new DispatchServiceImpl(api, taskAssignment, agentRegistry);
}
//# sourceMappingURL=dispatch-service.js.map