import { describe, test, expect, vi, beforeEach, afterEach } from "vitest";
import { NodeSDKConfig } from "../index";
import { instrumentNode } from "../index";
import * as buildNodeInstrumentationModule from "../lib/instrumentation.node";
import { metrics } from "@opentelemetry/sdk-node";

describe("instrumentNode", () => {
  beforeEach(() => {
    // @ts-ignore Avoid actually running exporters at any time in tests (overriding private method)
    vi.spyOn(
      metrics.PeriodicExportingMetricReader.prototype,
      "_doRun",
    ).mockImplementation(vi.fn());
  });

  afterEach(() => {
    vi.restoreAllMocks();
  });

  test("should call buildNodeInstrumentation with the provided config", async () => {
    const instrumentationMock = vi
      .spyOn(buildNodeInstrumentationModule, "default")
      .mockImplementation(vi.fn());

    const config: NodeSDKConfig = {
      serviceName: "custom-service",
      collectorUrl: "http://custom-collector.com",
      protocol: "grpc",
      resourceAttributes: {
        "team.infra.cluster": "dev-01",
        "team.infra.pod": "01",
        "team.service.type": "fastify",
      },
      spanAttributes: {
        "signal.namespace": "example",
        "signal.number": () => "callback",
      },
    };

    await instrumentNode(config);

    expect(instrumentationMock).toHaveBeenCalledWith(config);
  });

  test("should not throw when called without arguments", async () => {
    await expect(instrumentNode()).resolves.not.toThrow();
  });

  test("should invoke instrumentation shutdown on SIGTERM", async () => {
    const config: NodeSDKConfig = {
      serviceName: "custom-service",
      collectorUrl: "http://custom-collector.com",
      protocol: "grpc",
      resourceAttributes: {
        "team.infra.cluster": "dev-01",
        "team.infra.pod": "01",
        "team.service.type": "fastify",
      },
      spanAttributes: {
        "signal.namespace": "example",
        "signal.number": () => "callback",
      },
    };

    const sdk = await instrumentNode(config);
    const shutdownMock = vi.spyOn(sdk, "shutdown");
    process.emit("SIGTERM");
    expect(shutdownMock).toHaveBeenCalled();
  });
});
