import { EventEmitter } from 'events' export type ProgressStatus = 'pending' | 'active' | 'completed' | 'error' export interface ProgressStep { id: string title: string description: string status: ProgressStatus startTime?: number endTime?: number details?: string } export interface AnalysisProgress { sessionId: string currentStep: number totalSteps: number steps: ProgressStep[] timeframeProgress?: { current: number total: number currentTimeframe?: string } } class ProgressTracker extends EventEmitter { private sessions: Map = new Map() createSession(sessionId: string, steps: ProgressStep[]): AnalysisProgress { const progress: AnalysisProgress = { sessionId, currentStep: 0, totalSteps: steps.length, steps: steps.map(step => ({ ...step, status: 'pending' })) } this.sessions.set(sessionId, progress) // Small delay to ensure EventSource connection is established before emitting setTimeout(() => { this.emit(`progress:${sessionId}`, progress) }, 100) return progress } updateStep(sessionId: string, stepId: string, status: ProgressStatus, details?: string): void { console.log(`🔍 Progress Update: ${sessionId} -> ${stepId} -> ${status}${details ? ` (${details})` : ''}`) const progress = this.sessions.get(sessionId) if (!progress) { console.log(`🔍 Warning: No session found for ${sessionId}`) return } const updatedSteps = progress.steps.map(step => { if (step.id === stepId) { const updatedStep = { ...step, status, details: details || step.details } if (status === 'active' && !step.startTime) { updatedStep.startTime = Date.now() } else if ((status === 'completed' || status === 'error') && !step.endTime) { updatedStep.endTime = Date.now() } return updatedStep } return step }) const currentStepIndex = updatedSteps.findIndex(step => step.status === 'active') const updatedProgress: AnalysisProgress = { ...progress, steps: updatedSteps, currentStep: currentStepIndex >= 0 ? currentStepIndex + 1 : progress.currentStep } this.sessions.set(sessionId, updatedProgress) console.log(`🔍 Emitting progress event for ${sessionId}, currentStep: ${updatedProgress.currentStep}`) // Small delay to ensure proper event ordering and prevent race conditions setTimeout(() => { this.emit(`progress:${sessionId}`, updatedProgress) }, 50) } updateTimeframeProgress(sessionId: string, current: number, total: number, currentTimeframe?: string): void { const progress = this.sessions.get(sessionId) if (!progress) return const updatedProgress: AnalysisProgress = { ...progress, timeframeProgress: { current, total, currentTimeframe } } this.sessions.set(sessionId, updatedProgress) this.emit(`progress:${sessionId}`, updatedProgress) } getProgress(sessionId: string): AnalysisProgress | undefined { return this.sessions.get(sessionId) } deleteSession(sessionId: string): void { this.sessions.delete(sessionId) this.emit(`progress:${sessionId}:complete`) } // Get all active sessions (for debugging) getActiveSessions(): string[] { return Array.from(this.sessions.keys()) } } export const progressTracker = new ProgressTracker()