import { test, expect } from '@playwright/test';
import { TEST_CONFIG } from './utils/test-helpers';

/**
 * Performance Tests
 * 
 * These tests measure page load times, render performance, and Core Web Vitals.
 * Performance metrics are captured using Playwright's performance API and
 * browser Performance Timing API.
 * 
 * To run only performance tests:
 * - Run: npx playwright test performance
 * 
 * Performance thresholds:
 * - Page load time: < 3 seconds
 * - First Contentful Paint (FCP): < 1.8 seconds
 * - Largest Contentful Paint (LCP): < 2.5 seconds
 * - Time to Interactive (TTI): < 3.8 seconds
 * - Total Blocking Time (TBT): < 300ms
 */

interface PerformanceMetrics {
  loadTime: number;
  domContentLoaded: number;
  firstPaint: number;
  firstContentfulPaint: number;
  largestContentfulPaint: number;
  timeToInteractive: number;
  totalBlockingTime: number;
  cumulativeLayoutShift: number;
  firstInputDelay: number;
  networkRequests: number;
  jsHeapSizeUsed: number;
}

/**
 * Capture performance metrics from the browser
 */
async function capturePerformanceMetrics(page: any): Promise<PerformanceMetrics> {
  return await page.evaluate(() => {
    const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;
    const paint = performance.getEntriesByType('paint');
    const measure = performance.getEntriesByType('measure');
    
    // Calculate load time
    const loadTime = navigation.loadEventEnd - navigation.fetchStart;
    const domContentLoaded = navigation.domContentLoadedEventEnd - navigation.fetchStart;
    
    // Get paint metrics
    const firstPaint = paint.find((entry) => entry.name === 'first-paint')?.startTime || 0;
    const firstContentfulPaint = paint.find((entry) => entry.name === 'first-contentful-paint')?.startTime || 0;
    
    // Get LCP (Largest Contentful Paint) - approximate using load event
    const largestContentfulPaint = navigation.loadEventEnd - navigation.fetchStart;
    
    // Calculate TTI (Time to Interactive) - approximate
    const timeToInteractive = navigation.domInteractive - navigation.fetchStart;
    
    // Calculate TBT (Total Blocking Time) - approximate
    // This is a simplified calculation
    const totalBlockingTime = Math.max(0, navigation.domInteractive - navigation.domContentLoadedEventEnd);
    
    // Get CLS (Cumulative Layout Shift) - requires PerformanceObserver
    let cumulativeLayoutShift = 0;
    if ('PerformanceObserver' in window) {
      try {
        const clsEntries: any[] = [];
        const observer = new PerformanceObserver((list) => {
          for (const entry of list.getEntries()) {
            if (!(entry as any).hadRecentInput) {
              clsEntries.push(entry);
            }
          }
        });
        observer.observe({ type: 'layout-shift', buffered: true });
        cumulativeLayoutShift = clsEntries.reduce((sum, entry: any) => sum + entry.value, 0);
      } catch (e) {
        // CLS not supported
      }
    }
    
    // Get FID (First Input Delay) - approximate
    const firstInputDelay = 0; // Would need PerformanceObserver for real measurement
    
    // Count network requests
    const networkRequests = performance.getEntriesByType('resource').length;
    
    // Get memory usage (if available)
    const memory = (performance as any).memory;
    const jsHeapSizeUsed = memory ? memory.usedJSHeapSize : 0;
    
    return {
      loadTime,
      domContentLoaded,
      firstPaint,
      firstContentfulPaint,
      largestContentfulPaint,
      timeToInteractive,
      totalBlockingTime,
      cumulativeLayoutShift,
      firstInputDelay,
      networkRequests,
      jsHeapSizeUsed,
    };
  });
}

/**
 * Wait for page to be fully loaded and stable
 */
async function waitForPageStable(page: any, timeout = 10000) {
  await page.waitForLoadState('networkidle', { timeout });
  await page.waitForLoadState('domcontentloaded');
  // Wait a bit more for any async operations
  await page.waitForTimeout(1000);
}

