import { describe, expect, it, vi, beforeEach, afterEach } from "vitest";
import { metrics, trace } from "@opentelemetry/api";
import {
  InMemoryMetricExporter,
  AggregationTemporality,
  PeriodicExportingMetricReader,
} from "@opentelemetry/sdk-metrics";

describe("otel", () => {
  beforeEach(() => {
    // Reset global providers and module cache between tests
    metrics.disable();
    trace.disable();
    vi.resetModules();
  });

  afterEach(() => {
    metrics.disable();
    trace.disable();
    vi.restoreAllMocks();
  });

  it("initServerOtel registers a MeterProvider and TracerProvider", async () => {
    const { initServerOtel, getMeter, getTracer } = await import("./otel.js");

    initServerOtel({
      OTEL_EXPORTER_OTLP_ENDPOINT: "http://localhost:4318",
      OTEL_SERVICE_NAME: "flights-test",
      NODE_ENV: "test",
    } as unknown as Parameters<typeof initServerOtel>[0]);

    const meter = getMeter("test");
    const tracer = getTracer("test");

    expect(meter).toBeDefined();
    expect(tracer).toBeDefined();
  });

  it("counter incremented via proxy meter is observable by test reader", async () => {
    const exporter = new InMemoryMetricExporter(AggregationTemporality.CUMULATIVE);
    const reader = new PeriodicExportingMetricReader({
      exporter,
      exportIntervalMillis: 100,
    });

    const { initServerOtelWithReader } = await import("./otel.js");
    initServerOtelWithReader({
      OTEL_EXPORTER_OTLP_ENDPOINT: "http://localhost:4318",
      OTEL_SERVICE_NAME: "flights-test",
      NODE_ENV: "test",
    } as unknown as Parameters<typeof initServerOtelWithReader>[0], reader);

    const counter = metrics.getMeter("flights").createCounter("test.counter");
    counter.add(1, { route: "/smoke" });

    // Force a collection cycle
    await reader.forceFlush();

    const exported = exporter.getMetrics();
    expect(exported.length).toBeGreaterThan(0);

    const testMetric = exported
      .flatMap((rm) => rm.scopeMetrics)
      .flatMap((sm) => sm.metrics)
      .find((m) => m.descriptor.name === "test.counter");

    expect(testMetric).toBeDefined();

    await reader.shutdown();
  });

  it("getMeter returns a meter from @opentelemetry/api", async () => {
    const { getMeter } = await import("./otel.js");
    const meter = getMeter("my-component");
    expect(meter).toBeDefined();
    expect(typeof meter.createCounter).toBe("function");
    expect(typeof meter.createHistogram).toBe("function");
  });

  it("getTracer returns a tracer from @opentelemetry/api", async () => {
    const { getTracer } = await import("./otel.js");
    const tracer = getTracer("my-component");
    expect(tracer).toBeDefined();
    expect(typeof tracer.startSpan).toBe("function");
  });
});
