// 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.retrace;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import static org.objectweb.asm.Opcodes.INVOKESTATIC;

import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.JdkClassFileProvider;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.transformers.ClassTransformer;
import com.android.tools.r8.transformers.MethodTransformer;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.StackTraceUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.ZipUtils;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Supplier;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import org.objectweb.asm.MethodVisitor;

@RunWith(Parameterized.class)
public class RetraceStackTraceFunctionalCompositionTest extends TestBase {

  @Parameter() public TestParameters parameters;

  private Path rewrittenR8Jar;
  private static final int SAMPLING_SIZE = 50000;

  @Parameters(name = "{0}")
  public static TestParametersCollection data() {
    assumeTrue(ToolHelper.isLinux());
    return getTestParameters().withDefaultCfRuntime().build();
  }

  private void insertPrintingOfStacktraces(Path path, Path outputPath) throws Exception {
    String entryNameForClass = ZipUtils.zipEntryNameForClass(StackTraceUtils.class);
    Box<Long> idBox = new Box<>(0L);
    ZipUtils.map(
        path,
        outputPath,
        (zipEntry, bytes) -> {
          String entryName = zipEntry.getName();
          // Only insert into the R8 namespace, this will provide a better sampling than inserting
          // into all calls due to more inlining/outlining could have happened.
          if (ZipUtils.isClassFile(entryName)
              && !entryNameForClass.equals(entryName)
              && entryName.contains("com/android/tools/r8/")) {
            return transformer(bytes, null)
                .addClassTransformer(
                    new ClassTransformer() {
                      @Override
                      public MethodVisitor visitMethod(
                          int access,
                          String name,
                          String descriptor,
                          String signature,
                          String[] exceptions) {
                        MethodVisitor sub =
                            super.visitMethod(access, name, descriptor, signature, exceptions);
                        if (name.equals("<clinit>")) {
                          return sub;
                        } else {
                          return new InsertStackTraceCallTransformer(
                              sub, () -> idBox.getAndCompute(x -> x + 1));
                        }
                      }
                      ;
                    })
                .transform();
          }
          return bytes;
        });
  }

  private static class InsertStackTraceCallTransformer extends MethodTransformer {

    private boolean insertedStackTraceCall = false;
    private final Supplier<Long> idGenerator;

    private InsertStackTraceCallTransformer(MethodVisitor visitor, Supplier<Long> idGenerator) {
      this.mv = visitor;
      this.idGenerator = idGenerator;
    }

    @Override
    public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
      insertPrintIfFirstInstruction();
      super.visitFieldInsn(opcode, owner, name, descriptor);
    }

    @Override
    public void visitInsn(int opcode) {
      insertPrintIfFirstInstruction();
      super.visitInsn(opcode);
    }

    @Override
    public void visitLdcInsn(Object value) {
      insertPrintIfFirstInstruction();
      super.visitLdcInsn(value);
    }

    @Override
    public void visitMethodInsn(
        int opcode, String owner, String name, String descriptor, boolean isInterface) {
      insertPrintIfFirstInstruction();
      super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
    }

    private void insertPrintIfFirstInstruction() {
      if (!insertedStackTraceCall) {
        super.visitLdcInsn(idGenerator.get());
        super.visitMethodInsn(
            INVOKESTATIC, binaryName(StackTraceUtils.class), "printCurrentStack", "(J)V", false);
        insertedStackTraceCall = true;
      }
    }

