/*
 * Copyright The OpenTelemetry Authors
 * SPDX-License-Identifier: Apache-2.0
 */

package io.opentelemetry.instrumentation.api.internal;

import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapGetter;
import io.opentelemetry.context.propagation.TextMapSetter;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.InstrumenterBuilder;
import io.opentelemetry.instrumentation.api.instrumenter.SpanKindExtractor;
import java.time.Instant;
import javax.annotation.Nullable;

/**
 * This class is internal and is hence not for public use. Its APIs are unstable and can change at
 * any time.
 */
public final class InstrumenterUtil {

  private static InstrumenterAccess instrumenterAccess;
  private static InstrumenterBuilderAccess instrumenterBuilderAccess;

  public static void setInstrumenterAccess(InstrumenterAccess instrumenterAccess) {
    InstrumenterUtil.instrumenterAccess = instrumenterAccess;
  }

  public static void setInstrumenterBuilderAccess(
      InstrumenterBuilderAccess instrumenterBuilderAccess) {
    InstrumenterUtil.instrumenterBuilderAccess = instrumenterBuilderAccess;
  }

  public static <REQUEST, RESPONSE> Context startAndEnd(
      Instrumenter<REQUEST, RESPONSE> instrumenter,
      Context parentContext,
      REQUEST request,
      @Nullable RESPONSE response,
      @Nullable Throwable error,
      Instant startTime,
      Instant endTime) {
    // instrumenterAccess is guaranteed to be non-null here
    return instrumenterAccess.startAndEnd(
        instrumenter, parentContext, request, response, error, startTime, endTime);
  }

  public static <REQUEST, RESPONSE> Instrumenter<REQUEST, RESPONSE> buildUpstreamInstrumenter(
      InstrumenterBuilder<REQUEST, RESPONSE> builder,
      TextMapGetter<REQUEST> getter,
      SpanKindExtractor<REQUEST> spanKindExtractor) {
    // instrumenterBuilderAccess is guaranteed to be non-null here
    return instrumenterBuilderAccess.buildUpstreamInstrumenter(builder, getter, spanKindExtractor);
  }

  public static <REQUEST, RESPONSE> Instrumenter<REQUEST, RESPONSE> buildDownstreamInstrumenter(
      InstrumenterBuilder<REQUEST, RESPONSE> builder,
      TextMapSetter<REQUEST> setter,
      SpanKindExtractor<REQUEST> spanKindExtractor) {
    // instrumenterBuilderAccess is guaranteed to be non-null here
    return instrumenterBuilderAccess.buildDownstreamInstrumenter(
        builder, setter, spanKindExtractor);
  }

  private InstrumenterUtil() {}
}
