"use strict";
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2024-2026 Gracker (Chris)
// This file is part of SmartPerfetto. See LICENSE for details.
Object.defineProperty(exports, "__esModule", { value: true });
exports.registerAgentResumeRoutes = registerAgentResumeRoutes;
const enhancedSessionContext_1 = require("../agent/context/enhancedSessionContext");
const traceProcessorService_1 = require("../services/traceProcessorService");
const agentRuntime_1 = require("../agentRuntime");
const sessionLogger_1 = require("../services/sessionLogger");
const sessionPersistenceService_1 = require("../services/sessionPersistenceService");
const providerManager_1 = require("../services/providerManager");
const providerSnapshot_1 = require("../services/providerManager/providerSnapshot");
const auth_1 = require("../middleware/auth");
const resourceOwnership_1 = require("../services/resourceOwnership");
const traceMetadataStore_1 = require("../services/traceMetadataStore");
const finalResultQualityGate_1 = require("../services/finalResultQualityGate");
function restoredSessionStatus(restoredRun, hasRecoveredResult) {
    if (restoredRun?.status === 'quota_exceeded')
        return 'quota_exceeded';
    if (restoredRun?.status === 'failed')
        return 'failed';
    if (restoredRun?.status === 'pending' ||
        restoredRun?.status === 'running') {
        return 'failed';
    }
    if (restoredRun?.status === 'completed' || hasRecoveredResult)
        return 'completed';
    return 'completed';
}
function registerAgentResumeRoutes(router, deps) {
    router.post('/resume', async (req, res) => {
        const requestContext = (0, auth_1.requireRequestContext)(req);
        const { sessionId, traceId } = req.body || {};
        if (!sessionId || typeof sessionId !== 'string') {
            return res.status(400).json({
                success: false,
                error: 'sessionId is required',
            });
        }
        const existingSession = deps.sessionStore.getSession(sessionId);
        if (existingSession) {
            if (!(0, resourceOwnership_1.isOwnedByContext)(existingSession, requestContext)) {
                return (0, resourceOwnership_1.sendResourceNotFound)(res, 'Session not found');
            }
            return res.json({
                success: true,
                sessionId,
                status: existingSession.status,
                message: 'Session already active',
                restored: false,
                observability: deps.buildSessionObservability(existingSession),
            });
        }
        try {
            const persistenceService = sessionPersistenceService_1.SessionPersistenceService.getInstance();
            if (!persistenceService.hasSessionContext(sessionId)) {
                return res.status(404).json({
                    success: false,
                    error: 'Session not found in persistence',
                    hint: 'Session may have expired or was never persisted',
                });
            }
            const persistedSession = persistenceService.getSession(sessionId);
            if (!persistedSession) {
                return res.status(404).json({
                    success: false,
                    error: 'Session metadata not found',
                });
            }
            if (!(0, resourceOwnership_1.isOwnedByContext)(persistedSession.metadata, requestContext)) {
                return (0, resourceOwnership_1.sendResourceNotFound)(res, 'Session not found');
            }
            if (traceId && traceId !== persistedSession.traceId) {
                return res.status(400).json({
                    success: false,
                    error: 'traceId mismatch for resume',
                    hint: `This session was created for traceId=${persistedSession.traceId}. Upload/choose that trace to resume.`,
                    code: 'TRACE_ID_MISMATCH',
                });
            }
            const effectiveTraceId = persistedSession.traceId;
            if (!await (0, traceMetadataStore_1.readTraceMetadataForContext)(effectiveTraceId, requestContext)) {
                return (0, resourceOwnership_1.sendResourceNotFound)(res, 'Trace not found in backend');
            }
            const traceProcessorService = (0, traceProcessorService_1.getTraceProcessorService)();
            const trace = await traceProcessorService.getOrLoadTrace(effectiveTraceId);
            if (!trace) {
                return res.status(404).json({
                    success: false,
                    error: 'Trace not found in backend',
                    hint: 'Please upload the trace before resuming the session',
                    code: 'TRACE_NOT_UPLOADED',
                });
            }
            const restoredContext = persistenceService.loadSessionContext(sessionId);
            if (!restoredContext) {
                return res.status(500).json({
                    success: false,
                    error: 'Failed to deserialize session context',
                });
            }
            enhancedSessionContext_1.sessionContextManager.set(sessionId, effectiveTraceId, restoredContext);
            const providerSvc = (0, providerManager_1.getProviderService)();
            const providerScope = {
                tenantId: requestContext.tenantId,
                workspaceId: requestContext.workspaceId,
                userId: requestContext.userId,
            };
            const snapshot = persistenceService.loadSessionStateSnapshot(sessionId);
            const snapshotProviderId = snapshot?.agentRuntimeProviderId;
            const restoredProviderId = snapshot
                ? snapshotProviderId ?? null
                : providerSvc.getRawEffectiveProvider(providerScope)?.id ?? null;
            if (typeof snapshotProviderId === 'string' && !providerSvc.getRawProvider(snapshotProviderId, providerScope)) {
                return res.status(404).json({
                    success: false,
                    error: `Provider not found: ${snapshotProviderId}`,
                    code: 'PROVIDER_NOT_FOUND',
                    hint: 'This persisted session was created with a Provider Manager profile that no longer exists. Recreate the provider or start a new chat.',
                });
            }
            const restoredProviderSnapshotHash = (0, providerSnapshot_1.resolveProviderRuntimeSnapshot)(providerSvc, restoredProviderId, restoredProviderId ? undefined : snapshot?.agentRuntimeKind, providerScope).snapshotHash;
            const providerSnapshotChanged = Boolean(snapshot?.agentRuntimeProviderSnapshotHash &&
                snapshot.agentRuntimeProviderSnapshotHash !== restoredProviderSnapshotHash);
            const orchestrator = (0, agentRuntime_1.createAgentOrchestrator)({
                traceProcessorService: (0, traceProcessorService_1.getTraceProcessorService)(),
                providerId: restoredProviderId,
                runtimeOverride: restoredProviderId ? undefined : snapshot?.agentRuntimeKind,
                providerScope,
            });
            const focusSnapshot = persistenceService.loadFocusStore(sessionId);
            if (focusSnapshot && typeof orchestrator.getFocusStore === 'function') {
                orchestrator.getFocusStore().loadSnapshot(focusSnapshot);
                orchestrator.getFocusStore().syncWithEntityStore(restoredContext.getEntityStore());
            }
            const traceAgentStateSnapshot = persistenceService.loadTraceAgentState(sessionId);
            if (traceAgentStateSnapshot) {
                restoredContext.setTraceAgentState(traceAgentStateSnapshot);
            }
            const logger = (0, sessionLogger_1.createSessionLogger)(sessionId);
            logger.setMetadata({
                traceId: effectiveTraceId,
                query: persistedSession.question,
                architecture: 'agent-driven',
                resumed: true,
            });
            logger.info('AgentRoutes', 'Session restored from persistence', {
                entityStoreStats: restoredContext.getEntityStore().getStats(),
                turnCount: restoredContext.getAllTurns().length,
            });
            if (providerSnapshotChanged) {
                logger.warn('AgentRoutes', 'Provider snapshot changed; SDK session state will not be restored', {
                    providerId: restoredProviderId,
                    previousProviderSnapshotHash: snapshot?.agentRuntimeProviderSnapshotHash,
                    nextProviderSnapshotHash: restoredProviderSnapshotHash,
                });
            }
            const restoredTurns = restoredContext.getAllTurns();
            const latestTurn = restoredTurns.length > 0 ? restoredTurns[restoredTurns.length - 1] : null;
            const recoveredResult = deps.buildRecoveredResultFromContext(sessionId, restoredContext);
            if (recoveredResult) {
                const qualityIssue = (0, finalResultQualityGate_1.applyFinalResultQualityGate)({
                    result: recoveredResult,
                    query: latestTurn?.query || persistedSession.question,
                });
                if (qualityIssue && typeof restoredContext.annotateLatestCompletedTurn === 'function') {
                    restoredContext.annotateLatestCompletedTurn({
                        success: recoveredResult.success,
                        findings: recoveredResult.findings,
                        message: recoveredResult.conclusion,
                        confidence: recoveredResult.confidence,
                        partial: recoveredResult.partial,
                        terminationReason: recoveredResult.terminationReason,
                        terminationMessage: recoveredResult.terminationMessage,
                        conclusionContract: recoveredResult.conclusionContract,
                        claimSupport: recoveredResult.claimSupport,
                        claimVerificationResult: recoveredResult.claimVerificationResult,
                        identityResolutions: recoveredResult.identityResolutions,
                    });
                }
            }
            const restoredRunSequence = Math.max(0, restoredTurns.length);
            const fallbackRestoredRun = restoredRunSequence > 0
                ? {
                    runId: `run-${sessionId}-${restoredRunSequence}-recovered`,
                    requestId: `recovered-${sessionId}-${restoredRunSequence}`,
                    sequence: restoredRunSequence,
                    query: latestTurn?.query || persistedSession.question,
                    startedAt: latestTurn?.timestamp || persistedSession.createdAt,
                    completedAt: persistedSession.updatedAt,
                    status: 'completed',
                }
                : undefined;
            const restoredRun = (snapshot?.lastRun || snapshot?.activeRun || fallbackRestoredRun);
            const restoredStatus = restoredSessionStatus(restoredRun, Boolean(recoveredResult));
            const owner = (0, resourceOwnership_1.normalizeResourceOwner)(persistedSession.metadata);
            // Unified snapshot restoration — all fields populated from single source
            // Restore ClaudeRuntime Maps (notes, plans, hypotheses, flags, artifacts, architecture, sdkSessionId)
            if (snapshot && !providerSnapshotChanged && typeof orchestrator.restoreFromSnapshot === 'function') {
                orchestrator.restoreFromSnapshot(sessionId, effectiveTraceId, snapshot);
                logger.info('AgentRoutes', 'ClaudeRuntime Maps restored from snapshot', {
                    notes: snapshot.analysisNotes.length,
                    hasPlan: !!snapshot.analysisPlan,
                    hypotheses: snapshot.claudeHypotheses?.length || 0,
                    flags: snapshot.uncertaintyFlags.length,
                    artifacts: snapshot.artifacts?.length || 0,
                });
            }
            else if (typeof orchestrator.restoreArchitectureCache === 'function' && persistedSession.metadata?.architectureSnapshot) {
                // Compatibility path for older persisted sessions that predate unified snapshots.
                orchestrator.restoreArchitectureCache(effectiveTraceId, persistedSession.metadata.architectureSnapshot);
            }
            deps.sessionStore.setSession(sessionId, {
                orchestrator,
                sessionId,
                sseClients: [],
                result: recoveredResult || undefined,
                status: restoredStatus,
                error: restoredStatus === 'failed' && restoredRun?.status !== 'failed'
                    ? 'Session was interrupted before completion and cannot be resumed as completed'
                    : undefined,
                traceId: effectiveTraceId,
                tenantId: owner.tenantId,
                workspaceId: owner.workspaceId,
                userId: owner.userId,
                providerId: restoredProviderId,
                providerSnapshotHash: restoredProviderSnapshotHash,
                providerSnapshotChanged: providerSnapshotChanged || undefined,
                providerSnapshotChangeReason: providerSnapshotChanged
                    ? 'provider_snapshot_hash_mismatch'
                    : undefined,
                referenceTraceId: snapshot?.referenceTraceId,
                comparisonSource: snapshot?.comparisonSource,
                comparisonReportSection: snapshot?.comparisonReportSection,
                query: latestTurn?.query || persistedSession.question,
                createdAt: persistedSession.createdAt,
                lastActivityAt: Date.now(),
                logger,
                // All fields now restored from snapshot (previously agentDialogue/agentResponses were hardcoded to [])
                hypotheses: snapshot?.hypotheses || [],
                agentDialogue: snapshot?.agentDialogue || [],
                dataEnvelopes: snapshot?.dataEnvelopes || [],
                claimSupport: snapshot?.claimSupport,
                claimVerificationResult: snapshot?.claimVerificationResult,
                identityResolutions: snapshot?.identityResolutions,
                agentResponses: snapshot?.agentResponses || [],
                conversationOrdinal: snapshot?.conversationOrdinal || 0,
                conversationSteps: snapshot?.conversationSteps || [],
                queryHistory: snapshot?.queryHistory || [],
                conclusionHistory: snapshot?.conclusionHistory || [],
                runSequence: snapshot?.runSequence || restoredRunSequence,
                activeRun: snapshot?.activeRun || restoredRun,
                lastRun: snapshot?.lastRun || restoredRun,
                sseEventSeq: 0,
                sseEventBuffer: [],
            });
            return res.json({
                success: true,
                sessionId,
                traceId: effectiveTraceId,
                status: restoredStatus,
                message: providerSnapshotChanged
                    ? 'Session restored from persistence with a fresh SDK runtime because provider configuration changed'
                    : 'Session restored from persistence',
                restored: true,
                providerSnapshotChanged: providerSnapshotChanged || undefined,
                observability: restoredRun
                    ? {
                        runId: restoredRun.runId,
                        requestId: restoredRun.requestId,
                        runSequence: restoredRun.sequence,
                        status: restoredRun.status,
                    }
                    : undefined,
                historyEndpoints: {
                    turns: `/api/agent/v1/${sessionId}/turns`,
                    latestTurn: `/api/agent/v1/${sessionId}/turns/latest`,
                },
                restoredStats: {
                    turnCount: restoredTurns.length,
                    latestTurn: latestTurn ? deps.buildTurnSummary(latestTurn) : null,
                    entityStore: restoredContext.getEntityStore().getStats(),
                    focusStore: focusSnapshot ? orchestrator.getFocusStore().getStats() : null,
                    traceAgentState: traceAgentStateSnapshot
                        ? {
                            version: traceAgentStateSnapshot.version,
                            updatedAt: traceAgentStateSnapshot.updatedAt,
                            turns: Array.isArray(traceAgentStateSnapshot.turnLog)
                                ? traceAgentStateSnapshot.turnLog.length
                                : 0,
                            goal: traceAgentStateSnapshot.goal?.normalizedGoal ||
                                traceAgentStateSnapshot.goal?.userGoal ||
                                '',
                        }
                        : null,
                },
            });
        }
        catch (error) {
            console.error('[AgentRoutes] Session restore failed:', error);
            return res.status(500).json({
                success: false,
                error: error.message || 'Failed to restore session',
            });
        }
    });
}
//# sourceMappingURL=agentResumeRoutes.js.map