'use strict';

/* ────────────────────────────────────────────────────────────────
   Benchmark Suite — LEGENDARY L11
   
   • Standardized benchmark scenarios
   • Frame-time measurement with percentiles
   • Memory usage tracking
   • Regression detection (compare results)
   • JSON-serializable report output
──────────────────────────────────────────────────────────────── */
/* ══════════════════════════════════════════════════════════════
   BenchmarkRunner
   ══════════════════════════════════════════════════════════════ */
class BenchmarkRunner {
    constructor() {
        this.scenarios = new Map();
        this.results = [];
    }
    /** Register a benchmark scenario. */
    register(scenario) {
        this.scenarios.set(scenario.id, scenario);
    }
    /** Register multiple scenarios. */
    registerAll(scenarios) {
        for (const s of scenarios) {
            this.register(s);
        }
    }
    /** Run a single scenario. */
    runScenario(id) {
        var _a, _b, _c;
        const scenario = this.scenarios.get(id);
        if (!scenario)
            return null;
        const warmup = (_a = scenario.warmup) !== null && _a !== void 0 ? _a : 10;
        const iterations = (_b = scenario.iterations) !== null && _b !== void 0 ? _b : 100;
        // Setup
        let cleanup;
        if (scenario.setup) {
            cleanup = scenario.setup();
        }
        // Warm-up
        for (let i = 0; i < warmup; i++) {
            scenario.run();
        }
        // Measure memory before
        const memBefore = this.getHeapUsed();
        // Measure iterations
        const samples = [];
        const totalStart = performance.now();
        for (let i = 0; i < iterations; i++) {
            const start = performance.now();
            scenario.run();
            const end = performance.now();
            samples.push(end - start);
        }
        const totalMs = performance.now() - totalStart;
        const memAfter = this.getHeapUsed();
        // Teardown
        if (typeof cleanup === 'function')
            cleanup();
        if (scenario.teardown)
            scenario.teardown();
        // Calculate timings
        const timings = this.calculateTimings(samples, totalMs, iterations);
        // Memory delta
        const memory = (memBefore !== null && memAfter !== null) ? {
            heapUsedBefore: memBefore,
            heapUsedAfter: memAfter,
            heapDelta: memAfter - memBefore,
        } : null;
        const withinBudget = scenario.budgetMs != null ? (timings.mean <= scenario.budgetMs) : null;
        const result = {
            scenarioId: scenario.id,
            scenarioName: scenario.name,
            category: scenario.category,
            timings,
            memory,
            budgetMs: (_c = scenario.budgetMs) !== null && _c !== void 0 ? _c : null,
            withinBudget,
            timestamp: Date.now(),
        };
        this.results.push(result);
        return result;
    }
    /** Run all registered scenarios. */
    runAll() {
        this.results = [];
        const ids = Array.from(this.scenarios.keys());
        for (const id of ids) {
            this.runScenario(id);
        }
        return this.generateReport();
    }
    /** Run scenarios in a specific category. */
    runCategory(category) {
        this.results = [];
        for (const [id, scenario] of this.scenarios) {
            if (scenario.category === category) {
                this.runScenario(id);
            }
        }
        return this.generateReport();
    }
    /** Generate a full report from collected results. */
    generateReport(label) {
        let passed = 0;
        let failed = 0;
        let totalTimeMs = 0;
        for (const r of this.results) {
            totalTimeMs += r.timings.totalMs;
            if (r.withinBudget === true)
                passed++;
            else if (r.withinBudget === false)
                failed++;
        }
        return {
            label: label !== null && label !== void 0 ? label : 'benchmark',
            date: new Date().toISOString(),
            platform: typeof navigator !== 'undefined' ? navigator.userAgent : 'node',
            results: [...this.results],
            summary: {
                totalScenarios: this.results.length,
                passed,
                failed,
                skipped: this.results.length - passed - failed,
                totalTimeMs,
            },
        };
    }
    /** Compare two reports for regressions. */
    static compareReports(baseline, current, regressionThresholdPercent = 10) {
        const baseMap = new Map();
        for (const r of baseline.results)
            baseMap.set(r.scenarioId, r);
        const regressions = [];
        for (const cur of current.results) {
            const base = baseMap.get(cur.scenarioId);
            if (!base)
                continue;
            const meanDelta = ((cur.timings.mean - base.timings.mean) / base.timings.mean) * 100;
            const p95Delta = ((cur.timings.p95 - base.timings.p95) / base.timings.p95) * 100;
            regressions.push({
                scenarioId: cur.scenarioId,
                scenarioName: cur.scenarioName,
                meanDeltaPercent: Math.round(meanDelta * 100) / 100,
                p95DeltaPercent: Math.round(p95Delta * 100) / 100,
                regressed: meanDelta > regressionThresholdPercent,
                improved: meanDelta < -regressionThresholdPercent,
            });
        }
        return regressions;
    }
    /** Get last results. */
    getResults() {
        return [...this.results];
    }
    /** Clear all scenarios and results. */
    clear() {
        this.scenarios.clear();
        this.results = [];
    }
    /* ── Internals ──────────────────────────────────────────────── */
    calculateTimings(samples, totalMs, iterations) {
        const sorted = [...samples].sort((a, b) => a - b);
        const mean = samples.reduce((s, v) => s + v, 0) / samples.length;
        const variance = samples.reduce((s, v) => s + (v - mean) ** 2, 0) / samples.length;
        return {
            min: sorted[0],
            max: sorted[sorted.length - 1],
            mean,
            median: sorted[Math.floor(sorted.length / 2)],
            p95: sorted[Math.floor(sorted.length * 0.95)],
            p99: sorted[Math.floor(sorted.length * 0.99)],
            stdDev: Math.sqrt(variance),
            totalMs,
            iterations,
        };
    }
    getHeapUsed() {
        if (typeof performance !== 'undefined' && performance.memory) {
            return performance.memory.usedJSHeapSize;
        }
        return null;
    }
}
/* ══════════════════════════════════════════════════════════════
   Built-in Benchmark Scenarios
   ══════════════════════════════════════════════════════════════ */
