/**
 * Benchmarking Suite - Performance Measurement Tools
 * Measures code generation, memory usage, and overall performance
 */
import { fs } from '../node-singletons/index.js';
/**
 * Benchmark - Measure performance of operations
 * Sealed namespace for immutability
 */
export const Benchmark = Object.freeze({
    /**
     * Create a new benchmark instance
     */
    create(name = 'Benchmark Suite') {
        const results = [];
        const suiteName = name;
        const startTime = new Date();
        return {
            measure(name, fn, iterations = 1, metadata) {
                const result = runMeasure(name, fn, iterations, metadata);
                results.push(result);
                return result;
            },
            async measureAsync(name, fn, iterations = 1, metadata) {
                const result = await runMeasureAsync(name, fn, iterations, metadata);
                results.push(result);
                return result;
            },
            getResults: () => [...results],
            getTable: () => getFormattedTable(results),
            toJSON: () => getBenchmarkSuite(suiteName, startTime, results),
            export(filePath) {
                fs.writeFileSync(filePath, JSON.stringify(this.toJSON(), null, 2), 'utf-8');
            },
            compare: (previous) => compareBenchmarks(results, previous),
            getComparisonReport: (comparison) => getFormattedComparisonReport(comparison),
        };
    },
});
function createBenchmarkResult(name, iterations, memBefore, memAfter, totalDuration, metadata) {
    return {
        name,
        duration: totalDuration,
        memoryBefore: memBefore,
        memoryAfter: memAfter,
        memoryDelta: memAfter - memBefore,
        iterationCount: iterations,
        averageTime: totalDuration / iterations,
        averageMemory: (memAfter - memBefore) / iterations,
        timestamp: new Date(),
        metadata,
    };
}
/**
 * Run synchronous measurement
 */
function runMeasure(name, fn, iterations, metadata) {
    const durations = [];
    const memBefore = process.memoryUsage().heapUsed;
    for (let i = 0; i < iterations; i++) {
        const start = performance.now();
        fn();
        const duration = performance.now() - start;
        durations.push(duration);
    }
    const memAfter = process.memoryUsage().heapUsed;
    const totalDuration = durations.reduce((a, b) => a + b, 0);
    return createBenchmarkResult(name, iterations, memBefore, memAfter, totalDuration, metadata);
}
/**
 * Run asynchronous measurement
 */
async function runMeasureAsync(name, fn, iterations, metadata) {
    const durations = [];
    const memBefore = process.memoryUsage().heapUsed;
    // Benchmark iterations must run sequentially to measure time per run.
    /* eslint-disable no-await-in-loop */
    for (let i = 0; i < iterations; i++) {
        const start = performance.now();
        await fn();
        const duration = performance.now() - start;
        durations.push(duration);
    }
    /* eslint-enable no-await-in-loop */
    const memAfter = process.memoryUsage().heapUsed;
    const totalDuration = durations.reduce((a, b) => a + b, 0);
    return createBenchmarkResult(name, iterations, memBefore, memAfter, totalDuration, metadata);
}
/**
 * Compare benchmarks
 */
function compareBenchmarks(results, previous) {
    const comparisons = [];
    for (const current of results) {
        const prev = previous.results.find((r) => r.name === current.name);
        if (!prev) {
            continue;
        }
        const timeChange = ((current.averageTime - prev.averageTime) / prev.averageTime) * 100;
        const memChange = ((current.averageMemory - prev.averageMemory) / prev.averageMemory) * 100;
        comparisons.push({
            name: current.name,
            timeChange,
            memoryChange: memChange,
            timeFaster: timeChange < 0,
            memoryLower: memChange < 0,
        });
    }
    return {
        timestamp: new Date(),
        comparisons,
        overallImprovement: calculateOverallImprovement(comparisons),
    };
}
/**
 * Calculate overall improvement percentage
 */
function calculateOverallImprovement(comparisons) {
    if (comparisons.length === 0) {
        return 0;
    }
    const avgChange = comparisons.reduce((sum, c) => sum + c.timeChange, 0) / comparisons.length;
    return -avgChange; // Negative change = improvement
}
/**
 * Get results as formatted table
 */
function getFormattedTable(results) {
    if (results.length === 0) {
        return 'No benchmark results';
    }
    const rows = [
        ['Operation', 'Iterations', 'Total (ms)', 'Avg (ms)', 'Memory Δ (KB)', 'Avg Mem (KB)'],
        [
            '-'.repeat(15),
            '-'.repeat(11),
            '-'.repeat(12),
            '-'.repeat(10),
            '-'.repeat(13),
            '-'.repeat(13),
        ],
    ];
    for (const result of results) {
        rows.push([
            result.name.padEnd(15),
            result.iterationCount.toString().padEnd(11),
            result.duration.toFixed(2).padEnd(12),
            result.averageTime.toFixed(2).padEnd(10),
            (result.memoryDelta / 1024).toFixed(1).padEnd(13),
            (result.averageMemory / 1024).toFixed(1).padEnd(13),
        ]);
    }
    return rows.map((row) => row.join(' ')).join('\n');
}
/**
 * Get formatted comparison report
 */