test.describe('Performance Tests', () => {
  // Use authenticated state for most tests
  test.use({ storageState: 'e2e/.auth/user.json' });

  test.describe('Page Load Performance', () => {
    test('dashboard page load time should be acceptable', async ({ page }) => {
      const startTime = Date.now();
      
      await page.goto(`${TEST_CONFIG.FRONTEND_URL}/dashboard`);
      await waitForPageStable(page);
      
      const endTime = Date.now();
      const loadTime = endTime - startTime;
      
      const metrics = await capturePerformanceMetrics(page);
      
      // Log metrics for debugging
      console.log('Dashboard Performance Metrics:', {
        loadTime: `${loadTime}ms`,
        domContentLoaded: `${metrics.domContentLoaded.toFixed(2)}ms`,
        firstContentfulPaint: `${metrics.firstContentfulPaint.toFixed(2)}ms`,
        largestContentfulPaint: `${metrics.largestContentfulPaint.toFixed(2)}ms`,
        timeToInteractive: `${metrics.timeToInteractive.toFixed(2)}ms`,
        networkRequests: metrics.networkRequests,
      });
      
      // Assertions - thresholds based on Core Web Vitals
      expect(loadTime).toBeLessThan(5000); // 5 seconds max
      expect(metrics.domContentLoaded).toBeLessThan(3000); // 3 seconds
      expect(metrics.firstContentfulPaint).toBeLessThan(1800); // 1.8 seconds (Good FCP)
      expect(metrics.largestContentfulPaint).toBeLessThan(2500); // 2.5 seconds (Good LCP)
    });

    test('login page load time should be fast', async ({ page }) => {
      // Use unauthenticated state for login page
      await page.context().clearCookies();
      
      const startTime = Date.now();
      
      await page.goto(`${TEST_CONFIG.FRONTEND_URL}/login`);
      await waitForPageStable(page);
      
      const endTime = Date.now();
      const loadTime = endTime - startTime;
      
      const metrics = await capturePerformanceMetrics(page);
      
      console.log('Login Page Performance Metrics:', {
        loadTime: `${loadTime}ms`,
        firstContentfulPaint: `${metrics.firstContentfulPaint.toFixed(2)}ms`,
        networkRequests: metrics.networkRequests,
      });
      
      // Login page should be very fast (no data loading)
      expect(loadTime).toBeLessThan(2000); // 2 seconds max
      expect(metrics.firstContentfulPaint).toBeLessThan(1000); // 1 second
    });

    test('profile page load time should be acceptable', async ({ page }) => {
      const startTime = Date.now();
      
      await page.goto(`${TEST_CONFIG.FRONTEND_URL}/profile`);
      await waitForPageStable(page);
      
      const endTime = Date.now();
      const loadTime = endTime - startTime;
      
      const metrics = await capturePerformanceMetrics(page);
      
      expect(loadTime).toBeLessThan(5000);
      expect(metrics.firstContentfulPaint).toBeLessThan(1800);
    });

    test('tracks page load time should be acceptable', async ({ page }) => {
      const startTime = Date.now();
      
      await page.goto(`${TEST_CONFIG.FRONTEND_URL}/tracks`);
      await waitForPageStable(page);
      
      const endTime = Date.now();
      const loadTime = endTime - startTime;
      
      const metrics = await capturePerformanceMetrics(page);
      
      expect(loadTime).toBeLessThan(5000);
      expect(metrics.firstContentfulPaint).toBeLessThan(1800);
    });

    test('playlists page load time should be acceptable', async ({ page }) => {
      const startTime = Date.now();
      
      await page.goto(`${TEST_CONFIG.FRONTEND_URL}/playlists`);
      await waitForPageStable(page);
      
      const endTime = Date.now();
      const loadTime = endTime - startTime;
      
      const metrics = await capturePerformanceMetrics(page);
      
      expect(loadTime).toBeLessThan(5000);
      expect(metrics.firstContentfulPaint).toBeLessThan(1800);
    });
  });

  test.describe('Render Performance', () => {
    test('dashboard should render main content quickly', async ({ page }) => {
      await page.goto(`${TEST_CONFIG.FRONTEND_URL}/dashboard`);
      
      // Measure time to render main content
      const renderStart = Date.now();
      await page.waitForSelector('main, [role="main"]', { timeout: 10000 });
      const renderEnd = Date.now();
      const renderTime = renderEnd - renderStart;
      
      console.log(`Dashboard main content render time: ${renderTime}ms`);
      
      expect(renderTime).toBeLessThan(2000); // Should render in under 2 seconds
    });

    test('navigation should be responsive', async ({ page }) => {
      await page.goto(`${TEST_CONFIG.FRONTEND_URL}/dashboard`);
      await waitForPageStable(page);
      
      // Measure navigation time
      const navStart = Date.now();
      await page.click('a[href="/profile"]', { timeout: 5000 });
      await page.waitForURL('**/profile', { timeout: 5000 });
      await waitForPageStable(page);
      const navEnd = Date.now();
      const navTime = navEnd - navStart;
      
      console.log(`Navigation time (dashboard -> profile): ${navTime}ms`);
      
      expect(navTime).toBeLessThan(3000); // Navigation should be fast
    });
  });

  test.describe('Network Performance', () => {
    test('should minimize network requests on initial load', async ({ page }) => {
      await page.goto(`${TEST_CONFIG.FRONTEND_URL}/dashboard`);
      await waitForPageStable(page);
      
      const metrics = await capturePerformanceMetrics(page);
      
      console.log(`Total network requests: ${metrics.networkRequests}`);
      
      // Should not have excessive network requests
      // This threshold may need adjustment based on actual usage
      expect(metrics.networkRequests).toBeLessThan(50);
    });

    test('API requests should complete quickly', async ({ page }) => {
      const requestTimes: number[] = [];
      
      // Track API request times
      page.on('response', (response: any) => {
        const url = response.url();
        if (url.includes('/api/')) {
          const timing = response.timing();
          if (timing) {
            const requestTime = timing.responseEnd - timing.requestStart;
            requestTimes.push(requestTime);
          }
        }
      });
      
      await page.goto(`${TEST_CONFIG.FRONTEND_URL}/dashboard`);
      await waitForPageStable(page);
      
      if (requestTimes.length > 0) {
        const avgRequestTime = requestTimes.reduce((a, b) => a + b, 0) / requestTimes.length;
        const maxRequestTime = Math.max(...requestTimes);
        
        console.log(`Average API request time: ${avgRequestTime.toFixed(2)}ms`);
        console.log(`Max API request time: ${maxRequestTime.toFixed(2)}ms`);
        
        // API requests should complete reasonably quickly
        expect(avgRequestTime).toBeLessThan(1000); // Average under 1 second
        expect(maxRequestTime).toBeLessThan(3000); // Max under 3 seconds
      }
    });
  });

  test.describe('Memory Performance', () => {
    test('should not have excessive memory usage', async ({ page }) => {
      await page.goto(`${TEST_CONFIG.FRONTEND_URL}/dashboard`);
      await waitForPageStable(page);
      
      const metrics = await capturePerformanceMetrics(page);
      
      if (metrics.jsHeapSizeUsed > 0) {
        const heapSizeMB = metrics.jsHeapSizeUsed / (1024 * 1024);
        console.log(`JS Heap Size Used: ${heapSizeMB.toFixed(2)}MB`);
        
        // Should not use excessive memory (threshold: 100MB)
        expect(heapSizeMB).toBeLessThan(100);
      }
    });
  });

  test.describe('Core Web Vitals', () => {
    test('should meet Core Web Vitals thresholds', async ({ page }) => {
      await page.goto(`${TEST_CONFIG.FRONTEND_URL}/dashboard`);
      await waitForPageStable(page);
      
      const metrics = await capturePerformanceMetrics(page);
      
      // Core Web Vitals thresholds (Good)
      const coreWebVitals = {
        LCP: metrics.largestContentfulPaint, // Should be < 2.5s
        FID: metrics.firstInputDelay, // Should be < 100ms (not measured here)
        CLS: metrics.cumulativeLayoutShift, // Should be < 0.1
        FCP: metrics.firstContentfulPaint, // Should be < 1.8s
        TBT: metrics.totalBlockingTime, // Should be < 300ms
      };
      
      console.log('Core Web Vitals:', {
        LCP: `${coreWebVitals.LCP.toFixed(2)}ms (target: < 2500ms)`,
        FCP: `${coreWebVitals.FCP.toFixed(2)}ms (target: < 1800ms)`,
        TBT: `${coreWebVitals.TBT.toFixed(2)}ms (target: < 300ms)`,
        CLS: `${coreWebVitals.CLS.toFixed(4)} (target: < 0.1)`,
      });
      
      // Assert Core Web Vitals thresholds
      expect(coreWebVitals.LCP).toBeLessThan(2500);
      expect(coreWebVitals.FCP).toBeLessThan(1800);
      expect(coreWebVitals.TBT).toBeLessThan(300);
      expect(coreWebVitals.CLS).toBeLessThan(0.1);
    });
  });
});

