// Copyright (c) 2020, 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.kotlin.metadata;

import static com.android.tools.r8.ToolHelper.getKotlinC_1_3_72;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.objectweb.asm.Opcodes.ASM7;

import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.graph.DexAnnotationElement;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.transformers.ClassTransformer;
import com.android.tools.r8.utils.StreamUtils;
import com.android.tools.r8.utils.ZipUtils;
import com.android.tools.r8.utils.codeinspector.AnnotationSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
import java.io.IOException;
import java.util.Arrays;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.objectweb.asm.AnnotationVisitor;

@RunWith(Parameterized.class)
public class MetadataVersionNumberBumpTest extends KotlinMetadataTestBase {

  private final TestParameters parameters;

  @Parameters(name = "{0}")
  public static TestParametersCollection data() {
    return getTestParameters().withAllRuntimesAndApiLevels().build();
  }

  public MetadataVersionNumberBumpTest(TestParameters parameters) {
    super(KotlinTargetVersion.JAVA_8, getKotlinC_1_3_72());
    this.parameters = parameters;
  }

  @Test
  public void testLessThan1_4() throws Exception {
    final R8FullTestBuilder testBuilder = testForR8(parameters.getBackend());
    rewriteMetadataVersion(testBuilder::addProgramClassFileData, new int[] {1, 1, 16});
    testBuilder
        .setMinApi(parameters.getApiLevel())
        .addKeepAllClassesRule()
        .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
        .addDontWarnJetBrainsAnnotations()
        .compile()
        .inspect(inspector -> inspectMetadataVersion(inspector, "1.4.0"));
  }

  @Test
  public void testEqualTo1_4() throws Exception {
    final R8FullTestBuilder testBuilder = testForR8(parameters.getBackend());
    rewriteMetadataVersion(testBuilder::addProgramClassFileData, new int[] {1, 4, 0});
    testBuilder
        .setMinApi(parameters.getApiLevel())
        .addKeepAllClassesRule()
        .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
        .addDontWarnJetBrainsAnnotations()
        .compile()
        .inspect(inspector -> inspectMetadataVersion(inspector, "1.4.0"));
  }

  @Test
  public void testGreaterThan1_4() throws Exception {
    final R8FullTestBuilder testBuilder = testForR8(parameters.getBackend());
    rewriteMetadataVersion(testBuilder::addProgramClassFileData, new int[] {1, 4, 2});
    testBuilder
        .setMinApi(parameters.getApiLevel())
        .addKeepAllClassesRule()
        .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
        .addDontWarnJetBrainsAnnotations()
        .compile()
        .inspect(inspector -> inspectMetadataVersion(inspector, "1.4.2"));
  }

  private void rewriteMetadataVersion(Consumer<byte[]> rewrittenBytesConsumer, int[] newVersion)
      throws IOException {
    ZipUtils.iter(
        ToolHelper.getKotlinStdlibJar(kotlinc).toString(),
        ((entry, input) -> {
          if (!entry.getName().endsWith(".class")) {
            return;
          }
          final byte[] bytes = StreamUtils.StreamToByteArrayClose(input);
          final byte[] rewrittenBytes =
              transformMetadataVersion(
                  entry.getName().substring(0, entry.getName().length() - 6), bytes, newVersion);
          rewrittenBytesConsumer.accept(rewrittenBytes);
        }));
  }

  private byte[] transformMetadataVersion(String descriptor, byte[] bytes, int[] newVersion) {
    return transformer(bytes, Reference.classFromDescriptor(descriptor))
        .addClassTransformer(
            new ClassTransformer() {
              @Override
              public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
                if (!descriptor.equals("Lkotlin/Metadata;")) {
                  return super.visitAnnotation(descriptor, visible);
                } else {
                  return new AnnotationVisitor(ASM7, super.visitAnnotation(descriptor, visible)) {
                    @Override
                    public void visit(String name, Object value) {
                      if (name.equals("mv")) {
                        super.visit(name, newVersion);
                      } else {
                        super.visit(name, value);
                      }
                    }
                  };
                }
              }
            })
        .transform();
  }

  private void inspectMetadataVersion(CodeInspector inspector, String expectedVersion) {
    for (FoundClassSubject clazz : inspector.allClasses()) {
      verifyExpectedVersionForClass(clazz, expectedVersion);
    }
  }

  private void verifyExpectedVersionForClass(FoundClassSubject clazz, String expectedVersion) {
    final AnnotationSubject annotationSubject = clazz.annotation("kotlin.Metadata");
    // TODO(b/164418977): All classes should have an annotation?
    if (!annotationSubject.isPresent()) {
      return;
    }
    final DexAnnotationElement[] elements = annotationSubject.getAnnotation().elements;
    for (DexAnnotationElement element : elements) {
      if (!element.name.toString().equals("mv")) {
        continue;
      }
      final String version =
          Arrays.stream(element.value.asDexValueArray().getValues())
              .map(val -> val.asDexValueInt().value + "")
              .collect(Collectors.joining("."));
      assertEquals(expectedVersion, version);
      return;
    }
    fail("Could not find the mv (metadataVersion) element");
  }
}
