// EN: Unit tests for @goodgo/tracing — OpenTelemetry init wrapper.
// VI: Unit tests cho @goodgo/tracing — wrapper khởi tạo OpenTelemetry.
import { describe, it, expect, vi, beforeEach } from 'vitest';

// EN: Mock heavy OTel SDK to avoid network calls and real SDK startup.
// VI: Mock OTel SDK nặng để tránh network calls và khởi động SDK thực.
vi.mock('@opentelemetry/sdk-node', () => {
  const NodeSDK = vi.fn().mockImplementation(() => ({
    start: vi.fn(),
    shutdown: vi.fn().mockResolvedValue(undefined),
  }));
  return { NodeSDK };
});

vi.mock('@opentelemetry/auto-instrumentations-node', () => ({
  getNodeAutoInstrumentations: vi.fn().mockReturnValue([]),
}));

vi.mock('@opentelemetry/exporter-trace-otlp-http', () => {
  const OTLPTraceExporter = vi.fn().mockImplementation(() => ({}));
  return { OTLPTraceExporter };
});

import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
import { initTracing } from './index';

// ---------------------------------------------------------------------------
// initTracing
// ---------------------------------------------------------------------------
describe('initTracing', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('should return null when enabled=false', () => {
    const sdk = initTracing({ serviceName: 'order-service', enabled: false });
    expect(sdk).toBeNull();
    expect(NodeSDK).not.toHaveBeenCalled();
  });

  it('should create and start NodeSDK when enabled=true (default)', () => {
    const sdk = initTracing({ serviceName: 'catalog-service' });
    expect(NodeSDK).toHaveBeenCalled();
    const instance = (NodeSDK as ReturnType<typeof vi.fn>).mock.results[0].value;
    expect(instance.start).toHaveBeenCalled();
    expect(sdk).not.toBeNull();
  });

  it('should create NodeSDK when enabled is not provided', () => {
    const sdk = initTracing({ serviceName: 'wallet-service' });
    expect(sdk).not.toBeNull();
    expect(NodeSDK).toHaveBeenCalled();
  });

  it('should pass serviceName to NodeSDK constructor', () => {
    initTracing({ serviceName: 'merchant-service' });
    expect(NodeSDK).toHaveBeenCalledWith(
      expect.objectContaining({ serviceName: 'merchant-service' })
    );
  });

  it('should use default OTLP endpoint when not specified', () => {
    initTracing({ serviceName: 'inventory-service' });
    expect(OTLPTraceExporter).toHaveBeenCalledWith(
      expect.objectContaining({ url: 'http://localhost:4318/v1/traces' })
    );
  });

  it('should use custom OTLP endpoint when provided', () => {
    initTracing({
      serviceName: 'promotion-service',
      otlpEndpoint: 'http://otel-collector:4318/v1/traces',
    });
    expect(OTLPTraceExporter).toHaveBeenCalledWith(
      expect.objectContaining({ url: 'http://otel-collector:4318/v1/traces' })
    );
  });

  it('should include auto-instrumentations in NodeSDK', () => {
    initTracing({ serviceName: 'ads-service' });
    expect(getNodeAutoInstrumentations).toHaveBeenCalled();
    expect(NodeSDK).toHaveBeenCalledWith(
      expect.objectContaining({ instrumentations: expect.any(Array) })
    );
  });
});
