// 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;

import static junit.framework.Assert.assertNull;
import static junit.framework.TestCase.assertTrue;

import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidAppConsumers;
import com.android.tools.r8.utils.ConsumerUtils;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;

public class L8TestBuilder {

  private final AndroidApiLevel apiLevel;
  private final TestState state;

  private CompilationMode mode = CompilationMode.RELEASE;
  private String generatedKeepRules = null;
  private List<String> keepRules = new ArrayList<>();
  private List<Path> additionalProgramFiles = new ArrayList<>();
  private Consumer<InternalOptions> optionsModifier = ConsumerUtils.emptyConsumer();
  private Path desugarJDKLibs = ToolHelper.getDesugarJDKLibs();
  private Path desugarJDKLibsConfiguration = null;
  private StringResource desugaredLibraryConfiguration =
      StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting());
  private List<Path> libraryFiles = new ArrayList<>();

  private L8TestBuilder(AndroidApiLevel apiLevel, TestState state) {
    this.apiLevel = apiLevel;
    this.state = state;
  }

  public static L8TestBuilder create(AndroidApiLevel apiLevel, TestState state) {
    return new L8TestBuilder(apiLevel, state);
  }

  public L8TestBuilder addProgramFiles(Collection<Path> programFiles) {
    this.additionalProgramFiles.addAll(programFiles);
    return this;
  }

  public L8TestBuilder addLibraryFiles(Path... libraryFiles) {
    Collections.addAll(this.libraryFiles, libraryFiles);
    return this;
  }

  public L8TestBuilder addGeneratedKeepRules(String generatedKeepRules) {
    assertNull(this.generatedKeepRules);
    this.generatedKeepRules = generatedKeepRules;
    return this;
  }

  public L8TestBuilder addKeepRuleFile(Path keepRuleFile) throws IOException {
    this.keepRules.add(FileUtils.readTextFile(keepRuleFile, StandardCharsets.UTF_8));
    return this;
  }

  public L8TestBuilder addKeepRuleFiles(Collection<Path> keepRuleFiles) throws IOException {
    for (Path keepRuleFile : keepRuleFiles) {
      addKeepRuleFile(keepRuleFile);
    }
    return this;
  }

  public L8TestBuilder addOptionsModifier(Consumer<InternalOptions> optionsModifier) {
    this.optionsModifier = this.optionsModifier.andThen(optionsModifier);
    return this;
  }

  public L8TestBuilder applyIf(boolean condition, ThrowableConsumer<L8TestBuilder> thenConsumer) {
    return applyIf(condition, thenConsumer, ThrowableConsumer.empty());
  }

  public L8TestBuilder applyIf(
      boolean condition,
      ThrowableConsumer<L8TestBuilder> thenConsumer,
      ThrowableConsumer<L8TestBuilder> elseConsumer) {
    if (condition) {
      thenConsumer.acceptWithRuntimeException(this);
    } else {
      elseConsumer.acceptWithRuntimeException(this);
    }
    return this;
  }

  public L8TestBuilder setDebug() {
    this.mode = CompilationMode.DEBUG;
    return this;
  }

  public L8TestBuilder setDesugarJDKLibs(Path desugarJDKLibs) {
    this.desugarJDKLibs = desugarJDKLibs;
    return this;
  }

  public L8TestBuilder setDesugarJDKLibsConfiguration(Path desugarJDKLibsConfiguration) {
    this.desugarJDKLibsConfiguration = desugarJDKLibsConfiguration;
    return this;
  }

  public L8TestBuilder setDesugaredLibraryConfiguration(Path path) {
    this.desugaredLibraryConfiguration = StringResource.fromFile(path);
    return this;
  }

  public L8TestBuilder setDisableL8AnnotationRemoval(boolean disableL8AnnotationRemoval) {
    return addOptionsModifier(
        options -> options.testing.disableL8AnnotationRemoval = disableL8AnnotationRemoval);
  }

  public L8TestCompileResult compile()
      throws IOException, CompilationFailedException, ExecutionException {
    // We wrap exceptions in a RuntimeException to call this from a lambda.
    AndroidAppConsumers sink = new AndroidAppConsumers();
    L8Command.Builder l8Builder =
        L8Command.builder(state.getDiagnosticsHandler())
            .addProgramFiles(getProgramFiles())
            .addLibraryFiles(getLibraryFiles())
            .setMode(mode)
            .addDesugaredLibraryConfiguration(desugaredLibraryConfiguration)
            .setMinApiLevel(apiLevel.getLevel())
            .setProgramConsumer(sink.wrapProgramConsumer(DexIndexedConsumer.emptyConsumer()));
    Path mapping = null;
    if (!keepRules.isEmpty() || generatedKeepRules != null) {
      mapping = state.getNewTempFile("mapping.txt");
      l8Builder
          .addProguardConfiguration(
              ImmutableList.<String>builder()
                  .addAll(keepRules)
                  .addAll(
                      generatedKeepRules != null
                          ? ImmutableList.of(generatedKeepRules)
                          : Collections.emptyList())
                  .build(),
              Origin.unknown())
          .setProguardMapOutputPath(mapping);
    }
    ToolHelper.runL8(l8Builder.build(), optionsModifier);
    return new L8TestCompileResult(sink.build(), apiLevel, generatedKeepRules, mapping, state)
        .inspect(
            inspector ->
                inspector.forAllClasses(
                    clazz -> assertTrue(clazz.getFinalName().startsWith("j$."))));
  }

  private Collection<Path> getProgramFiles() {
    ImmutableList.Builder<Path> builder = ImmutableList.<Path>builder().add(desugarJDKLibs);
    if (desugarJDKLibsConfiguration != null) {
      builder.add(desugarJDKLibsConfiguration);
    }
    return builder.addAll(additionalProgramFiles).build();
  }

  private Collection<Path> getLibraryFiles() {
    return libraryFiles;
  }
}
