import type { Metric } from 'web-vitals';

const API_BASE_URL = process.env['NEXT_PUBLIC_API_URL'] || 'http://localhost:3001/api/v1';

/**
 * Baseline targets for Core Web Vitals:
 *   LCP  < 2.5s (good), < 4.0s (needs improvement)
 *   FCP  < 1.8s (good), < 3.0s (needs improvement)
 *   CLS  < 0.1 (good), < 0.25 (needs improvement)
 *   TTFB < 800ms (good)
 *   INP  < 200ms (good), < 500ms (needs improvement)
 */
export const WEB_VITALS_THRESHOLDS = {
  LCP: { good: 2500, poor: 4000 },
  FCP: { good: 1800, poor: 3000 },
  CLS: { good: 0.1, poor: 0.25 },
  TTFB: { good: 800, poor: 1800 },
  INP: { good: 200, poor: 500 },
} as const;

type VitalName = keyof typeof WEB_VITALS_THRESHOLDS;

function getRating(name: string, value: number): 'good' | 'needs-improvement' | 'poor' {
  const thresholds = WEB_VITALS_THRESHOLDS[name as VitalName];
  if (!thresholds) return 'good';
  if (value <= thresholds.good) return 'good';
  if (value <= thresholds.poor) return 'needs-improvement';
  return 'poor';
}

interface WebVitalPayload {
  name: string;
  value: number;
  rating: string;
  delta: number;
  id: string;
  navigationType: string;
  url: string;
  timestamp: number;
}

/** Queue metrics and flush in batches to avoid per-metric requests. */
const queue: WebVitalPayload[] = [];
let flushTimer: ReturnType<typeof setTimeout> | null = null;

const FLUSH_INTERVAL_MS = 5000;
const MAX_BATCH_SIZE = 10;

function getCsrfToken(): string | undefined {
  if (typeof document === 'undefined') return undefined;
  const match = document.cookie.match(/(?:^|;\s*)XSRF-TOKEN=([^;]*)/);
  return match?.[1] ? decodeURIComponent(match[1]) : undefined;
}

function flushQueue(): void {
  if (queue.length === 0) return;

  const batch = queue.splice(0, MAX_BATCH_SIZE);
  const body = JSON.stringify({ metrics: batch });

  // Use sendBeacon for reliability during page unload; fall back to fetch
  if (typeof navigator !== 'undefined' && navigator.sendBeacon) {
    const blob = new Blob([body], { type: 'application/json' });
    const sent = navigator.sendBeacon(`${API_BASE_URL}/web-vitals`, blob);
    if (!sent) {
      sendViaFetch(body);
    }
  } else {
    sendViaFetch(body);
  }
}

function sendViaFetch(body: string): void {
  const headers: Record<string, string> = { 'Content-Type': 'application/json' };
  const csrfToken = getCsrfToken();
  if (csrfToken) headers['X-CSRF-Token'] = csrfToken;

  fetch(`${API_BASE_URL}/web-vitals`, {
    method: 'POST',
    headers,
    credentials: 'include',
    body,
    keepalive: true,
  }).catch(() => {
    // Silently drop — metrics are best-effort
  });
}

function enqueue(payload: WebVitalPayload): void {
  queue.push(payload);

  if (queue.length >= MAX_BATCH_SIZE) {
    if (flushTimer) clearTimeout(flushTimer);
    flushTimer = null;
    flushQueue();
    return;
  }

  if (!flushTimer) {
    flushTimer = setTimeout(() => {
      flushTimer = null;
      flushQueue();
    }, FLUSH_INTERVAL_MS);
  }
}

/** Report a single web-vitals Metric to the backend. */
export function reportWebVital(metric: Metric): void {
  const payload: WebVitalPayload = {
    name: metric.name,
    value: metric.value,
    rating: metric.rating ?? getRating(metric.name, metric.value),
    delta: metric.delta,
    id: metric.id,
    navigationType: metric.navigationType ?? 'unknown',
    url: typeof location !== 'undefined' ? location.pathname : '',
    timestamp: Date.now(),
  };

  enqueue(payload);
}

/** Flush any remaining metrics (call on page hide / unload). */
export function flushWebVitals(): void {
  if (flushTimer) {
    clearTimeout(flushTimer);
    flushTimer = null;
  }
  flushQueue();
}
