/**
 * Handoff Service (TB-O10e, TB-O10f)
 *
 * This service enables agent session handoffs for context preservation:
 *
 * - **Self-Handoff (TB-O10e)**: Agent hands off to fresh instance of itself
 *   - Creates handoff message with context summary
 *   - Suspends current session (available for predecessor query)
 *   - New session finds handoff note in inbox
 *
 * - **Agent-Agent Handoff (TB-O10f)**: Agent hands off to another agent
 *   - Sends handoff message to target agent's channel
 *   - Optionally transfers tasks to target agent
 *   - Triggers target agent to process handoff
 *
 * Key design decisions:
 * - Handoff is manual-only (agent decides when to hand off)
 * - Handoff messages stored as Documents for persistence
 * - Uses existing inbox/channel system for delivery
 *
 * @module
 */
import { createTimestamp, createDocument, createMessage, ContentType } from '@stoneforge/core';
// ============================================================================
// Constants
// ============================================================================
/** Tag used to identify handoff documents */
export const HANDOFF_DOCUMENT_TAG = 'handoff';
/** Message type for handoff messages */
export const HANDOFF_MESSAGE_TYPE = 'handoff';
// ============================================================================
// Implementation
// ============================================================================
/**
 * Implementation of the Handoff Service.
 */
export class HandoffServiceImpl {
    sessionManager;
    registry;
    api;
    constructor(sessionManager, registry, api) {
        this.sessionManager = sessionManager;
        this.registry = registry;
        this.api = api;
    }
    async selfHandoff(agentId, sessionId, options) {
        const now = createTimestamp();
        try {
            // Get the current session
            const session = this.sessionManager.getSession(sessionId);
            if (!session) {
                return {
                    success: false,
                    error: `Session not found: ${sessionId}`,
                    completedAt: now,
                };
            }
            // Verify the session belongs to the agent
            if (session.agentId !== agentId) {
                return {
                    success: false,
                    error: `Session ${sessionId} does not belong to agent ${agentId}`,
                    completedAt: now,
                };
            }
            // Verify the session is running
            if (session.status !== 'running') {
                return {
                    success: false,
                    error: `Cannot handoff session in status: ${session.status}`,
                    completedAt: now,
                };
            }
            // Get the agent's channel
            const channelId = await this.registry.getAgentChannelId(agentId);
            if (!channelId) {
                return {
                    success: false,
                    error: `Agent ${agentId} has no channel`,
                    completedAt: now,
                };
            }
            // Create handoff content
            const handoffContent = {
                type: 'handoff',
                fromAgentId: agentId,
                toAgentId: undefined, // Self-handoff has no target
                contextSummary: options.contextSummary,
                nextSteps: options.nextSteps,
                reason: options.reason,
                providerSessionId: session.providerSessionId,
                initiatedAt: now,
            };
            // Create handoff document
            const handoffDocument = await createDocument({
                content: JSON.stringify(handoffContent, null, 2),
                contentType: ContentType.JSON,
                createdBy: agentId,
                tags: [HANDOFF_DOCUMENT_TAG, 'self-handoff'],
                metadata: {
                    handoffType: 'self',
                    fromAgentId: agentId,
                    providerSessionId: session.providerSessionId,
                    ...options.metadata,
                },
            });
            // Save the handoff document
            const savedDocument = await this.api.create(handoffDocument);
            const handoffDocumentId = savedDocument.id;
            // Create and send handoff message to the agent's channel
            const handoffMessage = await createMessage({
                channelId: channelId,
                sender: agentId,
                contentRef: handoffDocumentId,
                metadata: {
                    type: HANDOFF_MESSAGE_TYPE,
                    handoffType: 'self',
                    fromAgentId: agentId,
                    handoffDocumentId,
                },
            });
            const savedMessage = await this.api.create(handoffMessage);
            const messageId = savedMessage.id;
            // Suspend the session (preserves provider session ID for predecessor queries)
            const suspendReason = options.reason
                ? `Self-handoff: ${options.reason}`
                : 'Self-handoff initiated';
            await this.sessionManager.suspendSession(sessionId, suspendReason);
            // Get the updated session record
            const suspendedSession = this.sessionManager.getSession(sessionId);
            return {
                success: true,
                handoffDocumentId,
                messageId,
                suspendedSession: suspendedSession ?? undefined,
                completedAt: createTimestamp(),
            };
        }
        catch (error) {
            return {
                success: false,
                error: error instanceof Error ? error.message : String(error),
                completedAt: createTimestamp(),
            };
        }
    }
    async handoffToAgent(fromAgentId, toAgentId, sessionId, options) {
        const now = createTimestamp();
        try {
            // Get the current session
            const session = this.sessionManager.getSession(sessionId);
            if (!session) {
                return {
                    success: false,
                    error: `Session not found: ${sessionId}`,
                    completedAt: now,
                };
            }
            // Verify the session belongs to the source agent
            if (session.agentId !== fromAgentId) {
                return {
                    success: false,
                    error: `Session ${sessionId} does not belong to agent ${fromAgentId}`,
                    completedAt: now,
                };
            }
            // Verify the session is running
            if (session.status !== 'running') {
                return {
                    success: false,
                    error: `Cannot handoff session in status: ${session.status}`,
                    completedAt: now,
                };
            }
            // Verify target agent exists
            const targetAgent = await this.registry.getAgent(toAgentId);
            if (!targetAgent) {
                return {
                    success: false,
                    error: `Target agent not found: ${toAgentId}`,
                    completedAt: now,
                };
            }
            // Get the target agent's channel
            const targetChannelId = await this.registry.getAgentChannelId(toAgentId);
            if (!targetChannelId) {
                return {
                    success: false,
                    error: `Target agent ${toAgentId} has no channel`,
                    completedAt: now,
                };
            }
            // Create handoff content
            const handoffContent = {
                type: 'handoff',
                fromAgentId,
                toAgentId,
                contextSummary: options.contextSummary,
                nextSteps: options.nextSteps,
                reason: options.reason,
                taskIds: options.taskIds,
                providerSessionId: session.providerSessionId,
                initiatedAt: now,
            };
            // Create handoff document
            const handoffDocument = await createDocument({
                content: JSON.stringify(handoffContent, null, 2),
                contentType: ContentType.JSON,
                createdBy: fromAgentId,
                tags: [HANDOFF_DOCUMENT_TAG, 'agent-handoff'],
                metadata: {
                    handoffType: 'agent-to-agent',
                    fromAgentId,
                    toAgentId,
                    providerSessionId: session.providerSessionId,
                    taskIds: options.taskIds,
                    ...options.metadata,
                },
            });
            // Save the handoff document
            const savedDocument = await this.api.create(handoffDocument);
            const handoffDocumentId = savedDocument.id;
            // Create and send handoff message to the target agent's channel
            const handoffMessage = await createMessage({
                channelId: targetChannelId,
                sender: fromAgentId,
                contentRef: handoffDocumentId,
                metadata: {
                    type: HANDOFF_MESSAGE_TYPE,
                    handoffType: 'agent-to-agent',
                    fromAgentId,
                    toAgentId,
                    handoffDocumentId,
                    taskIds: options.taskIds,
                },
            });
            const savedMessage = await this.api.create(handoffMessage);
            const messageId = savedMessage.id;
            // Suspend the source session
            const suspendReason = options.reason
                ? `Handoff to ${toAgentId}: ${options.reason}`
                : `Handoff to ${toAgentId}`;
            await this.sessionManager.suspendSession(sessionId, suspendReason);
            // Get the updated session record
            const suspendedSession = this.sessionManager.getSession(sessionId);
            // TODO: If options.triggerTarget !== false and target agent is idle,
            // we could notify/wake up the target agent here.
            // This would require integration with a notification system or
            // direct session starting capability.
            return {
                success: true,
                handoffDocumentId,
                messageId,
                suspendedSession: suspendedSession ?? undefined,
                targetAgentId: toAgentId,
                completedAt: createTimestamp(),
            };
        }
        catch (error) {
            return {
                success: false,
                error: error instanceof Error ? error.message : String(error),
                completedAt: createTimestamp(),
            };
        }
    }
    async getLastHandoff(agentId) {
        try {
            // Get the agent's channel ID
            const channelId = await this.registry.getAgentChannelId(agentId);
            if (!channelId) {
                return undefined;
            }
            // Search for handoff documents targeting this agent
            const documents = await this.api.list({
                type: 'document',
                tags: [HANDOFF_DOCUMENT_TAG],
            });
            // Filter to handoff documents for this agent and sort by creation time
            const handoffDocs = documents
                .filter((doc) => {
                const meta = doc.metadata;
                // Match self-handoff (fromAgentId === agentId, no toAgentId) or
                // agent-to-agent handoff (toAgentId === agentId)
                return ((meta?.fromAgentId === agentId && meta?.handoffType === 'self') ||
                    meta?.toAgentId === agentId);
            })
                .sort((a, b) => {
                const aTime = typeof a.createdAt === 'number' ? a.createdAt : new Date(a.createdAt).getTime();
                const bTime = typeof b.createdAt === 'number' ? b.createdAt : new Date(b.createdAt).getTime();
                return bTime - aTime; // Most recent first
            });
            if (handoffDocs.length === 0) {
                return undefined;
            }
            // Get the most recent handoff document
            const latestDoc = handoffDocs[0];
            const content = latestDoc.content;
            if (!content) {
                return undefined;
            }
            // Parse the handoff content
            try {
                const handoffContent = JSON.parse(content);
                if (handoffContent.type !== 'handoff') {
                    return undefined;
                }
                return handoffContent;
            }
            catch {
                return undefined;
            }
        }
        catch {
            return undefined;
        }
    }
    async hasPendingHandoff(agentId) {
        const handoff = await this.getLastHandoff(agentId);
        return handoff !== undefined;
    }
}
// ============================================================================
// Factory Function
// ============================================================================
/**
 * Creates a HandoffService instance
 */
export function createHandoffService(sessionManager, registry, api) {
    return new HandoffServiceImpl(sessionManager, registry, api);
}
//# sourceMappingURL=handoff.js.map