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

package io.opentelemetry.results;

import static java.util.concurrent.TimeUnit.NANOSECONDS;

import io.opentelemetry.config.TestConfig;
import java.io.PrintStream;
import java.time.Duration;
import java.util.Date;
import java.util.List;
import java.util.function.Function;

class PrintStreamPersister implements ResultsPersister {

  private final PrintStream out;

  public PrintStreamPersister(PrintStream out) {
    this.out = out;
  }

  @Override
  public void write(List<AppPerfResults> results) {
    TestConfig config = results.stream().findFirst().get().config;
    out.println("----------------------------------------------------------");
    out.println(" Run at " + new Date());
    out.printf(" %s : %s\n", config.getName(), config.getDescription());
    out.printf(
        " %d users, %d iterations\n",
        config.getConcurrentConnections(), config.getTotalIterations());
    out.println("----------------------------------------------------------");

    display(results, "Agent", appPerfResults -> appPerfResults.agent.getName());
    display(
        results,
        "Run duration",
        res -> {
          Duration duration = Duration.ofMillis(res.runDurationMs);
          return String.format(
              "%02d:%02d:%02d",
              duration.toHours(), duration.toMinutesPart(), duration.toSecondsPart());
        });
    display(results, "Avg. CPU (user) %", res -> String.valueOf(res.averageJvmUserCpu));
    display(results, "Max. CPU (user) %", res -> String.valueOf(res.maxJvmUserCpu));
    display(results, "Avg. mch tot cpu %", res -> String.valueOf(res.averageMachineCpuTotal));
    display(results, "Startup time (ms)", res -> String.valueOf(res.startupDurationMs));
    display(results, "Total allocated MB", res -> format(res.getTotalAllocatedMB()));
    display(results, "Min heap used (MB)", res -> format(res.getMinHeapUsedMB()));
    display(results, "Max heap used (MB)", res -> format(res.getMaxHeapUsedMB()));
    display(results, "Thread switch rate", res -> String.valueOf(res.maxThreadContextSwitchRate));
    display(results, "GC time (ms)", res -> String.valueOf(NANOSECONDS.toMillis(res.totalGCTime)));
    display(
        results,
        "GC pause time (ms)",
        res -> String.valueOf(NANOSECONDS.toMillis(res.totalGcPauseNanos)));
    display(results, "Req. mean (ms)", res -> format(res.requestAvg));
    display(results, "Req. p95 (ms)", res -> format(res.requestP95));
    display(results, "Iter. mean (ms)", res -> format(res.iterationAvg));
    display(results, "Iter. p95 (ms)", res -> format(res.iterationP95));
    display(results, "Net read avg (bps)", res -> format(res.averageNetworkRead));
    display(results, "Net write avg (bps)", res -> format(res.averageNetworkWrite));
    display(results, "Peak threads", res -> String.valueOf(res.peakThreadCount));
  }

  private void display(
      List<AppPerfResults> results, String pref, Function<AppPerfResults, String> vs) {
    out.printf("%-20s: ", pref);
    results.forEach(
        result -> {
          out.printf("%17s", vs.apply(result));
        });
    out.println();
  }

  private String format(double d) {
    return String.format("%.2f", d);
  }
}
