/**
 * Benchmarking Suite for Code Generation Performance
 *
 * Run with: npm run benchmark
 * Or: node dist/benchmarks/generation-benchmark.js
 */

import { CodeGenerator } from '../generators/code-generator';
import { GeneratorRegistry } from '../generators/generator-registry';
import { Workflow } from '../types/workflow';
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';

interface BenchmarkResult {
  name: string;
  duration: number;
  filesGenerated: number;
  success: boolean;
  memoryUsed: number;
  error?: string;
}

interface BenchmarkSuite {
  name: string;
  results: BenchmarkResult[];
  totalDuration: number;
  averageDuration: number;
  successRate: number;
  systemInfo: {
    platform: string;
    cpus: number;
    memory: number;
    nodeVersion: string;
  };
}

export class GenerationBenchmark {
  private generator: CodeGenerator;
  private results: BenchmarkResult[] = [];
  private outputDir: string;

  constructor() {
    const registry = new GeneratorRegistry();
    this.generator = new CodeGenerator(registry);
    this.outputDir = path.join(os.tmpdir(), 'bangstack-benchmark');
  }

  /**
   * Run all benchmarks
   */
  async runAll(): Promise<BenchmarkSuite> {
    console.log('🚀 Starting Bangstack Generation Benchmarks\n');

    // Clean up output directory
    await this.cleanup();

    // Run benchmarks
    await this.benchmarkSmallWorkflow();
    await this.benchmarkMediumWorkflow();
    await this.benchmarkLargeWorkflow();
    await this.benchmarkTestHeavyWorkflow();
    await this.benchmarkParallelVsSequential();

    // Cleanup after benchmarks
    await this.cleanup();

    return this.generateReport();
  }

  /**
   * Small workflow: 1 model, 1 frontend, 1 backend
   */
  private async benchmarkSmallWorkflow(): Promise<void> {
    const workflow: Workflow = {
      workflow: {
        id: 'small-bench',
        version: '1.0.0',
        name: 'Small Workflow',
        description: 'Minimal workflow for benchmarking',
        actors: [],
      },
      stack: {
        frontend: {
          type: 'frontend',
          technology: 'react',
          components: [],
        },
        backend: {
          type: 'backend',
          technology: 'typescript/express',
          endpoints: [],
        },
      },
    };

    await this.runBenchmark('Small Workflow (1 model, 1 frontend, 1 backend)', workflow);
  }

  /**
   * Medium workflow: 5 models, frontend, backend, 3 test types
   */
  private async benchmarkMediumWorkflow(): Promise<void> {
    const workflow: Workflow = {
      workflow: {
        id: 'medium-bench',
        version: '1.0.0',
        name: 'Medium Workflow',
        description: 'Medium-sized workflow for benchmarking',
        actors: [],
      },
      stack: {
        frontend: {
          type: 'frontend',
          technology: 'react',
          components: [],
        },
        backend: {
          type: 'backend',
          technology: 'typescript/express',
          endpoints: [],
        },
      },
      testing: {
        unit_tests: [
          { component: 'frontend', scenarios: ['render', 'interactions'] },
        ],
        e2e_tests: [
          { name: 'Basic flow', tool: 'playwright', steps: ['navigate', 'click', 'verify'] },
        ],
      },
    };

    await this.runBenchmark('Medium Workflow (5 models, frontend, backend, 3 tests)', workflow);
  }

  /**
   * Large workflow: 15 models, frontend, backend, 4 test types, CI/CD
   */
  private async benchmarkLargeWorkflow(): Promise<void> {
    const workflow: Workflow = {
      workflow: {
        id: 'large-bench',
        version: '1.0.0',
        name: 'Large Workflow',
        description: 'Large workflow for benchmarking',
        actors: [],
      },
      stack: {
        frontend: {
          type: 'frontend',
          technology: 'react',
          components: [],
        },
        backend: {
          type: 'backend',
          technology: 'typescript/express',
          endpoints: [],
        },
      },
      testing: {
        unit_tests: [
          { component: 'frontend', scenarios: ['render', 'interactions'] },
        ],
        e2e_tests: [
          { name: 'Basic flow', tool: 'playwright', steps: ['navigate', 'click', 'verify'] },
        ],
      },
      documentation: {
        developer_docs: [
          {
            title: 'API Documentation',
            sections: [
              { heading: 'Getting Started', content: 'How to use the API', steps: [] },
            ],
          },
        ],
      },
    };

    await this.runBenchmark('Large Workflow (15 models, frontend, backend, 4 tests, CI/CD)', workflow);
  }

