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

package io.opentelemetry.opencensusshim;

import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat;
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.attributeEntry;
import static org.assertj.core.api.Assertions.assertThat;

import com.google.common.collect.ImmutableList;
import io.opencensus.common.Duration;
import io.opencensus.stats.Aggregation;
import io.opencensus.stats.Measure;
import io.opencensus.stats.Stats;
import io.opencensus.stats.StatsRecorder;
import io.opencensus.stats.View;
import io.opencensus.stats.ViewManager;
import io.opencensus.tags.TagContext;
import io.opencensus.tags.TagKey;
import io.opencensus.tags.TagMetadata;
import io.opencensus.tags.TagValue;
import io.opencensus.tags.Tagger;
import io.opencensus.tags.Tags;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.metrics.data.MetricData;
import io.opentelemetry.sdk.testing.exporter.InMemoryMetricExporter;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import org.awaitility.Awaitility;
import org.junit.jupiter.api.Test;

class OpenTelemetryMetricExporterTest {

  @Test
  @SuppressWarnings({"deprecation", "unchecked"}) // Summary is deprecated in census
  void testSupportedMetricsExportedCorrectly() throws Exception {
    Tagger tagger = Tags.getTagger();
    Measure.MeasureLong latency =
        Measure.MeasureLong.create("task_latency", "The task latency in milliseconds", "ms");
    Measure.MeasureDouble latency2 =
        Measure.MeasureDouble.create("task_latency_2", "The task latency in milliseconds 2", "ms");
    StatsRecorder statsRecorder = Stats.getStatsRecorder();
    TagKey tagKey = TagKey.create("tagKey");
    TagValue tagValue = TagValue.create("tagValue");
    View longSumView =
        View.create(
            View.Name.create("long_sum"),
            "long sum",
            latency,
            Aggregation.Sum.create(),
            ImmutableList.of(tagKey));
    View longGaugeView =
        View.create(
            View.Name.create("long_gauge"),
            "long gauge",
            latency,
            Aggregation.LastValue.create(),
            ImmutableList.of(tagKey));
    View doubleSumView =
        View.create(
            View.Name.create("double_sum"),
            "double sum",
            latency2,
            Aggregation.Sum.create(),
            ImmutableList.of());
    View doubleGaugeView =
        View.create(
            View.Name.create("double_gauge"),
            "double gauge",
            latency2,
            Aggregation.LastValue.create(),
            ImmutableList.of());
    ViewManager viewManager = Stats.getViewManager();
    viewManager.registerView(longSumView);
    viewManager.registerView(longGaugeView);
    viewManager.registerView(doubleSumView);
    viewManager.registerView(doubleGaugeView);
    // Create OpenCensus -> OpenTelemetry Exporter bridge
    InMemoryMetricExporter exporter = InMemoryMetricExporter.create();
    OpenTelemetryMetricsExporter otelExporter =
        OpenTelemetryMetricsExporter.createAndRegister(exporter, Duration.create(1, 0));
    try {
      TagContext tagContext =
          tagger
              .emptyBuilder()
              .put(tagKey, tagValue, TagMetadata.create(TagMetadata.TagTtl.UNLIMITED_PROPAGATION))
              .build();
      try (io.opencensus.common.Scope ss = tagger.withTagContext(tagContext)) {
        statsRecorder.newMeasureMap().put(latency, 50).record();
        statsRecorder.newMeasureMap().put(latency2, 60).record();
      }
      Set<String> allowedMetrics = new HashSet<>();
      allowedMetrics.add("double_gauge");
      allowedMetrics.add("double_sum");
      allowedMetrics.add("long_gauge");
      allowedMetrics.add("long_sum");
      // Slow down for OpenCensus to catch up.
      Awaitility.await()
          .atMost(java.time.Duration.ofSeconds(10))
          .untilAsserted(
              () ->
                  assertThat(
                          exporter.getFinishedMetricItems().stream()
                              .filter(metric -> allowedMetrics.contains(metric.getName()))
                              .sorted(Comparator.comparing(MetricData::getName))
                              .collect(Collectors.toList()))
                      .satisfiesExactly(
                          metric ->
                              assertThat(metric)
                                  .hasName("double_gauge")
                                  .hasDescription("double gauge")
                                  .hasUnit("ms")
                                  .hasDoubleGaugeSatisfying(
                                      gauge ->
                                          gauge.hasPointsSatisfying(
                                              point ->
                                                  point
                                                      .hasValue(60)
                                                      .hasAttributes(Attributes.empty()))),
                          metric ->
                              assertThat(metric)
                                  .hasName("double_sum")
                                  .hasDescription("double sum")
                                  .hasUnit("ms")
                                  .hasDoubleSumSatisfying(
                                      sum ->
                                          sum.hasPointsSatisfying(
                                              point ->
                                                  point
                                                      .hasValue(60)
                                                      .hasAttributes(Attributes.empty()))),
                          metric ->
                              assertThat(metric)
                                  .hasName("long_gauge")
                                  .hasDescription("long gauge")
                                  .hasUnit("ms")
                                  .hasLongGaugeSatisfying(
                                      gauge ->
                                          gauge.hasPointsSatisfying(
                                              point ->
                                                  point
                                                      .hasValue(50)
                                                      .hasAttributes(
                                                          attributeEntry(
                                                              tagKey.getName(),
                                                              tagValue.asString())))),
                          metric ->
                              assertThat(metric)
                                  .hasName("long_sum")
                                  .hasDescription("long sum")
                                  .hasUnit("ms")
                                  .hasLongSumSatisfying(
                                      sum ->
                                          sum.hasPointsSatisfying(
                                              point ->
                                                  point
                                                      .hasValue(50)
                                                      .hasAttributes(
                                                          attributeEntry(
                                                              tagKey.getName(),
                                                              tagValue.asString()))))));
    } finally {
      otelExporter.stop();
    }
  }
}

@@ -317,50 +317,46 @@
 tic 
-org.assertj.core.api.Assertions.assertThat
+java.util.stream.Collectors.groupingBy
 ;%0A%0Ai
@@ -1051,37 +1051,8 @@
 er;%0A
-import java.util.Comparator;%0A
 impo
@@ -1288,21 +1288,8 @@
 ion%22
-, %22unchecked%22
 %7D) /
@@ -1372,25 +1372,8 @@
 ly()
- throws Exception
  %7B%0A 
@@ -4031,16 +4031,175 @@
 rtThat(%0A
+                          // Filter for metrics with name in allowedMetrics, and dedupe to only one%0A                          // metric per unique metric name%0A
         
@@ -4385,35 +4385,26 @@
    .
-sorted(Comparator.compar
+collect(group
 ing
+By
 (Met
@@ -4422,16 +4422,164 @@
 tName))%0A
+                              .values()%0A                              .stream()%0A                              .map(metricData -%3E metricData.get(0))%0A
         
@@ -4670,16 +4670,26 @@
 sExactly
+InAnyOrder
 (%0A      

Fix OpenTelemetryMetricExporterTest flake (#4657)