// 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/251677184: Failing since update to target 11")
  @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");
    }
  }
}