const BUILTIN_BENCHMARKS = [
    {
        id: 'ecs-create-entities',
        name: 'ECS: Create 1000 entities',
        category: 'ecs',
        iterations: 200,
        budgetMs: 2,
        run: () => {
        },
    },
    {
        id: 'ecs-iterate-10k',
        name: 'ECS: Iterate 10k components',
        category: 'ecs',
        iterations: 200,
        budgetMs: 1,
        run: () => {
            const arr = new Float64Array(10000);
            for (let i = 0; i < 10000; i++) {
                arr[i] = i * 0.01;
            }
        },
    },
    {
        id: 'physics-aabb-1k',
        name: 'Physics: 1k AABB overlap checks',
        category: 'physics',
        iterations: 200,
        budgetMs: 1,
        run: () => {
        },
    },
    {
        id: 'rendering-transform-10k',
        name: 'Rendering: 10k transform multiplications',
        category: 'rendering',
        iterations: 200,
        budgetMs: 2,
        run: () => {
            const m = new Float64Array(9);
            for (let i = 0; i < 10000; i++) {
                m[0] = Math.cos(i);
                m[1] = -Math.sin(i);
                m[2] = i;
                m[3] = Math.sin(i);
                m[4] = Math.cos(i);
                m[5] = i;
                m[6] = 0;
                m[7] = 0;
                m[8] = 1;
            }
        },
    },
    {
        id: 'scene-graph-traverse',
        name: 'Scene: Traverse 1000-node tree',
        category: 'scene',
        iterations: 200,
        budgetMs: 1,
        setup: () => {
            // Build a tree in setup
            const nodes = [];
            for (let i = 0; i < 1000; i++) {
                nodes.push({ id: i, children: [] });
            }
            for (let i = 1; i < 1000; i++) {
                const parentIdx = Math.floor(Math.random() * i);
                nodes[parentIdx].children.push(i);
            }
            globalThis.__benchNodes = nodes;
            return () => { delete globalThis.__benchNodes; };
        },
        run: () => {
            const nodes = globalThis.__benchNodes;
            if (!nodes)
                return;
            const stack = [0];
            while (stack.length > 0) {
                const idx = stack.pop();
                const node = nodes[idx];
                for (let i = node.children.length - 1; i >= 0; i--) {
                    stack.push(node.children[i]);
                }
            }
        },
    },
    {
        id: 'general-event-dispatch',
        name: 'General: 10k event dispatches',
        category: 'general',
        iterations: 200,
        budgetMs: 2,
        run: () => {
            const handlers = [];
            for (let i = 0; i < 10; i++) {
                handlers.push(() => { });
            }
            for (let i = 0; i < 10000; i++) {
                for (const h of handlers)
                    h();
            }
        },
    },
    {
        id: 'general-object-pool',
        name: 'General: Object pool acquire/release 10k',
        category: 'general',
        iterations: 200,
        budgetMs: 1,
        run: () => {
            var _a;
            const pool = [];
            for (let i = 0; i < 100; i++) {
                pool.push({ x: 0, y: 0 });
            }
            for (let i = 0; i < 10000; i++) {
                const obj = (_a = pool.pop()) !== null && _a !== void 0 ? _a : { x: 0, y: 0 };
                obj.x = i;
                obj.y = i;
                pool.push(obj);
            }
        },
    },
];

exports.BUILTIN_BENCHMARKS = BUILTIN_BENCHMARKS;
exports.BenchmarkRunner = BenchmarkRunner;
//# sourceMappingURL=BenchmarkSuite.js.map