function getFormattedComparisonReport(comparison) {
    const lines = [
        '=== Performance Comparison Report ===\n',
        `Overall Improvement: ${comparison.overallImprovement > 0 ? '+' : ''}${comparison.overallImprovement.toFixed(1)}%\n`,
        'Operation Comparisons:',
        '-'.repeat(60),
    ];
    for (const comp of comparison.comparisons) {
        const timeEmoji = comp.timeFaster ? '🟢' : '🔴';
        const memEmoji = comp.memoryLower ? '🟢' : '🔴';
        const timeLine = `${timeEmoji} ${comp.name}: ${comp.timeChange > 0 ? '+' : ''}${comp.timeChange.toFixed(1)}% time`;
        const memLine = `${memEmoji} Memory: ${comp.memoryChange > 0 ? '+' : ''}${comp.memoryChange.toFixed(1)}% usage`;
        lines.push(`\n${comp.name}`, `  Time: ${timeLine}`, `  ${memLine}`);
    }
    return lines.join('\n');
}
/**
 * Get benchmark suite as JSON
 */
function getBenchmarkSuite(name, startTime, results) {
    const endTime = new Date();
    const totalDuration = endTime.getTime() - startTime.getTime();
    return {
        name,
        results: [...results],
        totalDuration,
        startTime,
        endTime,
    };
}
/**
 * Memory Monitor - Track memory usage over time
 * Sealed namespace for immutability
 */
export const MemoryMonitor = Object.freeze({
    /**
     * Create a new memory monitor instance
     */
    create() {
        let snapshots = [];
        let interval = null;
        /**
         * Format bytes as human-readable
         */
        const formatBytes = (bytes) => {
            const units = ['B', 'KB', 'MB', 'GB'];
            let size = bytes;
            let unitIndex = 0;
            while (size > 1024 && unitIndex < units.length - 1) {
                size /= 1024;
                unitIndex++;
            }
            return `${size.toFixed(2)} ${units[unitIndex]}`;
        };
        return {
            /**
             * Start monitoring
             */
            start(intervalMs = 100) {
                if (interval) {
                    clearInterval(interval);
                }
                snapshots = [];
                const MAX_SNAPSHOTS = 10000; // Limit to 10,000 snapshots (~1MB)
                interval = setInterval(() => {
                    const mem = process.memoryUsage();
                    snapshots.push({
                        timestamp: Date.now(),
                        heapUsed: mem.heapUsed,
                        heapTotal: mem.heapTotal,
                        external: mem.external,
                        rss: mem.rss,
                        arrayBuffers: mem.arrayBuffers || 0,
                    });
                    // Prevent unbounded growth
                    if (snapshots.length > MAX_SNAPSHOTS) {
                        snapshots.shift();
                    }
                }, intervalMs);
            },
            /**
             * Stop monitoring
             */
            stop() {
                if (interval) {
                    clearInterval(interval);
                    interval = null;
                }
                return [...snapshots];
            },
            /**
             * Get memory statistics
             */
            getStats() {
                return calculateMemoryStats(snapshots);
            },
            /**
             * Format memory stats as string
             */
            formatStats() {
                const stats = this.getStats();
                return formatMemoryStats(stats, formatBytes);
            },
        };
    },
});
/**
 * Calculate memory statistics
 */
function calculateMemoryStats(snapshots) {
    if (snapshots.length === 0) {
        return {
            peakHeap: 0,
            minHeap: 0,
            avgHeap: 0,
            peakRss: 0,
            snapshots: 0,
        };
    }
    const heapUsages = snapshots.map((s) => s.heapUsed);
    const rssUsages = snapshots.map((s) => s.rss);
    return {
        peakHeap: Math.max(...heapUsages),
        minHeap: Math.min(...heapUsages),
        avgHeap: heapUsages.reduce((a, b) => a + b, 0) / heapUsages.length,
        peakRss: Math.max(...rssUsages),
        snapshots: snapshots.length,
    };
}
/**
 * Format memory statistics
 */
function formatMemoryStats(stats, formatBytes) {
    return [
        'Memory Statistics:',
        `  Peak Heap: ${formatBytes(stats.peakHeap)}`,
        `  Min Heap: ${formatBytes(stats.minHeap)}`,
        `  Avg Heap: ${formatBytes(stats.avgHeap)}`,
        `  Peak RSS: ${formatBytes(stats.peakRss)}`,
        `  Snapshots: ${stats.snapshots}`,
    ].join('\n');
}