  /**
   * Test-heavy workflow: 1 model but all test types
   */
  private async benchmarkTestHeavyWorkflow(): Promise<void> {
    const workflow: Workflow = {
      workflow: {
        id: 'test-heavy-bench',
        version: '1.0.0',
        name: 'Test-Heavy Workflow',
        description: 'Test-heavy workflow for benchmarking',
        actors: [],
      },
      stack: {
        frontend: {
          type: 'frontend',
          technology: 'react',
          components: [],
        },
        backend: {
          type: 'backend',
          technology: 'typescript/express',
          endpoints: [],
        },
      },
      testing: {
        unit_tests: [
          { component: 'frontend', scenarios: ['render', 'interactions'] },
        ],
        e2e_tests: [
          { name: 'Basic flow', tool: 'playwright', steps: ['navigate', 'click', 'verify'] },
        ],
      },
    };

    await this.runBenchmark('Test-Heavy Workflow (1 model, 4 test types)', workflow);
  }

  /**
   * Compare parallel vs sequential execution
   */
  private async benchmarkParallelVsSequential(): Promise<void> {
    const workflow: Workflow = {
      workflow: {
        id: 'parallel-bench',
        version: '1.0.0',
        name: 'Parallel Benchmark',
        description: 'Compare parallel vs sequential',
        actors: [],
      },
      stack: {
        frontend: {
          type: 'frontend',
          technology: 'react',
          components: [],
        },
        backend: {
          type: 'backend',
          technology: 'typescript/express',
          endpoints: [],
        },
      },
      testing: {
        unit_tests: [
          { component: 'frontend', scenarios: ['render', 'interactions'] },
        ],
        e2e_tests: [
          { name: 'Basic flow', tool: 'playwright', steps: ['navigate', 'click', 'verify'] },
        ],
      },
    };

    // Run with parallel execution
    await this.runBenchmark('Parallel Execution (enabled)', workflow, {
      parallelExecution: true,
    });

    // Note: Sequential execution would require code changes to disable parallel execution
    // For now, we track the speedup in the parallel executor metrics
  }

  /**
   * Run a single benchmark
   */
  private async runBenchmark(
    name: string,
    workflow: Workflow,
    options: any = {}
  ): Promise<void> {
    console.log(`⏱️  Running: ${name}`);

    const startMemory = process.memoryUsage().heapUsed;
    const startTime = Date.now();

    let success = true;
    let filesGenerated = 0;
    let error: string | undefined;

    try {
      const result = await this.generator.generate(workflow, {
        outputDirectory: this.outputDir,
        dryRun: true, // Don't actually write files for benchmarks
        ...options,
      });

      filesGenerated = result.files.length;
      success = result.errors.length === 0;

      if (result.errors.length > 0) {
        error = result.errors[0];
      }
    } catch (err) {
      success = false;
      error = err instanceof Error ? err.message : String(err);
    }

    const duration = Date.now() - startTime;
    const endMemory = process.memoryUsage().heapUsed;
    const memoryUsed = endMemory - startMemory;

    const result: BenchmarkResult = {
      name,
      duration,
      filesGenerated,
      success,
      memoryUsed,
      error,
    };

    this.results.push(result);

    const status = success ? '✅' : '❌';
    console.log(`${status} ${name}: ${duration}ms (${filesGenerated} files)\n`);
  }

