/**
 * Dynamic performance analysis using Playwright.
 * Measures: page load, bundle sizes, memory, rendering, network.
 */
import { chromium } from 'playwright';
import { readdirSync, statSync } from 'fs';
import { join } from 'path';

const DIST = join(import.meta.dirname, '..', 'dist');
const PORT = 4174;

// ─── Bundle analysis from dist ───
function analyzeBundles() {
  const assets = readdirSync(join(DIST, 'assets'));
  const jsFiles = assets.filter(f => f.endsWith('.js'));
  const cssFiles = assets.filter(f => f.endsWith('.css'));
  const brFiles = assets.filter(f => f.endsWith('.js.br'));
  
  let totalJsSize = 0, totalCssSize = 0, totalBrSize = 0;
  const bundles = [];
  
  for (const f of jsFiles) {
    const size = statSync(join(DIST, 'assets', f)).size;
    totalJsSize += size;
    bundles.push({ name: f, sizeKB: (size / 1024).toFixed(2), type: 'js' });
  }
  for (const f of cssFiles) {
    const size = statSync(join(DIST, 'assets', f)).size;
    totalCssSize += size;
    bundles.push({ name: f, sizeKB: (size / 1024).toFixed(2), type: 'css' });
  }
  for (const f of brFiles) {
    const size = statSync(join(DIST, 'assets', f)).size;
    totalBrSize += size;
  }
  
  bundles.sort((a, b) => parseFloat(b.sizeKB) - parseFloat(a.sizeKB));
  
  console.log('\n═══════════════════════════════════════════════');
  console.log('  BUNDLE SIZE ANALYSIS');
  console.log('═══════════════════════════════════════════════');
  console.log(`\nTotal JS (raw):     ${(totalJsSize / 1024).toFixed(1)} KB`);
  console.log(`Total CSS (raw):    ${(totalCssSize / 1024).toFixed(1)} KB`);
  console.log(`Total JS (brotli):  ${(totalBrSize / 1024).toFixed(1)} KB`);
  console.log(`\nTop 15 bundles by raw size:`);
  for (const b of bundles.slice(0, 15)) {
    const bar = '█'.repeat(Math.min(40, Math.round(parseFloat(b.sizeKB) / 5)));
    console.log(`  ${b.name.padEnd(45)} ${String(b.sizeKB).padStart(8)} KB  ${bar}`);
  }
  
  // Identify oversized chunks
  console.log('\n⚠️  Oversized chunks (>50KB raw):');
  for (const b of bundles.filter(b => parseFloat(b.sizeKB) > 50)) {
    console.log(`  [WARN] ${b.name} = ${b.sizeKB} KB`);
  }
  
  return { totalJsSize, totalCssSize, totalBrSize, bundles };
}

