import { browserPerformanceTimeOrigin, getActiveSpan, getRootSpan, spanToJSON, getCurrentScope, timestampInSeconds, startSpan, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core';
import { addPerformanceInstrumentationHandler } from './instrument.js';
import { getBrowserPerformanceAPI, msToSec } from './utils.js';

// ElementTiming interface based on the W3C spec

/**
 * Start tracking ElementTiming performance entries.
 */
function startTrackingElementTiming() {
  const performance = getBrowserPerformanceAPI();
  if (performance && browserPerformanceTimeOrigin()) {
    return addPerformanceInstrumentationHandler('element', _onElementTiming);
  }

  return () => undefined;
}

/**
 * exported only for testing
 */
const _onElementTiming = ({ entries }) => {
  const activeSpan = getActiveSpan();
  const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;
  const transactionName = rootSpan
    ? spanToJSON(rootSpan).description
    : getCurrentScope().getScopeData().transactionName;

  entries.forEach(entry => {
    const elementEntry = entry ;

    // Skip entries without identifier (elementtiming attribute)
    if (!elementEntry.identifier) {
      return;
    }

    // `name` contains the type of the element paint. Can be `'image-paint'` or `'text-paint'`.
    // https://developer.mozilla.org/en-US/docs/Web/API/PerformanceElementTiming#instance_properties
    const paintType = elementEntry.name ;

    const renderTime = elementEntry.renderTime;
    const loadTime = elementEntry.loadTime;

    // starting the span at:
    // - `loadTime` if available (should be available for all "image-paint" entries, 0 otherwise)
    // - `renderTime` if available (available for all entries, except 3rd party images, but these should be covered by `loadTime`, 0 otherwise)
    // - `timestampInSeconds()` as a safeguard
    // see https://developer.mozilla.org/en-US/docs/Web/API/PerformanceElementTiming/renderTime#cross-origin_image_render_time
    const [spanStartTime, spanStartTimeSource] = loadTime
      ? [msToSec(loadTime), 'load-time']
      : renderTime
        ? [msToSec(renderTime), 'render-time']
        : [timestampInSeconds(), 'entry-emission'];

    const duration =
      paintType === 'image-paint'
        ? // for image paints, we can acually get a duration because image-paint entries also have a `loadTime`
          // and `renderTime`. `loadTime` is the time when the image finished loading and `renderTime` is the
          // time when the image finished rendering.
          msToSec(Math.max(0, (renderTime ?? 0) - (loadTime ?? 0)))
        : // for `'text-paint'` entries, we can't get a duration because the `loadTime` is always zero.
          0;

    const attributes = {
      [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.browser.elementtiming',
      [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'ui.elementtiming',
      // name must be user-entered, so we can assume low cardinality
      [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'component',
      // recording the source of the span start time, as it varies depending on available data
      'sentry.span_start_time_source': spanStartTimeSource,
      'sentry.transaction_name': transactionName,
      'element.id': elementEntry.id,
      'element.type': elementEntry.element?.tagName?.toLowerCase() || 'unknown',
      'element.size':
        elementEntry.naturalWidth && elementEntry.naturalHeight
          ? `${elementEntry.naturalWidth}x${elementEntry.naturalHeight}`
          : undefined,
      'element.render_time': renderTime,
      'element.load_time': loadTime,
      // `url` is `0`(number) for text paints (hence we fall back to undefined)
      'element.url': elementEntry.url || undefined,
      'element.identifier': elementEntry.identifier,
      'element.paint_type': paintType,
    };

    startSpan(
      {
        name: `element[${elementEntry.identifier}]`,
        attributes,
        startTime: spanStartTime,
        onlyIfParent: true,
      },
      span => {
        span.end(spanStartTime + duration);
      },
    );
  });
};

export { _onElementTiming, startTrackingElementTiming };//# sourceMappingURL=http://go/sourcemap/sourcemaps/042b3c1a4c53f2c3808067f519fbfc67b72cad80/node_modules/@sentry-internal/browser-utils/build/esm/metrics/elementTiming.js.map
