import { onCLS, onINP, onFCP, onLCP, onTTFB, type Metric } from 'web-vitals';

/**
 * Performance Monitoring Module
 *
 * Tracks Core Web Vitals metrics:
 * - CLS (Cumulative Layout Shift): Measures visual stability
 * - INP (Interaction to Next Paint): Measures interactivity (replaces FID in v5)
 * - FCP (First Contentful Paint): Measures perceived load speed
 * - LCP (Largest Contentful Paint): Measures loading performance
 * - TTFB (Time to First Byte): Measures server response time
 *
 * Sends metrics to analytics (Google Analytics if available)
 */

interface PerformanceMetric {
  name: string;
  value: number;
  id: string;
  delta: number;
  rating: 'good' | 'needs-improvement' | 'poor';
}

/**
 * Send metric to analytics service
 */
const sendToAnalytics = (metric: Metric) => {
  const body: PerformanceMetric = {
    name: metric.name,
    value: Math.round(metric.value),
    id: metric.id,
    delta: metric.delta,
    rating: metric.rating,
  };

  // Send to Google Analytics if available
  if (typeof window !== 'undefined' && (window as any).gtag) {
    (window as any).gtag('event', metric.name, {
      event_category: 'Web Vitals',
      event_label: metric.id,
      value: Math.round(metric.value),
      metric_id: metric.id,
      metric_value: metric.value,
      metric_delta: metric.delta,
      metric_rating: metric.rating,
      non_interaction: true,
    });
  }

  // Log to console in development
  if (process.env.NODE_ENV === 'development') {
    console.log('[Performance]', body);
  }

  // Send to custom analytics endpoint if needed
  if (process.env.NEXT_PUBLIC_ANALYTICS_ENDPOINT) {
    const analyticsEndpoint = process.env.NEXT_PUBLIC_ANALYTICS_ENDPOINT;

    // Use navigator.sendBeacon for reliable analytics even during page unload
    if (navigator.sendBeacon) {
      navigator.sendBeacon(
        analyticsEndpoint,
        JSON.stringify(body)
      );
    } else {
      // Fallback to fetch
      fetch(analyticsEndpoint, {
        method: 'POST',
        body: JSON.stringify(body),
        headers: {
          'Content-Type': 'application/json',
        },
        keepalive: true,
      }).catch((error) => {
        console.error('Failed to send analytics:', error);
      });
    }
  }
};

/**
 * Initialize performance monitoring
 * Call this function once when the app loads
 */
export const initPerformanceMonitoring = () => {
  if (typeof window === 'undefined') {
    return;
  }

  try {
    // Track Cumulative Layout Shift (CLS)
    // Good: < 0.1, Needs Improvement: < 0.25, Poor: >= 0.25
    onCLS(sendToAnalytics);

    // Track Interaction to Next Paint (INP) - replaces FID in web-vitals v5
    // Good: < 200ms, Needs Improvement: < 500ms, Poor: >= 500ms
    onINP(sendToAnalytics);

    // Track First Contentful Paint (FCP)
    // Good: < 1.8s, Needs Improvement: < 3s, Poor: >= 3s
    onFCP(sendToAnalytics);

    // Track Largest Contentful Paint (LCP)
    // Good: < 2.5s, Needs Improvement: < 4s, Poor: >= 4s
    onLCP(sendToAnalytics);

    // Track Time to First Byte (TTFB)
    // Good: < 800ms, Needs Improvement: < 1800ms, Poor: >= 1800ms
    onTTFB(sendToAnalytics);

    console.log('[Performance] Monitoring initialized');
  } catch (error) {
    console.error('[Performance] Failed to initialize monitoring:', error);
  }
};

/**
 * Report custom performance metrics
 */
export const reportCustomMetric = (name: string, value: number, metadata?: Record<string, any>) => {
  if (typeof window !== 'undefined' && (window as any).gtag) {
    (window as any).gtag('event', name, {
      event_category: 'Custom Metrics',
      value: Math.round(value),
      ...metadata,
    });
  }

  if (process.env.NODE_ENV === 'development') {
    console.log('[Performance Custom Metric]', { name, value, metadata });
  }
};

/**
 * Measure and report component render time
 */
export const measureComponentRender = (componentName: string) => {
  if (typeof window === 'undefined' || !window.performance) {
    return () => {};
  }

  const startMark = `${componentName}-render-start`;
  const endMark = `${componentName}-render-end`;
  const measureName = `${componentName}-render`;

  performance.mark(startMark);

  return () => {
    performance.mark(endMark);
    performance.measure(measureName, startMark, endMark);

    const measure = performance.getEntriesByName(measureName)[0];
    if (measure) {
      reportCustomMetric(`component_render_${componentName}`, measure.duration, {
        component: componentName,
      });
    }

    // Clean up marks and measures
    performance.clearMarks(startMark);
    performance.clearMarks(endMark);
    performance.clearMeasures(measureName);
  };
};

/**
 * Track page load time
 */
export const trackPageLoad = (pageName: string) => {
  if (typeof window === 'undefined' || !window.performance) {
    return;
  }

  // Wait for load event
  window.addEventListener('load', () => {
    setTimeout(() => {
      const navigation = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;
      if (navigation) {
        reportCustomMetric(`page_load_${pageName}`, navigation.loadEventEnd - navigation.fetchStart, {
          page: pageName,
          dom_content_loaded: navigation.domContentLoadedEventEnd - navigation.fetchStart,
          dom_interactive: navigation.domInteractive - navigation.fetchStart,
        });
      }
    }, 0);
  });
};

/**
 * Monitor long tasks (tasks that block the main thread for > 50ms)
 */
export const monitorLongTasks = () => {
  if (typeof window === 'undefined' || !(window as any).PerformanceObserver) {
    return;
  }

  try {
    const observer = new PerformanceObserver((list) => {
      for (const entry of list.getEntries()) {
        reportCustomMetric('long_task', entry.duration, {
          start_time: entry.startTime,
          duration: entry.duration,
        });
      }
    });

    observer.observe({ entryTypes: ['longtask'] });
  } catch (error) {
    console.error('[Performance] Failed to monitor long tasks:', error);
  }
};

/**
 * Track resource loading times
 */
export const trackResourceTiming = () => {
  if (typeof window === 'undefined' || !window.performance) {
    return;
  }

  const resources = performance.getEntriesByType('resource') as PerformanceResourceTiming[];

  const slowResources = resources.filter((resource) => resource.duration > 1000);

  slowResources.forEach((resource) => {
    reportCustomMetric('slow_resource', resource.duration, {
      url: resource.name,
      type: resource.initiatorType,
      size: resource.transferSize,
    });
  });
};