    @Override
    public void visitMaxs(int maxStack, int maxLocals) {
      super.visitMaxs(maxStack + 2, maxLocals);
    }
  }

  private Path getRewrittenR8Jar() throws Exception {
    if (rewrittenR8Jar != null) {
      return rewrittenR8Jar;
    }
    rewrittenR8Jar = temp.newFolder().toPath().resolve("r8_with_deps_with_prints.jar");
    insertPrintingOfStacktraces(ToolHelper.R8_WITH_DEPS_JAR, rewrittenR8Jar);
    return rewrittenR8Jar;
  }

  @Ignore("b/255292908")
  @Test
  public void testR8RetraceAndComposition() throws Exception {
    Path rewrittenR8Jar = getRewrittenR8Jar();
    List<String> originalStackTraces = generateStackTraces(rewrittenR8Jar);
    Map<String, List<String>> originalPartitions = partitionStacktraces(originalStackTraces);

    List<String> originalStackTracesDeterministicCheck = generateStackTraces(rewrittenR8Jar);
    Map<String, List<String>> deterministicPartitions =
        partitionStacktraces(originalStackTracesDeterministicCheck);
    comparePartitionedStackTraces(originalPartitions, deterministicPartitions);

    // Compile rewritten R8 with R8 to obtain first level
    Pair<Path, Path> r8OfR8 = compileR8WithR8(rewrittenR8Jar);

    // If we retrace the entire file we should get the same result as the original.
    List<String> retracedFirstLevelStackTraces =
        retrace(r8OfR8.getSecond(), generateStackTraces(r8OfR8.getFirst()));
    Map<String, List<String>> firstRoundPartitions =
        partitionStacktraces(retracedFirstLevelStackTraces);
    comparePartitionedStackTraces(originalPartitions, firstRoundPartitions);

    Pair<Path, Path> d8OfR8ofR8 = compileWithD8(r8OfR8.getFirst(), r8OfR8.getSecond());
    List<String> d8StackTraces = generateStackTraces(d8OfR8ofR8.getFirst());
    List<String> secondRoundStackTraces = retrace(d8OfR8ofR8.getSecond(), d8StackTraces);
    Map<String, List<String>> secondRoundPartitions = partitionStacktraces(secondRoundStackTraces);
    comparePartitionedStackTraces(originalPartitions, secondRoundPartitions);
  }

  private List<String> retrace(Path mappingFile, List<String> stacktraces) {
    List<String> retracedLines = new ArrayList<>();
    Retrace.run(
        RetraceCommand.builder()
            .setRetracedStackTraceConsumer(retracedLines::addAll)
            .setStackTrace(stacktraces)
            .setMappingSupplier(
                ProguardMappingSupplier.builder()
                    .setProguardMapProducer(ProguardMapProducer.fromPath(mappingFile))
                    // TODO(b/241763080): Remove when stable.
                    .setAllowExperimental(true)
                    .build())
            .build());
    return retracedLines;
  }

  private void comparePartitionedStackTraces(
      Map<String, List<String>> one, Map<String, List<String>> other) {
    for (Entry<String, List<String>> keyStackTraceEntry : one.entrySet()) {
      String oneAsString = StringUtils.lines(keyStackTraceEntry.getValue());
      String otherAsString = StringUtils.lines(other.get(keyStackTraceEntry.getKey()));
      assertEquals(oneAsString, otherAsString);
    }
    assertEquals(one.keySet(), other.keySet());
  }

  private Map<String, List<String>> partitionStacktraces(List<String> allStacktraces) {
    Map<String, List<String>> partitions = new LinkedHashMap<>();
    int lastIndex = 0;
    for (int i = 0; i < allStacktraces.size(); i++) {
      if (allStacktraces.get(i).contains("@@@@")) {
        List<String> stackTrace = allStacktraces.subList(lastIndex, i);
        String keyForStackTrace = getKeyForStackTrace(stackTrace);
        List<String> existing = partitions.put(keyForStackTrace, stackTrace);
        assertNull(existing);
        lastIndex = i + 1;
        i++;
      }
    }
    return partitions;
  }

  private String getKeyForStackTrace(List<String> stackTrace) {
    String identifier = "java.lang.RuntimeException: ------(";
    String firstLine = stackTrace.get(0);
    int index = firstLine.indexOf(identifier);
    assertEquals(0, index);
    String endIdentifier = ")------";
    int endIndex = firstLine.indexOf(endIdentifier);
    assertTrue(endIndex > 0);
    return firstLine.substring(index + identifier.length(), endIndex);
  }

  private Pair<Path, Path> compileR8WithR8(Path r8Input) throws Exception {
    Path MAIN_KEEP = Paths.get("src/main/keep.txt");
    Path jar = temp.newFolder().toPath().resolve("out.jar");
    Path map = temp.newFolder().toPath().resolve("out.map");
    testForR8(Backend.CF)
        .setMode(CompilationMode.RELEASE)
        .addProgramFiles(r8Input)
        .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
        .addKeepRuleFiles(MAIN_KEEP)
        // TODO(b/241763080): Remove when stable version is default.
        .enableExperimentalMapFileVersion()
        .allowUnusedProguardConfigurationRules()
        .addDontObfuscate()
        .compile()
        .apply(c -> FileUtils.writeTextFile(map, c.getProguardMap()))
        .writeToZip(jar);
    return Pair.create(jar, map);
  }

  private Pair<Path, Path> compileWithD8(Path r8Input, Path previousMappingFile) throws Exception {
    StringBuilder mappingComposed = new StringBuilder();
    Path jar = temp.newFolder().toPath().resolve("out.jar");
    Path map = temp.newFolder().toPath().resolve("out.map");
    testForD8(Backend.CF)
        .setMode(CompilationMode.RELEASE)
        .addProgramFiles(r8Input)
        .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
        .enableExperimentalMapFileVersion()
        // TODO(b/241763080): Enable CF PC test mapping for this compilation.
        .addOptionsModification(
            options -> options.mappingComposeOptions().enableExperimentalMappingComposition = true)
        .apply(
            b ->
                b.getBuilder()
                    .setProguardInputMapFile(previousMappingFile)
                    .setProguardMapConsumer((string, handler) -> mappingComposed.append(string)))
        .compile()
        .writeToZip(jar);
    FileUtils.writeTextFile(map, mappingComposed.toString());
    return Pair.create(jar, map);
  }

  private List<String> generateStackTraces(Path r8Jar) throws Exception {
    File stacktraceOutput = new File(temp.newFolder(), "stacktraces.txt");
    stacktraceOutput.createNewFile();
    testForExternalR8(Backend.DEX, parameters.getRuntime())
        .useProvidedR8(r8Jar)
        .addProgramClasses(HelloWorld.class)
        .addKeepMainRule(HelloWorld.class)
        .setMinApi(AndroidApiLevel.B)
        .addJvmFlag("-Dcom.android.tools.r8.deterministicdebugging=true")
        .addJvmFlag("-Dcom.android.tools.r8.internalStackTraceSamplingInterval=" + SAMPLING_SIZE)
        .addJvmFlag("-Dcom.android.tools.r8.internalPathToStacktraces=" + stacktraceOutput.toPath())
        .compile();
    return Files.readAllLines(stacktraceOutput.toPath(), StandardCharsets.UTF_8);
  }

  public static class HelloWorld {

    public static void main(String[] args) {
      System.out.println("Hello World");
    }
  }
}
