/**
 * Frontend metrics collection for BanGUI.
 *
 * Collects:
 * - Web Vitals (FCP, LCP, CLS, INP, TTFB)
 * - API request latencies and error rates
 * - Page load timings
 *
 * Metrics are sent to the backend `/metrics/events` endpoint.
 */

import type { CLSMetric, FCPMetric, INPMetric, LCPMetric, TTFBMetric } from 'web-vitals';
import { onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals';

export interface WebVitalsMetric {
  name: string;
  value: number;
  rating?: 'good' | 'needs-improvement' | 'poor';
  delta?: number;
  id: string;
  navigationType?: string;
}

export interface ApiMetric {
  method: string;
  endpoint: string;
  statusCode: number;
  durationMs: number;
  timestamp: number;
}

interface MetricsCollector {
  recordWebVital(metric: WebVitalsMetric): void;
  recordApiCall(metric: ApiMetric): void;
  getCollectedMetrics(): { vitals: WebVitalsMetric[]; apiCalls: ApiMetric[] };
  reset(): void;
}

class MetricsCollectorImpl implements MetricsCollector {
  private vitals: WebVitalsMetric[] = [];
  private apiCalls: ApiMetric[] = [];
  private readonly maxMetrics = 100;

  recordWebVital(metric: WebVitalsMetric): void {
    if (this.vitals.length >= this.maxMetrics) {
      this.vitals.shift();
    }
    this.vitals.push(metric);
  }

  recordApiCall(metric: ApiMetric): void {
    if (this.apiCalls.length >= this.maxMetrics) {
      this.apiCalls.shift();
    }
    this.apiCalls.push(metric);
  }

  getCollectedMetrics() {
    return { vitals: this.vitals, apiCalls: this.apiCalls };
  }

  reset(): void {
    this.vitals = [];
    this.apiCalls = [];
  }
}

const collector = new MetricsCollectorImpl();

/**
 * Initialize web vitals tracking.
 * Should be called once on application startup.
 */
export function initializeWebVitals(): void {
  // Track Cumulative Layout Shift
  onCLS((metric: CLSMetric) => {
    collector.recordWebVital({
      name: 'CLS',
      value: metric.value,
      rating: metric.rating,
      delta: metric.delta,
      id: metric.id,
      navigationType: metric.navigationType,
    });
  });

  // Track First Contentful Paint
  onFCP((metric: FCPMetric) => {
    collector.recordWebVital({
      name: 'FCP',
      value: metric.value,
      rating: metric.rating,
      delta: metric.delta,
      id: metric.id,
      navigationType: metric.navigationType,
    });
  });

  // Track Interaction to Next Paint (replaces First Input Delay)
  onINP((metric: INPMetric) => {
    collector.recordWebVital({
      name: 'INP',
      value: metric.value,
      rating: metric.rating,
      delta: metric.delta,
      id: metric.id,
      navigationType: metric.navigationType,
    });
  });

  // Track Largest Contentful Paint
  onLCP((metric: LCPMetric) => {
    collector.recordWebVital({
      name: 'LCP',
      value: metric.value,
      rating: metric.rating,
      delta: metric.delta,
      id: metric.id,
      navigationType: metric.navigationType,
    });
  });

  // Track Time to First Byte
  onTTFB((metric: TTFBMetric) => {
    collector.recordWebVital({
      name: 'TTFB',
      value: metric.value,
      rating: metric.rating,
      delta: metric.delta,
      id: metric.id,
      navigationType: metric.navigationType,
    });
  });
}

/**
 * Record an API call metric.
 *
 * @param method HTTP method (GET, POST, etc.)
 * @param endpoint API endpoint path
 * @param statusCode HTTP response status code
 * @param durationMs Request duration in milliseconds
 */
export function recordApiCall(
  method: string,
  endpoint: string,
  statusCode: number,
  durationMs: number,
): void {
  collector.recordApiCall({
    method,
    endpoint,
    statusCode,
    durationMs,
    timestamp: Date.now(),
  });
}

/**
 * Get all collected metrics.
 *
 * @returns Object containing collected web vitals and API metrics
 */
export function getCollectedMetrics() {
  return collector.getCollectedMetrics();
}

/**
 * Reset collected metrics.
 * Useful for testing or clearing metrics between sessions.
 */
export function resetMetrics(): void {
  collector.reset();
}

/**
 * Export metrics to backend (optional - for future integration).
 * Can be called periodically to send metrics to monitoring system.
 *
 * @returns Promise that resolves when metrics are sent
 */
export async function exportMetrics(): Promise<void> {
  const metrics = getCollectedMetrics();

  if (metrics.vitals.length === 0 && metrics.apiCalls.length === 0) {
    return;
  }

  try {
    await fetch('/api/metrics/events', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(metrics),
    });
  } catch (error) {
    // Fail silently - metrics export should not break the app
    console.debug('Failed to export metrics', error);
  }
}
