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

import static com.android.tools.r8.ToolHelper.isLocalDevelopment;
import static com.android.tools.r8.ToolHelper.shouldRunSlowTests;
import static com.android.tools.r8.internal.proto.ProtoShrinkingTestBase.assertRewrittenProtoSchemasMatch;
import static com.android.tools.r8.internal.proto.ProtoShrinkingTestBase.keepAllProtosRule;
import static com.android.tools.r8.internal.proto.ProtoShrinkingTestBase.keepDynamicMethodSignatureRule;
import static com.android.tools.r8.internal.proto.ProtoShrinkingTestBase.keepNewMessageInfoSignatureRule;
import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;

import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.L8TestCompileResult;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.ResourceException;
import com.android.tools.r8.StringConsumer;
import com.android.tools.r8.StringResource;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ThrowableConsumer;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.ExecutionException;
import org.junit.After;
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 YouTubeV1620Test extends YouTubeCompilationTestBase {

  private static final int MAX_APPLICATION_SIZE = 29750000;
  private static final int MAX_DESUGARED_LIBRARY_SIZE = 425000;

  private final TestParameters parameters;

  private final Path dumpDirectory = Paths.get("YouTubeV1620-" + System.currentTimeMillis());
  private final Reporter reporter = new Reporter();

  @Parameters(name = "{0}")
  public static TestParametersCollection data() {
    return getTestParameters()
        .withDexRuntime(Version.V9_0_0)
        .withApiLevel(AndroidApiLevel.L)
        .build();
  }

  public YouTubeV1620Test(TestParameters parameters) {
    super(16, 20, parameters.getApiLevel());
    this.parameters = parameters;
  }

  @Test
  public void test() throws Exception {
    assumeTrue(isLocalDevelopment());
    assumeTrue(shouldRunSlowTests());

    KeepRuleConsumer keepRuleConsumer = new PresentKeepRuleConsumer();
    R8TestCompileResult r8CompileResult = compileApplicationWithR8(keepRuleConsumer);
    L8TestCompileResult l8CompileResult = compileDesugaredLibraryWithL8(keepRuleConsumer);

    inspect(r8CompileResult, l8CompileResult);

    if (isLocalDevelopment()) {
      dump(r8CompileResult, l8CompileResult);
    }
  }

  @Test
  public void testProtoRewriting() throws Exception {
    assumeTrue(shouldRunSlowTests());

    StringConsumer keepRuleConsumer = StringConsumer.emptyConsumer();
    R8TestCompileResult r8CompileResult =
        compileApplicationWithR8(
            keepRuleConsumer,
            builder ->
                builder
                    .addKeepRules(
                        keepAllProtosRule(),
                        keepDynamicMethodSignatureRule(),
                        keepNewMessageInfoSignatureRule())
                    .allowCheckDiscardedErrors(true));
    assertRewrittenProtoSchemasMatch(
        new CodeInspector(getProgramFiles()), r8CompileResult.inspector());
  }

  @After
  public void teardown() {
    reporter.failIfPendingErrors();
  }

  private R8TestCompileResult compileApplicationWithR8(StringConsumer keepRuleConsumer)
      throws IOException, CompilationFailedException {
    return compileApplicationWithR8(keepRuleConsumer, ThrowableConsumer.empty());
  }

  private R8TestCompileResult compileApplicationWithR8(
      StringConsumer keepRuleConsumer, ThrowableConsumer<R8FullTestBuilder> configuration)
      throws IOException, CompilationFailedException {
    return testForR8(parameters.getBackend())
        .addProgramFiles(getProgramFiles())
        .addLibraryFiles(getLibraryFiles())
        .addKeepRuleFiles(getKeepRuleFiles())
        .addDontWarn("android.app.Activity$TranslucentConversionListener")
        .allowDiagnosticMessages()
        .allowUnusedDontWarnPatterns()
        .allowUnusedProguardConfigurationRules()
        .apply(configuration)
        .setMinApi(getApiLevel())
        .enableCoreLibraryDesugaring(
            getApiLevel(),
            keepRuleConsumer,
            StringResource.fromFile(getDesugaredLibraryConfiguration()))
        .compile()
        .assertAllInfoMessagesMatch(
            anyOf(
                containsString("Ignoring option: -optimizations"),
                containsString("Proguard configuration rule does not match anything"),
                containsString("Invalid signature")))
        .apply(this::printProtoStats);
  }

  private L8TestCompileResult compileDesugaredLibraryWithL8(KeepRuleConsumer keepRuleConsumer)
      throws CompilationFailedException, IOException, ExecutionException {
    return testForL8(getApiLevel())
        .setDesugaredLibraryConfiguration(getDesugaredLibraryConfiguration())
        .setDesugarJDKLibs(getDesugaredLibraryJDKLibs())
        .addGeneratedKeepRules(keepRuleConsumer.get())
        .addKeepRuleFiles(getDesugaredLibraryKeepRuleFiles())
        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
        .compile();
  }

  private void inspect(R8TestCompileResult r8CompileResult, L8TestCompileResult l8CompileResult)
      throws IOException, ResourceException {
    r8CompileResult.runDex2Oat(parameters.getRuntime()).assertNoVerificationErrors();
    l8CompileResult.runDex2Oat(parameters.getRuntime()).assertNoVerificationErrors();

    int applicationSize = r8CompileResult.getApp().applicationSize();
    if (applicationSize > MAX_APPLICATION_SIZE) {
      reporter.error(
          "Expected application size to be <="
              + MAX_APPLICATION_SIZE
              + ", but was "
              + applicationSize);
    }

    int desugaredLibrarySize = l8CompileResult.getApp().applicationSize();
    if (desugaredLibrarySize > MAX_DESUGARED_LIBRARY_SIZE) {
      reporter.error(
          "Expected desugared library size to be <="
              + MAX_DESUGARED_LIBRARY_SIZE
              + ", but was "
              + desugaredLibrarySize);
    }

    if (isLocalDevelopment()) {
      System.out.println("Dex size (application, excluding desugared library): " + applicationSize);
      System.out.println("Dex size (desugared library): " + desugaredLibrarySize);
      System.out.println("Dex size (total): " + (applicationSize + desugaredLibrarySize));
    }
  }

  private void dump(R8TestCompileResult r8CompileResult, L8TestCompileResult l8CompileResult)
      throws IOException {
    assertTrue(isLocalDevelopment());
    Files.createDirectories(dumpDirectory);
    r8CompileResult
        .writeToDirectory(dumpDirectory)
        .writeProguardMap(dumpDirectory.resolve("mapping.txt"));
    l8CompileResult
        .writeSingleDexOutputToFile(dumpDirectory.resolve("classes5.dex"))
        .writeGeneratedKeepRules(dumpDirectory.resolve("l8-keep.txt"))
        .writeProguardMap(dumpDirectory.resolve("l8-mapping.txt"));
  }
}
