interface RumEvent {
  kind: "navigation" | "web_vital" | "api" | "long_task";
  metric: string;
  route?: string;
  valueMs?: number;
  value?: number;
  method?: string;
  status?: number;
  statusClass?: string;
  outcome?: string;
}

interface ApiTimingInput {
  route: string;
  method?: string;
  status?: number;
  startedAt: number;
  outcome: string;
}

const SCHEMA_VERSION = "hwlab-web-performance-v1";
const FLUSH_INTERVAL_MS = 4000;
const MAX_QUEUE = 80;
const queue: RumEvent[] = [];
let installed = false;
let flushTimer: number | null = null;

export function installWebRum(): void {
  if (installed || typeof window === "undefined") return;
  installed = true;
  window.addEventListener("load", () => window.setTimeout(recordNavigationTiming, 0), { once: true });
  window.addEventListener("visibilitychange", () => {
    if (document.visibilityState === "hidden") flushRum(true);
  });
  installPerformanceObservers();
}

export function recordApiTiming(input: ApiTimingInput): void {
  if (typeof window === "undefined") return;
  if (isWorkbenchPageRoute()) return;
  const valueMs = Math.max(0, Date.now() - input.startedAt);
  enqueue({
    kind: "api",
    metric: "api_request",
    route: input.route,
    method: (input.method || "GET").toUpperCase(),
    status: input.status ?? 0,
    statusClass: statusClass(input.status),
    outcome: input.outcome,
    valueMs
  });
}

function installPerformanceObservers(): void {
  const Observer = window.PerformanceObserver;
  if (!Observer) return;
  observe("largest-contentful-paint", (entry) => enqueue({ kind: "web_vital", metric: "lcp", route: pageRoute(), valueMs: entry.startTime }));
  observe("first-input", (entry) => {
    const firstInput = entry as PerformanceEventTiming;
    enqueue({ kind: "web_vital", metric: "fid", route: pageRoute(), valueMs: Math.max(0, firstInput.processingStart - firstInput.startTime) });
  });
  observe("layout-shift", (entry) => {
    const shift = entry as PerformanceEntry & { value?: number; hadRecentInput?: boolean };
    if (shift.hadRecentInput) return;
    enqueue({ kind: "web_vital", metric: "cls", route: pageRoute(), value: Number(shift.value) || 0 });
  });
  observe("longtask", (entry) => enqueue({ kind: "long_task", metric: "long_task", route: pageRoute(), valueMs: entry.duration }));
}

function observe(type: string, onEntry: (entry: PerformanceEntry) => void): void {
  try {
    const observer = new PerformanceObserver((list) => {
      for (const entry of list.getEntries()) onEntry(entry);
    });
    observer.observe({ type, buffered: true });
  } catch {
    // Older Chromium builds may not support every Web Vital entry type.
  }
}

function recordNavigationTiming(): void {
  const navigation = performance.getEntriesByType("navigation")[0] as PerformanceNavigationTiming | undefined;
  if (!navigation) return;
  const route = pageRoute();
  const start = navigation.startTime || 0;
  enqueue({ kind: "navigation", metric: "navigation_ttfb", route, valueMs: Math.max(0, navigation.responseStart - start) });
  enqueue({ kind: "navigation", metric: "navigation_dom_content_loaded", route, valueMs: Math.max(0, navigation.domContentLoadedEventEnd - start) });
  enqueue({ kind: "navigation", metric: "navigation_load", route, valueMs: Math.max(0, navigation.loadEventEnd - start) });
}

function enqueue(event: RumEvent): void {
  if (!Number.isFinite(event.valueMs ?? event.value ?? NaN)) return;
  queue.push(event);
  if (queue.length > MAX_QUEUE) queue.splice(0, queue.length - MAX_QUEUE);
  scheduleFlush();
}

function scheduleFlush(): void {
  if (flushTimer !== null) return;
  flushTimer = window.setTimeout(() => flushRum(false), FLUSH_INTERVAL_MS);
}

function flushRum(useBeacon: boolean): void {
  if (flushTimer !== null) {
    window.clearTimeout(flushTimer);
    flushTimer = null;
  }
  if (!queue.length) return;
  const events = queue.splice(0, queue.length);
  const body = JSON.stringify({ schemaVersion: SCHEMA_VERSION, serviceId: "hwlab-cloud-web", page: pageRoute(), events });
  if (useBeacon && navigator.sendBeacon) {
    navigator.sendBeacon("/v1/web-performance", new Blob([body], { type: "application/json" }));
    return;
  }
  void fetch("/v1/web-performance", { method: "POST", headers: { "content-type": "application/json" }, body, credentials: "same-origin", keepalive: true }).catch(() => undefined);
}

function pageRoute(): string {
  return `${window.location.pathname}${window.location.hash || ""}` || "/";
}

function isWorkbenchPageRoute(): boolean {
  const pathname = window.location.pathname || "";
  return pathname.startsWith("/workbench") || pathname.startsWith("/workspace");
}

function statusClass(status?: number): string {
  if (!status || !Number.isFinite(status)) return "network";
  return `${Math.floor(status / 100)}xx`;
}
