/**
 * Startup Timing Utility
 *
 * Tracks and reports startup performance metrics.
 * Useful for identifying slow modules and optimizing cold start times.
 */
// ============================================================================
// Default Configuration
// ============================================================================
const DEFAULT_CONFIG = {
    enabled: process.env.PERF_TIMING === 'true' || process.env.DEBUG === 'true',
    slowThresholdMs: 100,
    logToConsole: process.env.PERF_TIMING === 'true',
    updateProcessTitle: false,
};
// ============================================================================
// Global State
// ============================================================================
// Record absolute startup time as early as possible
const processStartTime = Date.now();
// Phases storage
const phases = [];
const activePhases = new Map();
let config = { ...DEFAULT_CONFIG };
let isInitialized = false;
// ============================================================================
// Core Functions
// ============================================================================
/**
 * Initialize startup timing with optional config
 */
export function initStartupTiming(overrideConfig) {
    if (isInitialized)
        return;
    config = { ...config, ...overrideConfig };
    isInitialized = true;
    // Record initialization phase
    recordPhase('init', processStartTime, Date.now());
}
/**
 * Start timing a phase
 */
export function startPhase(name) {
    if (!config.enabled)
        return;
    activePhases.set(name, Date.now());
}
/**
 * End timing a phase
 */
export function endPhase(name, metadata) {
    if (!config.enabled)
        return 0;
    const startTime = activePhases.get(name);
    if (startTime === undefined) {
        return 0;
    }
    activePhases.delete(name);
    const endTime = Date.now();
    const duration = endTime - startTime;
    recordPhase(name, startTime, endTime, metadata);
    return duration;
}
/**
 * Measure an async operation
 */
export async function measurePhase(name, fn, metadata) {
    if (!config.enabled) {
        return fn();
    }
    startPhase(name);
    try {
        const result = await fn();
        endPhase(name, metadata);
        return result;
    }
    catch (error) {
        endPhase(name, { ...metadata, error: true });
        throw error;
    }
}
/**
 * Measure a sync operation
 */
export function measurePhaseSync(name, fn, metadata) {
    if (!config.enabled) {
        return fn();
    }
    startPhase(name);
    try {
        const result = fn();
        endPhase(name, metadata);
        return result;
    }
    catch (error) {
        endPhase(name, { ...metadata, error: true });
        throw error;
    }
}
/**
 * Mark startup as complete and get metrics
 */
export function completeStartup() {
    const totalTime = Date.now() - processStartTime;
    // Complete any still-active phases
    Array.from(activePhases.keys()).forEach((name) => {
        endPhase(name, { incomplete: true });
    });
    const slowPhases = phases.filter((p) => p.duration >= config.slowThresholdMs);
    const metrics = {
        totalTime,
        phases: [...phases],
        slowPhases,
        timestamp: new Date(),
    };
    if (config.logToConsole) {
        logStartupMetrics(metrics);
    }
    return metrics;
}
/**
 * Get current metrics without completing startup
 */
export function getStartupMetrics() {
    const totalTime = Date.now() - processStartTime;
    const slowPhases = phases.filter((p) => p.duration >= config.slowThresholdMs);
    return {
        totalTime,
        phases: [...phases],
        slowPhases,
        timestamp: new Date(),
    };
}
/**
 * Get total startup time so far
 */
export function getElapsedTime() {
    return Date.now() - processStartTime;
}
/**
 * Record a phase directly (when start/end times are known)
 */
export function recordPhase(name, startTime, endTime, metadata) {
    if (!config.enabled)
        return;
    const duration = endTime - startTime;
    phases.push({
        name,
        startTime,
        endTime,
        duration,
        metadata,
    });
}
/**
 * Clear all recorded phases
 */
export function clearPhases() {
    phases.length = 0;
    activePhases.clear();
}
/**
 * Format metrics for display
 */
export function formatStartupMetrics(metrics) {
    const lines = [];
    lines.push('');
    lines.push('=== Startup Performance ===');
    lines.push(`Total Time: ${metrics.totalTime}ms`);
    lines.push('');
    lines.push('Phase Breakdown:');
    // Sort by duration (slowest first)
    const sortedPhases = [...metrics.phases].sort((a, b) => b.duration - a.duration);
    for (const phase of sortedPhases) {
        const marker = phase.duration >= config.slowThresholdMs ? '[SLOW]' : '';
        const pct = ((phase.duration / metrics.totalTime) * 100).toFixed(1);
        lines.push(`  ${phase.name}: ${phase.duration}ms (${pct}%) ${marker}`);
    }
    if (metrics.slowPhases.length > 0) {
        lines.push('');
        lines.push(`Slow Phases (>${config.slowThresholdMs}ms): ${metrics.slowPhases.length}`);
    }
    lines.push('===========================');
    return lines.join('\n');
}
/**
 * Log startup metrics to console
 */
export function logStartupMetrics(metrics) {
    console.log(formatStartupMetrics(metrics));
}
// ============================================================================
// Decorators for Module Loading
// ============================================================================
/**
 * Create a timed import function
 */
export function timedImport(name, importFn) {
    return async () => {
        if (!config.enabled) {
            return importFn();
        }
        startPhase(`import:${name}`);
        const result = await importFn();
        endPhase(`import:${name}`);
        return result;
    };
}
/**
 * Create a lazy loader with timing
 */
export function timedLazy(name, loader) {
    let cached;
    let loading;
    return async () => {
        if (cached !== undefined) {
            return cached;
        }
        if (loading) {
            return loading;
        }
        loading = measurePhase(`lazy:${name}`, async () => {
            const result = await loader();
            cached = result;
            return result;
        });
        return loading;
    };
}
// ============================================================================
// Config Management
// ============================================================================
/**
 * Update timing configuration
 */
export function updateTimingConfig(newConfig) {
    config = { ...config, ...newConfig };
}
/**
 * Get current configuration
 */
export function getTimingConfig() {
    return { ...config };
}
/**
 * Enable timing (useful for debugging)
 */
export function enableTiming() {
    config.enabled = true;
}
/**
 * Disable timing
 */
export function disableTiming() {
    config.enabled = false;
}
// ============================================================================
// Exports for Common Patterns
// ============================================================================
/**
 * Quick startup timer for simple use cases
 */
export class StartupTimer {
    startTime;
    marks = new Map();
    constructor() {
        this.startTime = Date.now();
    }
    mark(name) {
        const elapsed = Date.now() - this.startTime;
        this.marks.set(name, elapsed);
        return elapsed;
    }
    getMark(name) {
        return this.marks.get(name);
    }
    getElapsed() {
        return Date.now() - this.startTime;
    }
    getMarks() {
        return Object.fromEntries(this.marks);
    }
    format() {
        const elapsed = this.getElapsed();
        const lines = [`Total: ${elapsed}ms`];
        Array.from(this.marks.entries()).forEach(([name, time]) => {
            lines.push(`  ${name}: ${time}ms`);
        });
        return lines.join('\n');
    }
}
// Export process start time for external use
export const PROCESS_START_TIME = processStartTime;
//# sourceMappingURL=startup-timing.js.map