  /**
   * Generate benchmark report
   */
  private generateReport(): BenchmarkSuite {
    const totalDuration = this.results.reduce((sum, r) => sum + r.duration, 0);
    const averageDuration = totalDuration / this.results.length;
    const successCount = this.results.filter(r => r.success).length;
    const successRate = (successCount / this.results.length) * 100;

    const suite: BenchmarkSuite = {
      name: 'Bangstack Generation Benchmarks',
      results: this.results,
      totalDuration,
      averageDuration,
      successRate,
      systemInfo: {
        platform: `${os.platform()} ${os.release()}`,
        cpus: os.cpus().length,
        memory: Math.round(os.totalmem() / 1024 / 1024 / 1024), // GB
        nodeVersion: process.version,
      },
    };

    this.printReport(suite);
    return suite;
  }

  /**
   * Print formatted report
   */
  private printReport(suite: BenchmarkSuite): void {
    console.log('\n' + '='.repeat(80));
    console.log('📊 BENCHMARK RESULTS');
    console.log('='.repeat(80) + '\n');

    console.log('System Information:');
    console.log(`  Platform: ${suite.systemInfo.platform}`);
    console.log(`  CPUs: ${suite.systemInfo.cpus} cores`);
    console.log(`  Memory: ${suite.systemInfo.memory} GB`);
    console.log(`  Node: ${suite.systemInfo.nodeVersion}\n`);

    console.log('Results:');
    console.log('─'.repeat(80));
    console.log(
      `${'Benchmark'.padEnd(50)} ${'Time'.padStart(10)} ${'Files'.padStart(10)}`
    );
    console.log('─'.repeat(80));

    for (const result of suite.results) {
      const status = result.success ? '✅' : '❌';
      const name = `${status} ${result.name}`.padEnd(50);
      const duration = `${result.duration}ms`.padStart(10);
      const files = `${result.filesGenerated}`.padStart(10);

      console.log(`${name} ${duration} ${files}`);

      if (result.error) {
        console.log(`   Error: ${result.error}`);
      }
    }

    console.log('─'.repeat(80));
    console.log(`${'TOTAL'.padEnd(50)} ${`${suite.totalDuration}ms`.padStart(10)}`);
    console.log(`${'AVERAGE'.padEnd(50)} ${`${Math.round(suite.averageDuration)}ms`.padStart(10)}`);
    console.log(`${'SUCCESS RATE'.padEnd(50)} ${`${suite.successRate.toFixed(1)}%`.padStart(10)}`);
    console.log('─'.repeat(80) + '\n');

    // Performance insights
    const fastest = this.results.reduce((min, r) => r.duration < min.duration ? r : min);
    const slowest = this.results.reduce((max, r) => r.duration > max.duration ? r : max);

    console.log('Performance Insights:');
    console.log(`  Fastest: ${fastest.name} (${fastest.duration}ms)`);
    console.log(`  Slowest: ${slowest.name} (${slowest.duration}ms)`);

    if (slowest.duration > 0) {
      const ratio = slowest.duration / fastest.duration;
      console.log(`  Ratio: ${ratio.toFixed(2)}x`);
    }

    console.log('\n' + '='.repeat(80) + '\n');
  }

  /**
   * Clean up benchmark output directory
   */
  private async cleanup(): Promise<void> {
    try {
      if (fs.existsSync(this.outputDir)) {
        fs.rmSync(this.outputDir, { recursive: true, force: true });
      }
    } catch (error) {
      console.warn('Warning: Failed to cleanup benchmark directory:', error);
    }
  }

  /**
   * Save results to JSON file
   */
  async saveResults(outputPath: string): Promise<void> {
    const suite = this.generateReport();
    const json = JSON.stringify(suite, null, 2);
    fs.writeFileSync(outputPath, json, 'utf8');
    console.log(`📁 Results saved to: ${outputPath}`);
  }
}

// CLI entry point
if (require.main === module) {
  const benchmark = new GenerationBenchmark();

  benchmark.runAll()
    .then(async (suite) => {
      // Save results to file
      const outputPath = path.join(process.cwd(), 'benchmark-results.json');
      await benchmark.saveResults(outputPath);

      // Exit with appropriate code
      process.exit(suite.successRate === 100 ? 0 : 1);
    })
    .catch((error) => {
      console.error('❌ Benchmark failed:', error);
      process.exit(1);
    });
}
