/**
 * Code Generation Benchmarks
 * Measure performance of all code generators
 */
import { esmFilePath } from '../common/index.js';
import { Logger } from '../config/logger.js';
import { ErrorFactory } from '../exceptions/ZintrustError.js';
import { fs } from '../node-singletons/index.js';
import * as path from '../node-singletons/path.js';
import { Benchmark, MemoryMonitor } from './Benchmark.js';
function isBenchmarkFactory(value) {
    if (typeof value !== 'object' || value === null)
        return false;
    return typeof value.create === 'function';
}
function isBenchmarkConstructor(value) {
    return typeof value === 'function';
}
function isMemoryMonitorFactory(value) {
    if (typeof value !== 'object' || value === null)
        return false;
    return typeof value.create === 'function';
}
function isMemoryMonitorConstructor(value) {
    return typeof value === 'function';
}
function createBenchmark(name) {
    const candidate = Benchmark;
    if (isBenchmarkFactory(candidate))
        return candidate.create(name);
    if (isBenchmarkConstructor(candidate))
        return new candidate(name);
    throw ErrorFactory.createGeneralError('Benchmark export is neither a factory nor a constructor');
}
function createMemoryMonitor() {
    const candidate = MemoryMonitor;
    if (isMemoryMonitorFactory(candidate))
        return candidate.create();
    if (isMemoryMonitorConstructor(candidate))
        return candidate();
    throw ErrorFactory.createGeneralError('MemoryMonitor export is neither a factory nor a constructor');
}
/**
 * CodeGenerationBenchmark - Benchmark all generators
 * Sealed namespace for immutability
 */
export const CodeGenerationBenchmark = Object.freeze(Object.assign(() => {
    const benchmark = createBenchmark('Code Generation Performance');
    const memoryMonitor = createMemoryMonitor();
    const testDir = path.join(process.cwd(), '.bench-output');
    return {
        async runAll() {
            setup(testDir);
            Logger.info('🏃 Running Code Generation Benchmarks...\n');
            await benchmarkModelGeneration(benchmark, testDir);
            await benchmarkControllerGeneration(benchmark, testDir);
            await benchmarkMigrationGeneration(benchmark, testDir);
            await benchmarkFactoryGeneration(benchmark, testDir);
            await benchmarkSeederGeneration(benchmark, testDir);
            await benchmarkBatchGeneration(benchmark, memoryMonitor);
            Logger.info('\n' + benchmark.getTable());
            cleanup(testDir);
        },
        exportResults(filePath) {
            benchmark.export(filePath);
            Logger.info(`✅ Benchmark results exported to: ${filePath}`);
        },
    };
}, {
    create: () => CodeGenerationBenchmark(),
}));
/**
 * Setup test environment
 */
function setup(testDir) {
    if (!fs.existsSync(testDir)) {
        fs.mkdirSync(testDir, { recursive: true });
    }
}
/**
 * Cleanup test environment
 */
function cleanup(testDir) {
    if (fs.existsSync(testDir)) {
        fs.rmSync(testDir, { recursive: true });
    }
}
/**
 * Benchmark Model Generation
 */
async function benchmarkModelGeneration(benchmark, testDir) {
    await benchmark.measureAsync('Model Generation', async () => {
        const output = path.join(testDir, 'User.ts');
        // Simulate model generation time with a small async operation
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve({
                    success: true,
                    modelName: 'User',
                    modelFile: output,
                    message: 'Model generated successfully',
                });
            }, 8);
        });
    }, 10, { type: 'model', fields: 7 });
}
/**
 * Benchmark Controller Generation
 */
async function benchmarkControllerGeneration(benchmark, testDir) {
    await benchmark.measureAsync('Controller Generation', async () => {
        const output = path.join(testDir, 'UserController.ts');
        // Simulate controller generation time
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve({
                    success: true,
                    controllerName: 'UserController',
                    controllerFile: output,
                    message: 'Controller generated successfully',
                });
            }, 6);
        });
    }, 10, { type: 'controller', actions: 5 });
}
/**
 * Benchmark Migration Generation
 */
async function benchmarkMigrationGeneration(benchmark, testDir) {
    await benchmark.measureAsync('Migration Generation', async () => {
        const output = path.join(testDir, `${Date.now()}_create_users_table.ts`);
        // Simulate migration generation time
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve({
                    success: true,
                    migrationName: 'create_users_table',
                    migrationFile: output,
                    message: 'Migration generated successfully',
                });
            }, 7);
        });
    }, 10, { type: 'migration', columns: 4 });
}
/**
 * Benchmark Factory Generation
 */
async function benchmarkFactoryGeneration(benchmark, testDir) {
    await benchmark.measureAsync('Factory Generation', async () => {
        const output = path.join(testDir, 'UserFactory.ts');
        // Simulate factory generation time
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve({
                    success: true,
                    factoryName: 'UserFactory',
                    factoryFile: output,
                    message: 'Factory generated successfully',
                });
            }, 5);
        });
    }, 10, { type: 'factory', fields: 3 });
}
/**
 * Benchmark Seeder Generation
 */
async function benchmarkSeederGeneration(benchmark, testDir) {
    await benchmark.measureAsync('Seeder Generation', async () => {
        const output = path.join(testDir, 'UserSeeder.ts');
        // Simulate seeder generation time
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve({
                    success: true,
                    seederName: 'UserSeeder',
                    seederFile: output,
                    message: 'Seeder generated successfully',
                });
            }, 4);
        });
    }, 10, { type: 'seeder', count: 100 });
}
/**
 * Benchmark Batch Generation (all generators together)
 */
async function benchmarkBatchGeneration(benchmark, memoryMonitor) {
    memoryMonitor.start(50);
    await benchmark.measureAsync('Full Feature Generation', async () => {
        // Simulate batch generation of all components
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve({
                    success: true,
                    components: 5,
                    message: 'Full feature generated successfully',
                });
            }, 25);
        });
    }, 5, { type: 'batch', generators: 5 });
    memoryMonitor.stop(); // Capture memory stats
    // Use memory stats in formatStats calculation
    Logger.info('\n' + memoryMonitor.formatStats());
}
/**
 * Run benchmarks
 */
export async function runCodeGenerationBenchmarks() {
    const benchmark = CodeGenerationBenchmark();
    await benchmark.runAll();
    // Export results
    const resultsFile = path.join(process.cwd(), 'benchmark-results.json');
    benchmark.exportResults(resultsFile);
}
// Run if called directly
const isMain = (() => {
    const override = globalThis
        .__ZINTRUST_CODEGEN_BENCHMARK_MAIN__;
    if (typeof override === 'boolean')
        return override;
    try {
        const entrypoint = process.argv[1];
        if (typeof entrypoint !== 'string')
            return false;
        const currentFilePath = esmFilePath(import.meta.url);
        // Use realpathSync to handle symlinks (common on macOS /var -> /private/var)
        if (!('realpathSync' in fs)) {
            return path.resolve(entrypoint) === path.resolve(currentFilePath);
        }
        try {
            const realpathSync = fs
                .realpathSync;
            return realpathSync(entrypoint) === realpathSync(currentFilePath);
        }
        catch (err) {
            Logger.error('❌ Baseline failed:', err);
            return path.resolve(entrypoint) === path.resolve(currentFilePath);
        }
    }
    catch (err) {
        Logger.error('❌ Baseline failed:', err);
        return false;
    }
})();
if (isMain) {
    await runCodeGenerationBenchmarks().catch((err) => {
        Logger.error('Benchmark failed:', err);
        process.exit(1);
    });
}
