// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.benchmarks;

import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.StringUtils.BraceType;
import com.google.common.base.Strings;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BenchmarkCollectionPrinter {

  private interface RunnableIO {
    void run() throws IOException;
  }

  private static final PrintStream QUIET =
      new PrintStream(
          new OutputStream() {
            @Override
            public void write(int b) {
              // ignore
            }
          });

  // Internal state for printing the benchmark config for golem.
  private int currentIndent = 0;
  private final PrintStream out;

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

  private void scopeBraces(RunnableIO fn) throws IOException {
    print("{");
    indentScope(2, fn);
    print("}");
  }

  private void indentScope(RunnableIO fn) throws IOException {
    indentScope(2, fn);
  }

  private void indentScope(int spaces, RunnableIO fn) throws IOException {
    currentIndent += spaces;
    fn.run();
    currentIndent -= spaces;
  }

  private static String quote(String str) {
    return "\"" + str + "\"";
  }

  private void print(String string) {
    printIndented(string, currentIndent);
  }

  private void printSemi(String string) {
    print(string + ";");
  }

  private void printIndented(String string, int indent) {
    out.print(Strings.repeat(" ", indent));
    out.println(string);
  }

  public void printGolemConfig(Collection<BenchmarkConfig> benchmarks) throws IOException {
    Path jdkHome = getJdkHome();
    Map<String, List<BenchmarkConfig>> nameToTargets = new HashMap<>();
    benchmarks.forEach(
        b -> nameToTargets.computeIfAbsent(b.getName(), k -> new ArrayList<>()).add(b));
    List<String> sortedNames = new ArrayList<>(nameToTargets.keySet());
    sortedNames.sort(String::compareTo);
    print("// AUTOGENERATED FILE generated with");
    print("// src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollection.java");
    print("// in the R8 repository.");
    print("");
    printSemi("part of r8_config");
    print("");
    print("createTestBenchmarks() {");
    indentScope(
        () -> {
          print("final cpus = [\"Lenovo M90\"];");
          addGolemResource("openjdk", Paths.get(jdkHome + ".tar.gz"));
          for (String benchmarkName : sortedNames) {
            List<BenchmarkConfig> benchmarkTargets = nameToTargets.get(benchmarkName);
            assert !benchmarkTargets.isEmpty();
            scopeBraces(() -> printBenchmarkBlock(benchmarkName, benchmarkTargets));
          }
        });
    print("}");
  }

  private void printBenchmarkBlock(String benchmarkName, List<BenchmarkConfig> benchmarkVariants)
      throws IOException {
    // Common properties that must be consistent among all the benchmark variants.
    String suite = BenchmarkConfig.getCommonSuite(benchmarkVariants).getDartName();
    List<String> metrics =
        new ArrayList<>(
            ListUtils.map(
                BenchmarkConfig.getCommonMetrics(benchmarkVariants), BenchmarkMetric::getDartType));
    metrics.sort(String::compareTo);
    printSemi("final name = " + quote(benchmarkName));
    printSemi("final metrics = " + StringUtils.join(", ", metrics, BraceType.SQUARE));
    printSemi("final benchmark = StandardBenchmark(name, metrics)");
    BenchmarkTimeout timeout = BenchmarkConfig.getCommonTimeout(benchmarkVariants);
    if (timeout != null) {
      printSemi("final timeout = const Duration(seconds: " + timeout.asSeconds() + ")");
      printSemi("ExecutionManagement.addTimeoutConstraint(timeout, benchmark: benchmark)");
    }
    for (BenchmarkConfig benchmark : benchmarkVariants) {
      scopeBraces(
          () -> {
            printSemi("final target = " + quote(benchmark.getTarget().getGolemName()));
            printSemi("final options = benchmark.addTargets(noImplementation, [target])");
            printSemi("options.cpus = cpus");
            printSemi("options.isScript = true");
            printSemi("options.fromRevision = " + benchmark.getFromRevision());
            print("options.mainFile =");
            indentScope(
                4,
                () ->
                    printSemi(
                        quote(
                            "tools/run_benchmark.py --golem"
                                + " --target "
                                + benchmark.getTarget().getIdentifierName()
                                + " --benchmark "
                                + benchmark.getName())));
            printSemi("options.resources.add(openjdk)");
            for (BenchmarkDependency dependency : benchmark.getDependencies()) {
              scopeBraces(
                  () -> {
                    String dependencyName = dependency.getName();
                    addGolemResource(dependencyName, dependency.getTarball());
                    printSemi("options.resources.add(" + dependencyName + ")");
                  });
            }
          });
    }
    printSemi(suite + ".addBenchmark(name)");
  }

  private void addGolemResource(String name, Path tarball) throws IOException {
    Path shaFile = Paths.get(tarball.toString() + ".sha1");
    downloadDependency(shaFile);
    String sha256 = computeSha256(tarball);
    String shaFileContent = getShaFileContent(shaFile);
    print("final " + name + " = BenchmarkResource(" + quote("") + ",");
    indentScope(
        4,
        () -> {
          print("type: BenchmarkResourceType.storage,");
          print("uri: " + quote("gs://r8-deps/" + shaFileContent) + ",");
          // Make dart formatter happy.
          if (currentIndent > 6) {
            print("hash:");
            indentScope(4, () -> print(quote(sha256) + ","));
          } else {
            print("hash: " + quote(sha256) + ",");
          }
          print("extract: " + quote("gz") + ");");
        });
  }

  private static Path getJdkHome() throws IOException {
    ProcessBuilder builder = new ProcessBuilder("python3", "tools/jdk.py");
    ProcessResult result = ToolHelper.runProcess(builder, QUIET);
    if (result.exitCode != 0) {
      throw new BenchmarkConfigError("Unexpected failure to determine jdk home: " + result);
    }
    return Paths.get(result.stdout.trim());
  }

  private static String computeSha256(Path path) throws IOException {
    Hasher hasher = Hashing.sha256().newHasher();
    return hasher.putBytes(Files.readAllBytes(path)).hash().toString();
  }

  private static String getShaFileContent(Path path) throws IOException {
    return String.join("\n", Files.readAllLines(path)).trim();
  }

  private static void downloadDependency(Path path) throws IOException {
    ProcessBuilder builder =
        new ProcessBuilder(
            "download_from_google_storage", "-n", "-b", "r8-deps", "-u", "-s", path.toString());
    ProcessResult result = ToolHelper.runProcess(builder, QUIET);
    if (result.exitCode != 0) {
      throw new BenchmarkConfigError("Unable to download dependency '" + path + "'\n" + result);
    }
  }
}
