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

package com.example.javaagent;

import static java.util.concurrent.Executors.newFixedThreadPool;

import com.google.auto.service.AutoService;
import com.google.common.collect.ImmutableMap;
import io.opentelemetry.contrib.kafka.KafkaSpanExporter;
import io.opentelemetry.contrib.kafka.KafkaSpanExporterBuilder;
import io.opentelemetry.contrib.kafka.SpanDataSerializer;
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer;
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Logger;
import org.apache.kafka.clients.producer.Producer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.common.serialization.StringSerializer;

/**
 * This is one of the main entry points for Instrumentation Agent's customizations. It allows
 * configuring the {@link AutoConfigurationCustomizer}. See the {@link
 * #customize(AutoConfigurationCustomizer)} method below.
 *
 * @see AutoConfigurationCustomizerProvider
 * @see DemoPropagatorProvider
 */
@AutoService(AutoConfigurationCustomizerProvider.class)
public class DemoAutoConfigurationCustomizerProvider
    implements AutoConfigurationCustomizerProvider {
  private final Logger logger =
      Logger.getLogger(DemoAutoConfigurationCustomizerProvider.class.getName());

  @Override
  public void customize(AutoConfigurationCustomizer autoConfiguration) {
    autoConfiguration.addTracerProviderCustomizer(this::configureSdkTracerProvider);
//        .addPropertiesSupplier(this::getDefaultProperties);
  }

  String getEnvOrDefault(String envName, String de) {
    String var = System.getenv(envName);
    if (var == null) {
      return de;
    }
    return var;
  }

  int getEnvOrDefaultInt(String envName, int de) {
    String s = getEnvOrDefault(envName, null);
    if (s == null) {
      return de;
    }
    try {
      return Integer.parseInt(s);
    } catch (NumberFormatException e) {
      return de;
    }
  }

  private SdkTracerProviderBuilder configureSdkTracerProvider(
      SdkTracerProviderBuilder tracerProvider, ConfigProperties config) {

    String extExporter = getEnvOrDefault("OTEL_TRACES_EXT_EXPORTER", "defaultExtExporter");
    String idGenerator = getEnvOrDefault("OTEL_TRACES_EXT_ID_GENERATOR", "defaultIdGenerator");
    if (extExporter.equals("kafka")) {
      KafkaSpanExporterBuilder kafkaSpanExporterBuilder = new KafkaSpanExporterBuilder();
      String kafkaBrokers = getEnvOrDefault("OTEL_TRACES_EXT_KAFKA_BROKERS",
          "defaultKafkaBrokers:9092");
      int kafkaBatchSize = getEnvOrDefaultInt("OTEL_TRACES_EXT_KAFKA_BATCH_SIZE",
          16384);
      int kafkaExecutorSize = getEnvOrDefaultInt("OTEL_TRACES_EXT_KAFKA_EXECUTOR_SIZE",
          2);
      int kafkaSendTimeoutSeconds = getEnvOrDefaultInt("OTEL_TRACES_EXT_KAFKA_TIMEOUT_SECONDS",
          1);
      String kafkaTopic = getEnvOrDefault("OTEL_TRACES_EXT_KAFKA_TOPIC",
          "otel_agent");
      System.out.printf(
          "设置:extExporter:%s, idGenerator:%s, brokers:%s, batchSize:%s, timeout:%d, topic:%s%n",
          extExporter, idGenerator, kafkaBrokers, kafkaBatchSize, kafkaSendTimeoutSeconds,
          kafkaTopic);
      ImmutableMap<String, Object> producerConfig =
          ImmutableMap.of(
              ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,
              kafkaBrokers,
              ProducerConfig.BATCH_SIZE_CONFIG,
              kafkaBatchSize,
              ProducerConfig.CLIENT_ID_CONFIG,
              UUID.randomUUID().toString());
      SpanDataSerializer spanDataSerializer = new SpanDataSerializer();
      KafkaSpanExporter kafkaSpanExporter;
      try {
        Producer<String, Collection<SpanData>> producer = KafkaSpanExporterBuilder.ProducerBuilder
            .newInstance().setConfig(producerConfig)
            .setKeySerializer(new StringSerializer())
            .setValueSerializer(spanDataSerializer)
            .build();
        kafkaSpanExporter = kafkaSpanExporterBuilder.setTopicName(kafkaTopic)
            .setTimeoutInSeconds(kafkaSendTimeoutSeconds)
            .setProducer(producer)
            .setExecutorService(newFixedThreadPool(kafkaExecutorSize))
            .build();
      } catch (Exception e) {
        System.err.printf("设置异常:%s%n", e);
        return tracerProvider;
      }
      tracerProvider
          .addSpanProcessor(SimpleSpanProcessor.create(kafkaSpanExporter));
    }
    if (idGenerator.equals("tsTraceId")) {
      tracerProvider.setIdGenerator(new TsTraceIDIdGenerator());
    }
    return tracerProvider;
  }

  private Map<String, String> getDefaultProperties() {
    Map<String, String> properties = new HashMap<>();
    properties.put("otel.exporter.otlp.endpoint", "http://127.0.0.1:8181");
    properties.put("otel.exporter.otlp.insecure", "true");
    properties.put("otel.config.max.attrs", "16");
    properties.put("otel.traces.sampler", "demo");
    return properties;
  }
}
