// Copyright (c) 2019, 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.naming.b124357885;

import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;

import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

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

  private final TestParameters parameters;
  private final boolean minification;

  @Parameters(name = "{0}, minification: {1}")
  public static List<Object[]> data() {
    return buildParameters(
        getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
  }

  public B124357885Test(TestParameters parameters, boolean minification) {
    this.parameters = parameters;
    this.minification = minification;
  }

  private void checkSignature(CodeInspector inspector, String signature) {
    String fooImplFinalDescriptor =
        DescriptorUtils.javaTypeToDescriptor(inspector.clazz(FooImpl.class).getFinalName());
    assertEquals("()" + fooImplFinalDescriptor, signature);
  }

  @Test
  public void test() throws Exception {
    R8TestCompileResult compileResult =
        testForR8Compat(parameters.getBackend())
            .addProgramClasses(Main.class, Service.class, Foo.class, FooImpl.class)
            .addKeepMainRule(Main.class)
            .addKeepAttributes(
                ProguardKeepAttributes.SIGNATURE,
                ProguardKeepAttributes.INNER_CLASSES,
                ProguardKeepAttributes.ENCLOSING_METHOD)
            .minification(minification)
            .setMinApi(parameters.getApiLevel())
            .compile()
            .inspect(
                inspector -> {
                  assertThat(inspector.clazz(Main.class), isPresentAndNotRenamed());
                  assertThat(inspector.clazz(Foo.class), not(isPresent()));
                  assertThat(inspector.clazz(FooImpl.class), isPresentAndRenamed(minification));
                  ClassSubject serviceClass = inspector.clazz(Service.class);
                  assertThat(serviceClass, isPresentAndRenamed(minification));
                  // TODO(124477502): Using uniqueMethodWithName("fooList") does not work.
                  assertEquals(1, serviceClass.allMethods().size());
                  MethodSubject fooList = serviceClass.allMethods().get(0);
                  assertThat(fooList, isPresent());
                  checkSignature(
                      inspector, fooList.asFoundMethodSubject().getFinalSignatureAttribute());
                });

    String fooImplFinalName = compileResult.inspector().clazz(FooImpl.class).getFinalName();

    compileResult
        .run(parameters.getRuntime(), Main.class)
        .assertSuccessWithOutput(StringUtils.lines(fooImplFinalName, fooImplFinalName));
  }

  public static class Main {
    public static void main(String... args) throws Exception {
      Method method = Service.class.getMethod("fooList");

      try {
        ParameterizedType type = (ParameterizedType) method.getGenericReturnType();
        Class<?> rawType = (Class<?>) type.getRawType();
        System.out.println(rawType.getName());
      } catch (ClassCastException e) {
        System.out.println(((Class<?>) method.getGenericReturnType()).getName());
      }

      // Convince R8 we only use subtypes to get class merging of Foo into FooImpl.
      Foo<String> foo = new FooImpl<>();
      System.out.println(foo.getClass().getCanonicalName());
    }
  }

  interface Service {
    Foo<String> fooList();
  }

  interface Foo<T> {}

  public static class FooImpl<T> implements Foo<T> {}
}
