import { metrics, trace } from "@opentelemetry/api";
import type { Meter, Tracer } from "@opentelemetry/api";
import { NodeSDK } from "@opentelemetry/sdk-node";
import { MeterProvider, PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
import type { MetricReader } from "@opentelemetry/sdk-metrics";
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import type { Env } from "@/env";

let initialized = false;

/**
 * Initialize OpenTelemetry for the server (Node) process.
 * Called once per process at startup.
 */
export function initServerOtel(env: Env): void {
  if (initialized) return;

  const endpoint = env.OTEL_EXPORTER_OTLP_ENDPOINT;
  const serviceName = (env as unknown as Record<string, string>).OTEL_SERVICE_NAME ?? "flights-web";

  const metricReader = new PeriodicExportingMetricReader({
    exporter: new OTLPMetricExporter({ url: `${endpoint}/v1/metrics` }),
    exportIntervalMillis: 15_000,
  });

  const sdk = new NodeSDK({
    serviceName,
    traceExporter: new OTLPTraceExporter({ url: `${endpoint}/v1/traces` }),
    metricReader,
  });

  sdk.start();
  initialized = true;
}

/**
 * Test-only variant that accepts a custom MetricReader for in-memory assertions.
 */
export function initServerOtelWithReader(env: Env, reader: MetricReader): void {
  if (initialized) return;

  const meterProvider = new MeterProvider({
    readers: [reader],
  });

  metrics.setGlobalMeterProvider(meterProvider);
  initialized = true;
}

/**
 * Initialize OpenTelemetry for the browser.
 * Called once per tab via useEffect in the root layout.
 * Browser-side uses web-vitals to report CWV as histograms.
 */
export function initBrowserOtel(env: Env): void {
  if (initialized) return;

  const endpoint = env.OTEL_EXPORTER_OTLP_ENDPOINT;
  if (!endpoint) return;

  const meterProvider = new MeterProvider({
    readers: [
      new PeriodicExportingMetricReader({
        exporter: new OTLPMetricExporter({ url: `${endpoint}/v1/metrics` }),
        exportIntervalMillis: 30_000,
      }),
    ],
  });

  metrics.setGlobalMeterProvider(meterProvider);

  // Report web-vitals as OTel histograms
  const cwvMeter = meterProvider.getMeter("web-vitals");
  void import("web-vitals").then(({ onCLS, onINP, onLCP, onFCP, onTTFB }) => {
    const cls = cwvMeter.createHistogram("web_vitals.cls");
    const inp = cwvMeter.createHistogram("web_vitals.inp");
    const lcp = cwvMeter.createHistogram("web_vitals.lcp");
    const fcp = cwvMeter.createHistogram("web_vitals.fcp");
    const ttfb = cwvMeter.createHistogram("web_vitals.ttfb");

    onCLS((m: { value: number }) => cls.record(m.value));
    onINP((m: { value: number }) => inp.record(m.value));
    onLCP((m: { value: number }) => lcp.record(m.value));
    onFCP((m: { value: number }) => fcp.record(m.value));
    onTTFB((m: { value: number }) => ttfb.record(m.value));
  });

  initialized = true;
}

/** Returns a named Meter from the global MeterProvider. */
export function getMeter(name: string): Meter {
  return metrics.getMeter(name);
}

/** Returns a named Tracer from the global TracerProvider. */
export function getTracer(name: string): Tracer {
  return trace.getTracer(name);
}
