// Copyright (c) 2023, 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.synthesis;

import static com.android.tools.r8.synthesis.SyntheticItemsTestUtils.syntheticBackportClass;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

import com.android.tools.r8.ByteDataView;
import com.android.tools.r8.ClassFileConsumer;
import com.android.tools.r8.DexFilePerClassFileConsumer;
import com.android.tools.r8.DexFilePerClassFileConsumerData;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

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

  private final String EXPECTED = StringUtils.lines("-2", "254");

  private final TestParameters parameters;
  private final Backend intermediateBackend;

  private final AndroidApiLevel API_WITH_BYTE_COMPARE = AndroidApiLevel.K;

  @Parameterized.Parameters(name = "{0}, intermediate: {1}")
  public static List<Object[]> data() {
    return buildParameters(
        getTestParameters().withDefaultDexRuntime().withMinimumApiLevel().build(),
        Backend.values());
  }

  public RepeatedCompilationSyntheticsTest(TestParameters parameters, Backend intermediateBackend) {
    this.parameters = parameters;
    this.intermediateBackend = intermediateBackend;
  }

  @Test
  public void testReference() throws Exception {
    testForD8(parameters.getBackend())
        .addProgramClasses(TestClass.class)
        .addProgramClassFileData(getTransformedUsesBackport())
        .setMinApi(parameters)
        .run(parameters.getRuntime(), TestClass.class)
        .assertSuccessWithOutput(EXPECTED);
  }

  @Test
  public void test() throws Exception {
    assertEquals(Backend.DEX, parameters.getBackend());

    Map<String, byte[]> firstCompilation = new HashMap<>();
    testForD8(Backend.CF)
        // High API level such that only the compareUnsigned is desugared.
        .setMinApi(API_WITH_BYTE_COMPARE)
        .setIntermediate(true)
        .addProgramClassFileData(getTransformedUsesBackport())
        .setProgramConsumer(
            new ClassFileConsumer() {
              @Override
              public synchronized void accept(
                  ByteDataView data, String descriptor, DiagnosticsHandler handler) {
                byte[] old = firstCompilation.put(descriptor, data.copyByteData());
                assertNull("Duplicate " + descriptor, old);
              }

              @Override
              public void finished(DiagnosticsHandler handler) {}
            })
        .compile();
    assertEquals(
        ImmutableSet.of(
            descriptor(UsesBackport.class),
            syntheticBackportClass(UsesBackport.class, 0).getDescriptor()),
        firstCompilation.keySet());

    List<String> secondCompilation = new ArrayList<>();
    for (Entry<String, byte[]> entry : firstCompilation.entrySet()) {
      byte[] bytes = entry.getValue();
      testForD8(intermediateBackend)
          .setMinApi(parameters)
          .setIntermediate(true)
          .addProgramClassFileData(bytes)
          .applyIf(
              intermediateBackend == Backend.CF,
              b ->
                  b.setProgramConsumer(
                      new ClassFileConsumer() {
                        @Override
                        public synchronized void accept(
                            ByteDataView data, String descriptor, DiagnosticsHandler handler) {
                          secondCompilation.add(descriptor);
                        }

                        @Override
                        public void finished(DiagnosticsHandler handler) {}
                      }),
              b ->
                  b.setProgramConsumer(
                      new DexFilePerClassFileConsumer() {
                        @Override
                        public synchronized void acceptDexFile(
                            DexFilePerClassFileConsumerData data) {
                          secondCompilation.addAll(data.getClassDescriptors());
                        }

                        @Override
                        public void finished(DiagnosticsHandler handler) {}
                      }))
          .compile();
    }

    // TODO(b/271235788): The repeated compilation is unsound and we have duplicate definitions of
    //  the backports both using the same type name.
    secondCompilation.sort(String::compareTo);
    assertEquals(
        ImmutableList.of(
            syntheticBackportClass(UsesBackport.class, 0).getDescriptor(),
            syntheticBackportClass(UsesBackport.class, 0).getDescriptor(),
            descriptor(UsesBackport.class)),
        secondCompilation);
  }

  private byte[] getTransformedUsesBackport() throws Exception {
    return transformer(UsesBackport.class)
        .transformMethodInsnInMethod(
            "bar",
            (opcode, owner, name, descriptor, isInterface, visitor) -> {
              assertEquals("compare", name);
              visitor.visitMethodInsn(opcode, owner, "compareUnsigned", descriptor, isInterface);
            })
        .transform();
  }

  static class UsesBackport {
    public static int foo(byte[] bs) {
      return Byte.compare(bs[0], bs[1]);
    }

    public static int bar(byte[] bs) {
      return Byte.compare /*Unsigned*/(bs[0], bs[1]);
    }
  }

  static class TestClass {

    public static void main(String[] args) {
      System.out.println(UsesBackport.foo(new byte[] {-1, 1}));
      System.out.println(UsesBackport.bar(new byte[] {-1, 1}));
    }
  }
}
