/**
 * ChatStateAssembler
 *
 * Pure read-side DTO assembly. Reads messages, session state, usage,
 * turn statuses, pending interaction, and workflow steps from their
 * respective stores and assembles the ChatState DTO.
 *
 * No mutations — every method is a pure projection.
 *
 * Extracted from `InteractiveSessionService` in Phase 6 of the strangler refactor.
 * See `docs/plans/2026-04-14-interactive-session-service-refactor.md`.
 */
import { InteractiveSessionStatus, WorkflowStepStatus, } from '../../../../domain/generated/output.js';
export class ChatStateAssembler {
    messageRepo;
    sessionRepo;
    workflowStepRepo;
    registry;
    constructor(messageRepo, sessionRepo, workflowStepRepo, registry) {
        this.messageRepo = messageRepo;
        this.sessionRepo = sessionRepo;
        this.workflowStepRepo = workflowStepRepo;
        this.registry = registry;
    }
    async assemble(featureId) {
        // DB messages
        const messages = await this.messageRepo.findByFeatureId(featureId);
        // Find active in-memory session
        const state = this.registry.findActiveStateForFeature(featureId);
        let sessionStatus = null;
        let streamingText = null;
        let sessionInfo = null;
        if (state) {
            const dbSession = await this.sessionRepo.findById(state.sessionId);
            sessionStatus = dbSession?.status ?? null;
            if (state.currentAssistantBuffer) {
                streamingText = state.currentAssistantBuffer;
            }
            // Resolve model display: explicit override > default
            const displayModel = state.model ?? 'claude-sonnet-4-6';
            const usage = await this.sessionRepo.getUsage(state.sessionId);
            sessionInfo = {
                pid: null, // SDK manages process internally
                sessionId: state.agentSessionId ?? state.sessionId,
                model: displayModel,
                startedAt: dbSession?.startedAt
                    ? new Date(dbSession.startedAt).toISOString()
                    : new Date().toISOString(),
                lastActivityAt: dbSession?.lastActivityAt
                    ? new Date(dbSession.lastActivityAt).toISOString()
                    : new Date().toISOString(),
                totalCostUsd: usage?.totalCostUsd ?? null,
                totalInputTokens: usage?.totalInputTokens ?? null,
                totalOutputTokens: usage?.totalOutputTokens ?? null,
            };
        }
        else {
            // No in-memory state — check DB for last session (e.g. after server restart)
            const latest = await this.sessionRepo.findByFeatureId(featureId);
            if (latest) {
                sessionStatus = latest.status;
                if (latest.status !== InteractiveSessionStatus.stopped &&
                    latest.status !== InteractiveSessionStatus.error) {
                    const latestUsage = await this.sessionRepo.getUsage(latest.id);
                    sessionInfo = {
                        pid: null,
                        sessionId: latest.id,
                        model: null,
                        startedAt: latest.startedAt
                            ? new Date(latest.startedAt).toISOString()
                            : new Date().toISOString(),
                        lastActivityAt: latest.lastActivityAt
                            ? new Date(latest.lastActivityAt).toISOString()
                            : new Date().toISOString(),
                        totalCostUsd: latestUsage?.totalCostUsd ?? null,
                        totalInputTokens: latestUsage?.totalInputTokens ?? null,
                        totalOutputTokens: latestUsage?.totalOutputTokens ?? null,
                    };
                }
            }
        }
        // Resolve turn status from DB
        let turnStatus = 'idle';
        const activeState = state;
        if (activeState) {
            const statuses = await this.sessionRepo.getTurnStatuses([featureId]);
            turnStatus = statuses.get(featureId) ?? 'idle';
        }
        else {
            const latest = await this.sessionRepo.findByFeatureId(featureId);
            if (latest) {
                const statuses = await this.sessionRepo.getTurnStatuses([featureId]);
                turnStatus = statuses.get(featureId) ?? 'idle';
            }
        }
        // Include pending interaction if one exists
        const pendingInteraction = state?.pendingInteraction ?? null;
        // Workflow view — derived entirely from the DB
        const workflowSteps = await this.workflowStepRepo.listByFeature(featureId);
        let workflow = null;
        if (workflowSteps.length > 0) {
            const running = workflowSteps.find((s) => s.status === WorkflowStepStatus.running);
            workflow = {
                workflowId: workflowSteps[0].workflowId,
                steps: workflowSteps,
                currentStepId: running?.id ?? null,
            };
            if (running)
                turnStatus = 'processing';
        }
        return {
            messages,
            sessionStatus,
            streamingText,
            sessionInfo,
            turnStatus,
            pendingInteraction,
            workflow,
        };
    }
}
