/**
 * @fileoverview Performance Benchmarker Tests
 */

import { beforeEach, describe, expect, it, vi } from 'vitest';
import type { BenchmarkConfig, PerformanceMetrics } from './performance-benchmarker.js';
import { PerformanceBenchmarker } from './performance-benchmarker.js';

// Mock performance API
const mockPerformance = {
  now: vi.fn(() => Date.now())
};

// Mock global performance
global.performance = mockPerformance as any;

describe('PerformanceBenchmarker', () => {
  let benchmarker: PerformanceBenchmarker;

  beforeEach(() => {
    benchmarker = new PerformanceBenchmarker();
    vi.clearAllMocks();
  });

  describe('constructor', () => {
    it('should initialize with default configuration', () => {
      expect(benchmarker).toBeInstanceOf(PerformanceBenchmarker);
    });

    it('should accept custom configuration', () => {
      const customConfig: Partial<BenchmarkConfig> = {
        iterations: 5,
        includeRuntime: false,
        measureMemory: false
      };

      const customBenchmarker = new PerformanceBenchmarker(customConfig);
      expect(customBenchmarker).toBeInstanceOf(PerformanceBenchmarker);
    });
  });

  describe('benchmarkComponent', () => {
    it('should benchmark a simple component', async () => {
      const source = `
        component SimpleComponent {
          client {
            let count = 0;
            function increment() {
              count++;
            }
          }
          markup {
            <div>
              <h1>Hello World</h1>
              <button onclick="increment">Click me</button>
            </div>
          }
        }
      `;

      const result = await benchmarker.benchmarkComponent(source, 'SimpleComponent');

      expect(result).toBeDefined();
      expect(result.componentName).toBe('SimpleComponent');
      expect(result.averageMetrics).toBeDefined();
      expect(result.measurements).toHaveLength(10); // Default iterations
      expect(result.validation).toBeDefined();
      expect(result.suggestions).toBeDefined();
    });

    it('should handle complex components', async () => {
      const source = `
        component ComplexComponent {
          client {
            let users = [];
            let loading = false;
            let error = null;

            function fetchUsers() {
              loading = true;
              // Simulate API call
              setTimeout(() => {
                users = [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }];
                loading = false;
              }, 1000);
            }

            function addUser(name) {
              users.push({ id: users.length + 1, name });
            }

            function removeUser(id) {
              users = users.filter(user => user.id !== id);
            }
          }

          markup {
            <div class="container">
              <h1>User Management</h1>
              {loading ? <p>Loading...</p> : null}
              {error ? <p class="error">{error}</p> : null}
              <button onclick="fetchUsers">Load Users</button>
              <ul>
                {users.map(user =>
                  <li key={user.id}>
                    {user.name}
                    <button onclick={() => removeUser(user.id)}>Delete</button>
                  </li>
                )}
              </ul>
            </div>
          }
        }
      `;

      const result = await benchmarker.benchmarkComponent(source, 'ComplexComponent');

      expect(result.averageMetrics.compilationTime).toBeGreaterThan(0);
      expect(result.averageMetrics.bundleSize).toBeGreaterThan(0);
      expect(result.averageMetrics.astNodeCount).toBeGreaterThan(0);
      expect(result.averageMetrics.tokenCount).toBeGreaterThan(0);
    });

    it('should handle components with server blocks', async () => {
      const source = `
        component ServerComponent {
          server {
            public async function getData() {
              return { message: "Hello from server" };
            }

            function internalHelper() {
              return "internal";
            }
          }

          client {
            let data = null;

            async function loadData() {
              data = await server.getData();
            }
          }

          markup {
            <div>
              <h1>Server Component</h1>
              {data ? <p>{data.message}</p> : <p>No data</p>}
              <button onclick="loadData">Load Data</button>
            </div>
          }
        }
      `;

      const result = await benchmarker.benchmarkComponent(source, 'ServerComponent');

      expect(result.averageMetrics.compilationTime).toBeGreaterThan(0);
      expect(result.averageMetrics.bundleSize).toBeGreaterThan(0);
    });

    it('should handle components with CSS', async () => {
      const source = `
        component StyledComponent {
          client {
            let theme = 'light';

            function toggleTheme() {
              theme = theme === 'light' ? 'dark' : 'light';
            }
          }

          markup {
            <div class="container">
              <h1>Styled Component</h1>
              <button onclick="toggleTheme">Toggle Theme</button>
            </div>
          }

          style {
            .container {
              padding: 20px;
              background: var(--bg-color);
              color: var(--text-color);
            }

            .container.dark {
              --bg-color: #333;
              --text-color: #fff;
            }

            .container.light {
              --bg-color: #fff;
              --text-color: #333;
            }
          }
        }
      `;

      const result = await benchmarker.benchmarkComponent(source, 'StyledComponent');

      expect(result.averageMetrics.compilationTime).toBeGreaterThan(0);
      expect(result.averageMetrics.bundleSize).toBeGreaterThan(0);
    });

    it('should handle baseline comparison', async () => {
      const source = `
        component TestComponent {
          client {
            let count = 0;
            function increment() { count++; }
          }
          markup {
            <div>
              <h1>Test</h1>
              <button onclick="increment">Click</button>
            </div>
          }
        }
      `;

      // Set baseline
      const baselineMetrics: PerformanceMetrics = {
        compilationTime: 50,
        lexingTime: 10,
        parsingTime: 15,
        codeGenerationTime: 20,
        optimizationTime: 5,
        bundleSize: 5000,
        gzippedSize: 1500,
        brotliSize: 1200,
        astNodeCount: 50,
        tokenCount: 200,
        memoryUsage: 1000000
      };

      benchmarker.setBaseline('baseline', baselineMetrics);

      const result = await benchmarker.benchmarkComponent(source, 'TestComponent', 'baseline');

      expect(result.comparison).toBeDefined();
      expect(result.comparison!.baseline).toEqual(baselineMetrics);
      expect(result.comparison!.improvement).toBeDefined();
    });

    it('should handle performance validation', async () => {
      const customBenchmarker = new PerformanceBenchmarker({
        thresholds: {
          maxCompilationTime: 10, // Very strict threshold
          maxBundleSize: 1000, // Very strict threshold
          maxHydrationTime: 50,
          maxTimeToFirstPaint: 1000,
          maxTimeToInteractive: 1500
        }
      });

      const source = `
        component LargeComponent {
          client {
            let data = [];
            function generateData() {
              for (let i = 0; i < 1000; i++) {
                data.push({ id: i, value: Math.random() });
              }
            }
          }
          markup {
            <div>
              <h1>Large Component</h1>
              <button onclick="generateData">Generate Data</button>
              {data.map(item => <div key={item.id}>{item.value}</div>)}
            </div>
          }
        }
      `;

      const result = await customBenchmarker.benchmarkComponent(source, 'LargeComponent');

      expect(result.validation.passed).toBe(false);
      expect(result.validation.failures.length).toBeGreaterThan(0);
      expect(result.validation.score).toBeLessThan(100);
    });

    it('should generate optimization suggestions', async () => {
      const source = `
        component OptimizableComponent {
          client {
            let unusedVar = "unused";
            let usedVar = "used";

            function unusedFunction() {
              return "unused";
            }

            function usedFunction() {
              return usedVar;
            }
          }
          markup {
            <div>
              <h1>{usedFunction()}</h1>
            </div>
          }
        }
      `;

      const result = await benchmarker.benchmarkComponent(source, 'OptimizableComponent');

      expect(result.suggestions.length).toBeGreaterThan(0);
      expect(result.suggestions.some(s => s.includes('tree shaking'))).toBe(true);
    });

    it('should handle errors gracefully', async () => {
      const invalidSource = `
        component InvalidComponent {
          client {
            let count = 0;
            function increment() {
              count++;
            }
          }
          markup {
            <div>
              <h1>Invalid Component
              <!-- Missing closing tag -->
            </div>
          }
        }
      `;

      await expect(benchmarker.benchmarkComponent(invalidSource, 'InvalidComponent')).rejects.toThrow();

      const errors = benchmarker.getErrors();
      expect(errors.length).toBeGreaterThan(0);
    });

    it('should handle empty components', async () => {
      const emptySource = `
        component EmptyComponent {
          markup {
            <div></div>
          }
        }
      `;

      const result = await benchmarker.benchmarkComponent(emptySource, 'EmptyComponent');

      expect(result.averageMetrics.compilationTime).toBeGreaterThan(0);
      expect(result.averageMetrics.bundleSize).toBeGreaterThan(0);
      expect(result.averageMetrics.astNodeCount).toBeGreaterThan(0);
    });

    it('should handle components with many reactive variables', async () => {
      const source = `
        component ReactiveComponent {
          client {
            let var1 = 1;
            let var2 = 2;
            let var3 = 3;
            let var4 = 4;
            let var5 = 5;
            let var6 = 6;
            let var7 = 7;
            let var8 = 8;
            let var9 = 9;
            let var10 = 10;

            function updateAll() {
              var1++; var2++; var3++; var4++; var5++;
              var6++; var7++; var8++; var9++; var10++;
            }
          }
          markup {
            <div>
              <h1>Reactive Component</h1>
              <p>Var1: {var1}</p>
              <p>Var2: {var2}</p>
              <p>Var3: {var3}</p>
              <p>Var4: {var4}</p>
              <p>Var5: {var5}</p>
              <p>Var6: {var6}</p>
              <p>Var7: {var7}</p>
              <p>Var8: {var8}</p>
              <p>Var9: {var9}</p>
              <p>Var10: {var10}</p>
              <button onclick="updateAll">Update All</button>
            </div>
          }
        }
      `;

      const result = await benchmarker.benchmarkComponent(source, 'ReactiveComponent');

      expect(result.averageMetrics.compilationTime).toBeGreaterThan(0);
      expect(result.averageMetrics.bundleSize).toBeGreaterThan(0);
      expect(result.averageMetrics.astNodeCount).toBeGreaterThan(10);
    });

    it('should handle components with complex expressions', async () => {
      const source = `
        component ComplexExpressionsComponent {
          client {
            let items = [1, 2, 3, 4, 5];
            let filter = '';

            function filteredItems() {
              return items.filter(item =>
                item.toString().includes(filter)
              ).map(item => ({
                value: item,
                doubled: item * 2,
                squared: item * item
              }));
            }

            function addItem() {
              items.push(items.length + 1);
            }
          }
          markup {
            <div>
              <h1>Complex Expressions</h1>
              <input bind:value="filter" placeholder="Filter items" />
              <button onclick="addItem">Add Item</button>
              <ul>
                {filteredItems().map(item =>
                  <li key={item.value}>
                    {item.value} (doubled: {item.doubled}, squared: {item.squared})
                  </li>
                )}
              </ul>
            </div>
          }
        }
      `;

      const result = await benchmarker.benchmarkComponent(source, 'ComplexExpressionsComponent');

      expect(result.averageMetrics.compilationTime).toBeGreaterThan(0);
      expect(result.averageMetrics.bundleSize).toBeGreaterThan(0);
      expect(result.averageMetrics.tokenCount).toBeGreaterThan(100);
    });
  });

  describe('configuration options', () => {
    it('should respect iterations configuration', async () => {
      const customBenchmarker = new PerformanceBenchmarker({ iterations: 3 });

      const source = `
        component TestComponent {
          client {
            let count = 0;
            function increment() { count++; }
          }
          markup {
            <div>
              <h1>Test</h1>
              <button onclick="increment">Click</button>
            </div>
          }
        }
      `;

      const result = await customBenchmarker.benchmarkComponent(source, 'TestComponent');

      expect(result.measurements).toHaveLength(3);
    });

    it('should respect includeRuntime configuration', async () => {
      const benchmarkerWithoutRuntime = new PerformanceBenchmarker({ includeRuntime: false });

      const source = `
        component TestComponent {
          client {
            let count = 0;
            function increment() { count++; }
          }
          markup {
            <div>
              <h1>Test</h1>
              <button onclick="increment">Click</button>
            </div>
          }
        }
      `;

      const result = await benchmarkerWithoutRuntime.benchmarkComponent(source, 'TestComponent');

      expect(result.averageMetrics.runtimeMetrics).toBeUndefined();
    });

    it('should respect measureMemory configuration', async () => {
      const benchmarkerWithoutMemory = new PerformanceBenchmarker({ measureMemory: false });

      const source = `
        component TestComponent {
          client {
            let count = 0;
            function increment() { count++; }
          }
          markup {
            <div>
              <h1>Test</h1>
              <button onclick="increment">Click</button>
            </div>
          }
        }
      `;

      const result = await benchmarkerWithoutMemory.benchmarkComponent(source, 'TestComponent');

      expect(result.averageMetrics.memoryUsage).toBe(0);
    });
  });

  describe('baseline management', () => {
    it('should set and get baseline metrics', () => {
      const metrics: PerformanceMetrics = {
        compilationTime: 100,
        lexingTime: 20,
        parsingTime: 30,
        codeGenerationTime: 40,
        optimizationTime: 10,
        bundleSize: 10000,
        gzippedSize: 3000,
        brotliSize: 2500,
        astNodeCount: 100,
        tokenCount: 500,
        memoryUsage: 2000000
      };

      benchmarker.setBaseline('test-baseline', metrics);
      const retrieved = benchmarker.getBaseline('test-baseline');

      expect(retrieved).toEqual(metrics);
    });

    it('should return undefined for non-existent baseline', () => {
      const retrieved = benchmarker.getBaseline('non-existent');
      expect(retrieved).toBeUndefined();
    });
  });

  describe('error handling', () => {
    it('should handle null source', async () => {
      await expect(benchmarker.benchmarkComponent(null as any, 'TestComponent')).rejects.toThrow();
    });

    it('should handle undefined source', async () => {
      await expect(benchmarker.benchmarkComponent(undefined as any, 'TestComponent')).rejects.toThrow();
    });

    it('should handle empty source', async () => {
      await expect(benchmarker.benchmarkComponent('', 'TestComponent')).rejects.toThrow();
    });

    it('should handle malformed source', async () => {
      const malformedSource = `
        component MalformedComponent {
          client {
            let count = 0;
            function increment() {
              count++;
            }
          }
          markup {
            <div>
              <h1>Malformed
              <!-- Missing closing tags and syntax errors -->
            </div>
          }
        }
      `;

      await expect(benchmarker.benchmarkComponent(malformedSource, 'MalformedComponent')).rejects.toThrow();
    });
  });

  describe('report generation', () => {
    it('should generate comprehensive performance report', async () => {
      const source = `
        component ReportComponent {
          client {
            let data = [];
            function loadData() {
              data = [1, 2, 3, 4, 5];
            }
          }
          markup {
            <div>
              <h1>Report Component</h1>
              <button onclick="loadData">Load Data</button>
              {data.map(item => <div key={item}>{item}</div>)}
            </div>
          }
        }
      `;

      const result = await benchmarker.benchmarkComponent(source, 'ReportComponent');
      const report = benchmarker.generateReport(result);

      expect(report).toContain('# Performance Report: ReportComponent');
      expect(report).toContain('## Compilation Metrics');
      expect(report).toContain('## Bundle Metrics');
      expect(report).toContain('## Performance Validation');
      expect(report).toContain('## Optimization Suggestions');
    });
  });
});
