Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });

const instrumentationUndici = require('@opentelemetry/instrumentation-undici');
const core = require('@sentry/core');
const nodeCore = require('@sentry/node-core');

const INTEGRATION_NAME = 'NodeFetch';

const instrumentOtelNodeFetch = nodeCore.generateInstrumentOnce(
  INTEGRATION_NAME,
  instrumentationUndici.UndiciInstrumentation,
  (options) => {
    return getConfigWithDefaults(options);
  },
);

const instrumentSentryNodeFetch = nodeCore.generateInstrumentOnce(
  `${INTEGRATION_NAME}.sentry`,
  nodeCore.SentryNodeFetchInstrumentation,
  (options) => {
    return options;
  },
);

const _nativeNodeFetchIntegration = ((options = {}) => {
  return {
    name: 'NodeFetch',
    setupOnce() {
      const instrumentSpans = _shouldInstrumentSpans(options, core.getClient()?.getOptions());

      // This is the "regular" OTEL instrumentation that emits spans
      if (instrumentSpans) {
        instrumentOtelNodeFetch(options);
      }

      // This is the Sentry-specific instrumentation that creates breadcrumbs & propagates traces
      // This must be registered after the OTEL one, to ensure that the core trace propagation logic takes presedence
      // Otherwise, the sentry-trace header may be set multiple times
      instrumentSentryNodeFetch(options);
    },
  };
}) ;

const nativeNodeFetchIntegration = core.defineIntegration(_nativeNodeFetchIntegration);

// Matching the behavior of the base instrumentation
function getAbsoluteUrl(origin, path = '/') {
  const url = `${origin}`;

  if (url.endsWith('/') && path.startsWith('/')) {
    return `${url}${path.slice(1)}`;
  }

  if (!url.endsWith('/') && !path.startsWith('/')) {
    return `${url}/${path.slice(1)}`;
  }

  return `${url}${path}`;
}

function _shouldInstrumentSpans(options, clientOptions = {}) {
  // If `spans` is passed in, it takes precedence
  // Else, we by default emit spans, unless `skipOpenTelemetrySetup` is set to `true` or spans are not enabled
  return typeof options.spans === 'boolean'
    ? options.spans
    : !clientOptions.skipOpenTelemetrySetup && core.hasSpansEnabled(clientOptions);
}

function getConfigWithDefaults(options = {}) {
  const instrumentationConfig = {
    requireParentforSpans: false,
    ignoreRequestHook: request => {
      const url = getAbsoluteUrl(request.origin, request.path);
      const _ignoreOutgoingRequests = options.ignoreOutgoingRequests;
      const shouldIgnore = _ignoreOutgoingRequests && url && _ignoreOutgoingRequests(url);

      return !!shouldIgnore;
    },
    startSpanHook: () => {
      return {
        [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.otel.node_fetch',
      };
    },
    requestHook: options.requestHook,
    responseHook: options.responseHook,
  } ;

  return instrumentationConfig;
}

exports.nativeNodeFetchIntegration = nativeNodeFetchIntegration;