// ─── Runtime performance with Playwright ───
async function runtimeAnalysis() {
  console.log('\n═══════════════════════════════════════════════');
  console.log('  RUNTIME PERFORMANCE ANALYSIS');
  console.log('═══════════════════════════════════════════════');
  
  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext({ viewport: { width: 1920, height: 1080 } });
  const page = await context.newPage();
  
  // Collect performance metrics
  const perfEntries = [];
  page.on('console', msg => {
    if (msg.type() === 'info' && msg.text().startsWith('[PERF]')) {
      perfEntries.push(msg.text());
    }
  });
  
  // Track network requests
  const networkRequests = [];
  page.on('request', req => {
    networkRequests.push({
      url: req.url(),
      method: req.method(),
      startTime: Date.now()
    });
  });
  
  const networkResponses = [];
  page.on('response', res => {
    networkResponses.push({
      url: res.url(),
      status: res.status(),
      size: res.headers()['content-length'] || '0',
      endTime: Date.now()
    });
  });
  
  // Measure page load
  console.log('\n--- Page Load Performance ---');
  const navStart = Date.now();
  
  try {
    const response = await page.goto(`http://127.0.0.1:${PORT}/`, { 
      waitUntil: 'networkidle',
      timeout: 30000 
    });
    const loadTime = Date.now() - navStart;
    console.log(`  Initial page load:  ${loadTime}ms`);
    console.log(`  HTTP status:        ${response.status()}`);
    
    // Get navigation timing from the browser
    const navTiming = await page.evaluate(() => {
      const perf = performance.getEntriesByType('navigation')[0];
      if (!perf) return null;
      return {
        dns: Math.round(perf.domainLookupEnd - perf.domainLookupStart),
        tcp: Math.round(perf.connectEnd - perf.connectStart),
        ttfb: Math.round(perf.responseStart - perf.requestStart),
        download: Math.round(perf.responseEnd - perf.responseStart),
        domInteractive: Math.round(perf.domInteractive),
        domComplete: Math.round(perf.domComplete),
        loadEvent: Math.round(perf.loadEventEnd),
        transferSize: perf.transferSize,
      };
    });
    
    if (navTiming) {
      console.log(`\n  Navigation Timing:`);
      console.log(`    DNS lookup:       ${navTiming.dns}ms`);
      console.log(`    TCP connect:      ${navTiming.tcp}ms`);
      console.log(`    TTFB:             ${navTiming.ttfb}ms`);
      console.log(`    Download:         ${navTiming.download}ms`);
      console.log(`    DOM interactive:  ${navTiming.domInteractive}ms`);
      console.log(`    DOM complete:     ${navTiming.domComplete}ms`);
      console.log(`    Load event end:   ${navTiming.loadEvent}ms`);
      console.log(`    Transfer size:    ${(navTiming.transferSize / 1024).toFixed(1)} KB`);
    }
    
    // Resource timing
    const resources = await page.evaluate(() => {
      return performance.getEntriesByType('resource').map(r => ({
        name: r.name.split('/').pop(),
        type: r.initiatorType,
        duration: Math.round(r.duration),
        size: r.transferSize,
      }));
    });
    
    console.log(`\n--- Resource Loading ---`);
    console.log(`  Total resources:    ${resources.length}`);
    const totalTransfer = resources.reduce((s, r) => s + r.size, 0);
    console.log(`  Total transfer:     ${(totalTransfer / 1024).toFixed(1)} KB`);
    
    const slowResources = resources.filter(r => r.duration > 100).sort((a, b) => b.duration - a.duration);
    if (slowResources.length > 0) {
      console.log(`\n  Slow resources (>100ms):`);
      for (const r of slowResources.slice(0, 10)) {
        console.log(`    [SLOW] ${r.name.padEnd(40)} ${r.duration}ms  (${(r.size/1024).toFixed(1)}KB)`);
      }
    }
    
    // Memory analysis
    console.log(`\n--- Memory Analysis ---`);
    const memory = await page.evaluate(() => {
      if (performance.memory) {
        return {
          usedJSHeap: performance.memory.usedJSHeapSize,
          totalJSHeap: performance.memory.totalJSHeapSize,
          heapLimit: performance.memory.jsHeapSizeLimit,
        };
      }
      return null;
    });
    
    if (memory) {
      console.log(`  Used JS heap:       ${(memory.usedJSHeap / 1024 / 1024).toFixed(1)} MB`);
      console.log(`  Total JS heap:      ${(memory.totalJSHeap / 1024 / 1024).toFixed(1)} MB`);
      console.log(`  Heap limit:         ${(memory.heapLimit / 1024 / 1024).toFixed(1)} MB`);
      console.log(`  Heap utilization:   ${((memory.usedJSHeap / memory.heapLimit) * 100).toFixed(1)}%`);
    } else {
      console.log('  Memory API not available (Chromium flag needed: --enable-precise-memory-info)');
    }
    
    // DOM complexity
    console.log(`\n--- DOM Complexity ---`);
    const domStats = await page.evaluate(() => {
      const allElements = document.querySelectorAll('*');
      const tagCounts = {};
      let maxDepth = 0;
      const totalNodes = allElements.length;
      
      allElements.forEach(el => {
        const tag = el.tagName.toLowerCase();
        tagCounts[tag] = (tagCounts[tag] || 0) + 1;
        let depth = 0, parent = el.parentElement;
        while (parent) { depth++; parent = parent.parentElement; }
        if (depth > maxDepth) maxDepth = depth;
      });
      
      return { totalNodes, maxDepth, tagCounts };
    });
    
    console.log(`  Total DOM nodes:    ${domStats.totalNodes}`);
    console.log(`  Max DOM depth:       ${domStats.maxDepth}`);
    console.log(`  Top 10 tags:`);
    const sortedTags = Object.entries(domStats.tagCounts).sort((a, b) => b[1] - a[1]);
    for (const [tag, count] of sortedTags.slice(0, 10)) {
      console.log(`    <${tag}>: ${count}`);
    }
    
    // DOM warnings
    if (domStats.totalNodes > 1500) {
      console.log(`  ⚠️  DOM nodes > 1500 — may cause sluggish rendering`);
    }
    if (domStats.maxDepth > 15) {
      console.log(`  ⚠️  DOM depth > 15 — may slow style/layout calculations`);
    }
    
    // React-specific analysis: check for unnecessary re-renders
    console.log(`\n--- Render Performance ---`);
    const renderMetrics = await page.evaluate(() => {
      // Check if React DevTools hook exists
      const hasReact = !!window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
      return {
        hasReact,
        eventListeners: typeof getEventListeners !== 'undefined' ? 'available' : 'not-in-page-context',
      };
    });
    console.log(`  React DevTools:     ${renderMetrics.hasReact ? 'detected' : 'not detected'}`);
    
    // Measure interaction performance - simulate scroll
    console.log(`\n--- Interaction Performance ---`);
    const scrollStart = Date.now();
    await page.evaluate(() => {
      const container = document.querySelector('.app-shell-content') || document.documentElement;
      for (let i = 0; i < 10; i++) {
        container.scrollTop = i * 100;
      }
      container.scrollTop = 0;
    });
    const scrollTime = Date.now() - scrollStart;
    console.log(`  10x scroll ops:     ${scrollTime}ms`);
    
    // Navigate to different routes to test lazy loading
    const routes = ['#/', '#/canvas', '#/workbench', '#/ecommerce', '#/image-workbench', '#/home'];
    console.log(`\n--- Route Navigation (Lazy Loading) ---`);
    for (const route of routes) {
      const routeStart = Date.now();
      await page.goto(`http://127.0.0.1:${PORT}/${route}`, { waitUntil: 'domcontentloaded', timeout: 15000 });
      const routeTime = Date.now() - routeStart;
      console.log(`  ${route.padEnd(30)} ${routeTime}ms`);
    }
    
    // Memory after navigation
    const memoryAfter = await page.evaluate(() => {
      if (performance.memory) {
        return {
          usedJSHeap: performance.memory.usedJSHeapSize,
          totalJSHeap: performance.memory.totalJSHeapSize,
        };
      }
      return null;
    });
    
    if (memoryAfter) {
      console.log(`\n--- Memory After Route Navigation ---`);
      console.log(`  Used JS heap:       ${(memoryAfter.usedJSHeap / 1024 / 1024).toFixed(1)} MB`);
      console.log(`  Total JS heap:      ${(memoryAfter.totalJSHeap / 1024 / 1024).toFixed(1)} MB`);
      if (memory) {
        const delta = memoryAfter.usedJSHeap - memory.usedJSHeap;
        console.log(`  Heap delta:         ${(delta > 0 ? '+' : '')}${(delta / 1024 / 1024).toFixed(1)} MB`);
      }
    }
    
    // Network summary
    console.log(`\n--- Network Summary ---`);
    console.log(`  Total requests:     ${networkResponses.length}`);
    const totalNetworkSize = networkResponses.reduce((s, r) => s + parseInt(r.size || '0'), 0);
    console.log(`  Total response:     ${(totalNetworkSize / 1024).toFixed(1)} KB`);
    const failedRequests = networkResponses.filter(r => r.status >= 400);
    if (failedRequests.length > 0) {
      console.log(`  Failed requests:    ${failedRequests.length}`);
      for (const r of failedRequests) {
        console.log(`    [${r.status}] ${r.url}`);
      }
    }
    
  } catch (err) {
    console.log(`\n  ❌ Error during runtime analysis: ${err.message}`);
  } finally {
    await browser.close();
  }
}

// ─── Main ───
console.log('╔═══════════════════════════════════════════════╗');
console.log('║   OmniAI Web Preview - Performance Analysis  ║');
console.log('╚═══════════════════════════════════════════════╝');

analyzeBundles();
await runtimeAnalysis();

console.log('\n═══════════════════════════════════════════════');
console.log('  ANALYSIS COMPLETE');
console.log('═══════════════════════════════════════════════');
