// packages/core-shared/src/instrumentation/di/bind-otel-instrumentation.test.ts
import "reflect-metadata";
import { describe, it, expect, vi, beforeEach } from "vitest";

vi.mock("@sentry/nextjs", () => ({
  init: vi.fn(),
  captureException: vi.fn(),
  captureMessage: vi.fn(),
  addBreadcrumb: vi.fn(),
  setUser: vi.fn(),
}));

import { Container } from "inversify";
import { bindOtelInstrumentation } from "@/instrumentation/di/bind-otel-instrumentation";
import { INSTRUMENTATION_SYMBOLS } from "@/instrumentation/symbols";
import { OtelTracer } from "@/instrumentation/otel/otel-tracer";
import { OtelLogger } from "@/instrumentation/otel/otel-logger";

// NOTE: initOtelServerNode is intentionally NOT called by bindOtelInstrumentation.
// The SDK is initialized by each app's instrumentation.ts register() hook so PII
// scrub processors are active before the first request (C1 fix). There is therefore
// no initOtelServerNode mock or call-count assertion here.

describe("bindOtelInstrumentation", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("binds OtelTracer + OtelLogger to the container", () => {
    const c = new Container();
    bindOtelInstrumentation(c, { dsn: "https://x@y/1", app: "web-next" });
    expect(c.get(INSTRUMENTATION_SYMBOLS.TRACER)).toBeInstanceOf(OtelTracer);
    expect(c.get(INSTRUMENTATION_SYMBOLS.LOGGER)).toBeInstanceOf(OtelLogger);
  });

  it("returns the tracer + logger instances", () => {
    const c = new Container();
    const { tracer, logger } = bindOtelInstrumentation(c, {
      dsn: "https://x@y/1",
      app: "web-next",
    });
    expect(tracer).toBeInstanceOf(OtelTracer);
    expect(logger).toBeInstanceOf(OtelLogger);
  });

  it("rebinds when called a second time (idempotent container state)", () => {
    const c = new Container();
    bindOtelInstrumentation(c, { dsn: "https://x@y/1", app: "web-next" });
    // Second call should not throw even if TRACER is already bound.
    expect(() =>
      bindOtelInstrumentation(c, { dsn: "https://x@y/2", app: "cms" }),
    ).not.toThrow();
    expect(c.get(INSTRUMENTATION_SYMBOLS.TRACER)).toBeInstanceOf(OtelTracer);
  });
});
