// Copyright 2014 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.buildtool;

import static com.google.common.collect.ImmutableSet.toImmutableSet;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.ConfiguredAspect;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.FileProvider;
import com.google.devtools.build.lib.analysis.OutputGroupInfo;
import com.google.devtools.build.lib.analysis.ProviderCollection;
import com.google.devtools.build.lib.analysis.TopLevelArtifactContext;
import com.google.devtools.build.lib.analysis.TopLevelArtifactHelper;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.configuredtargets.OutputFileConfiguredTarget;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.exec.ExecutionOptions;
import com.google.devtools.build.lib.runtime.BlazeRuntime;
import com.google.devtools.build.lib.runtime.CommandEnvironment;
import com.google.devtools.build.lib.skyframe.AspectKeyCreator.AspectKey;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
import com.google.devtools.build.lib.util.io.OutErr;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;

/**
 * Handles --show_result and --experimental_show_artifacts.
 */
class BuildResultPrinter {
  private final CommandEnvironment env;

  BuildResultPrinter(CommandEnvironment env) {
    this.env = env;
  }

  /**
   * Shows the result of the build. Information includes the list of up-to-date and failed targets
   * and list of output artifacts for successful targets
   *
   * <p>This corresponds to the --show_result flag.
   */
  void showBuildResult(
      BuildRequest request,
      BuildResult result,
      Collection<ConfiguredTarget> configuredTargets,
      Collection<ConfiguredTarget> configuredTargetsToSkip,
      ImmutableMap<AspectKey, ConfiguredAspect> aspects) {
    // NOTE: be careful what you print!  We don't want to create a consistency
    // problem where the summary message and the exit code disagree.  The logic
    // here is already complex.
    boolean ok =
        outputTargets(request, result, configuredTargets, configuredTargetsToSkip, aspects);
    if (!ok && !request.getOptions(ExecutionOptions.class).verboseFailures) {
      request
          .getOutErr()
          .printErr("Use --verbose_failures to see the command lines of failed build steps.\n");
    }
  }

  /**
   * Outputs the targets, omitting values with {@code (nothing to build)} when it allows staying
   * under the --show_result limit.
   *
   * <p>This method exits early if there are too many results.
   *
   * @return {@code true} if no errors were detected among the results inspected, this can be a
   *     false positive on early exit.
   */
  private boolean outputTargets(
      BuildRequest request,
      BuildResult result,
      Collection<ConfiguredTarget> configuredTargets,
      Collection<ConfiguredTarget> configuredTargetsToSkip,
      ImmutableMap<AspectKey, ConfiguredAspect> aspects) {
    BlazeRuntime runtime = env.getRuntime();
    String productName = runtime.getProductName();
    PathPrettyPrinter prettyPrinter =
        OutputDirectoryLinksUtils.getPathPrettyPrinter(
            runtime.getRuleClassProvider().getSymlinkDefinitions(),
            request.getBuildOptions().getSymlinkPrefix(productName),
            productName,
            env.getWorkspace());
    OutErr outErr = request.getOutErr();

    // Splits aspects based on whether they are validation aspects.
    final ImmutableSet<AspectKey> aspectsToPrint;
    final ImmutableList<AspectKey> validationAspects;
    if (request.useValidationAspect()) {
      var aspectsToPrintBuilder = ImmutableSet.<AspectKey>builder();
      var validationAspectsBuilder = ImmutableList.<AspectKey>builder();
      for (AspectKey key : aspects.keySet()) {
        if (Objects.equals(key.getAspectClass().getName(), BuildRequest.VALIDATION_ASPECT_NAME)) {
          validationAspectsBuilder.add(key);
        } else {
          aspectsToPrintBuilder.add(key);
        }
      }
      aspectsToPrint = aspectsToPrintBuilder.build();
      validationAspects = validationAspectsBuilder.build();
    } else {
      aspectsToPrint = aspects.keySet();
      validationAspects = ImmutableList.of();
    }

    Collection<ConfiguredTarget> targetsToPrint = filterTargetsToPrint(configuredTargets);
    TopLevelArtifactContext context = request.getTopLevelArtifactContext();

    // `essentialBudget` tracks the number of non-empty results that can be printed.
    int essentialBudget = request.getBuildOptions().maxResultTargets;

    // Splits the targets we care about into three buckets. Targets are only considered successful
    // if they and their validation aspects succeeded.
    var skipped = new ArrayList<ConfiguredTarget>();
    var succeeded = new ArrayList<ConfiguredTarget>();
    var artifactsToPrintPerTarget = new ArrayList<ArrayList<Artifact>>();
    var failed = new ArrayList<ConfiguredTarget>();
    essentialBudget =
        splitConfiguredTargetsByResultReturnRemaining(
            targetsToPrint,
            result,
            context,
            configuredTargetsToSkip,
            validationAspects,
            skipped,
            succeeded,
            artifactsToPrintPerTarget,
            failed,
            essentialBudget);
    if (essentialBudget < 0) {
      return failed.isEmpty();
    }

    // Splits the aspects we care about into two buckets.
    var successfulAspects = new ArrayList<AspectKey>();
    var failedAspects = new ArrayList<AspectKey>();
    var artifactsToPrintPerAspect = new ArrayList<ArrayList<Artifact>>(successfulAspects.size());
    essentialBudget =
        splitAspectsByResultReturnRemaining(
            aspectsToPrint,
            aspects,
            context,
            result.getSuccessfulAspects(),
            successfulAspects,
            artifactsToPrintPerAspect,
            failedAspects,
            essentialBudget);
    if (essentialBudget < 0) {
      return failed.isEmpty() && failedAspects.isEmpty();
    }

    // Omits "nothing to build" values if it enables staying under --show_result.
    boolean omitNothingToBuild =
        (targetsToPrint.size() + aspectsToPrint.size())
            > request.getBuildOptions().maxResultTargets;

    outputConfiguredTargets(
        outErr,
        prettyPrinter,
        succeeded,
        artifactsToPrintPerTarget,
        failed,
        skipped,
        omitNothingToBuild);
    outputAspects(
        outErr,
        prettyPrinter,
        successfulAspects,
        artifactsToPrintPerAspect,
        failedAspects,
        omitNothingToBuild);

    return failed.isEmpty() && failedAspects.isEmpty();
  }

  private static int splitConfiguredTargetsByResultReturnRemaining(
      Collection<ConfiguredTarget> configuredTargets,
      BuildResult result,
      TopLevelArtifactContext context,
      Collection<ConfiguredTarget> configuredTargetsToSkip,
      ImmutableList<AspectKey> validationAspects,
      ArrayList<ConfiguredTarget> skipped,
      ArrayList<ConfiguredTarget> succeeded,
      ArrayList<ArrayList<Artifact>> artifactsToPrintPerTarget,
      ArrayList<ConfiguredTarget> failed,
      int essentialBudget) {
    ImmutableSet<ConfiguredTargetKey> validationFailures =
        validationAspects.stream()
            .filter(k -> !result.getSuccessfulAspects().contains(k))
            .map(AspectKey::getBaseConfiguredTargetKey)
            .collect(toImmutableSet());
    Collection<ConfiguredTarget> successfulTargets = result.getSuccessfulTargets();
    for (ConfiguredTarget target : configuredTargets) {
      if (configuredTargetsToSkip.contains(target)) {
        skipped.add(target);
        if (--essentialBudget < 0) {
          return essentialBudget;
        }
      } else if (successfulTargets.contains(target)
          && !validationFailures.contains(ConfiguredTargetKey.fromConfiguredTarget(target))) {
        succeeded.add(target);
        ArrayList<Artifact> artifactsToPrint = getArtifactsToPrint(target, context);
        artifactsToPrintPerTarget.add(artifactsToPrint);
        if (!artifactsToPrint.isEmpty()) {
          if (--essentialBudget < 0) {
            return essentialBudget;
          }
        }
      } else {
        failed.add(target);
        if (--essentialBudget < 0) {
          return essentialBudget;
        }
      }
    }
    return essentialBudget;
  }

  private static ArrayList<Artifact> getArtifactsToPrint(
      ProviderCollection target, TopLevelArtifactContext context) {
    var artifacts = new ArrayList<Artifact>();
    // For up-to-date targets report generated artifacts, but only if they have associated action
    // and not middleman artifacts.
    for (Artifact artifact :
        TopLevelArtifactHelper.getAllArtifactsToBuild(target, context)
            .getImportantArtifacts()
            .toList()) {
      if (TopLevelArtifactHelper.shouldDisplay(artifact)) {
        artifacts.add(artifact);
      }
    }
    return artifacts;
  }

  private static int splitAspectsByResultReturnRemaining(
      Collection<AspectKey> aspectsToPrint,
      ImmutableMap<AspectKey, ConfiguredAspect> aspects,
      TopLevelArtifactContext context,
      ImmutableSet<AspectKey> successfulAspects,
      ArrayList<AspectKey> succeeded,
      ArrayList<ArrayList<Artifact>> artifactsToPrintPerAspect,
      ArrayList<AspectKey> failed,
      int essentialBudget) {
    for (AspectKey aspect : aspectsToPrint) {
      if (successfulAspects.contains(aspect)) {
        succeeded.add(aspect);
        ArrayList<Artifact> artifactsToPrint = getArtifactsToPrint(aspects.get(aspect), context);
        artifactsToPrintPerAspect.add(artifactsToPrint);
        if (!artifactsToPrint.isEmpty()) {
          if (--essentialBudget < 0) {
            return essentialBudget;
          }
        }
      } else {
        failed.add(aspect);
        if (--essentialBudget < 0) {
          return essentialBudget;
        }
      }
    }
    return essentialBudget;
  }

  private static void outputConfiguredTargets(
      OutErr outErr,
      PathPrettyPrinter prettyPrinter,
      ArrayList<ConfiguredTarget> succeeded,
      ArrayList<ArrayList<Artifact>> artifactsToPrintPerTarget,
      ArrayList<ConfiguredTarget> failed,
      ArrayList<ConfiguredTarget> skipped,
      boolean omitNothingToBuild) {
    for (ConfiguredTarget target : skipped) {
      outErr.printErr("Target " + target.getLabel() + " was skipped\n");
    }
    for (int i = 0; i < succeeded.size(); ++i) {
      ConfiguredTarget target = succeeded.get(i);
      Label label = target.getLabel();
      ArrayList<Artifact> artifacts = artifactsToPrintPerTarget.get(i);
      if (artifacts.isEmpty()) {
        if (!omitNothingToBuild) {
          outErr.printErr("Target " + label + " up-to-date (nothing to build)\n");
        }
        continue;
      }
      outErr.printErr("Target " + label + " up-to-date:\n");
      for (Artifact artifact : artifacts) {
        outErr.printErrLn(formatArtifactForShowResults(prettyPrinter, artifact));
      }
    }
    for (ConfiguredTarget target : failed) {
      outErr.printErr("Target " + target.getLabel() + " failed to build\n");

      // For failed compilation, it is still useful to examine temp artifacts, (ie, preprocessed and
      // assembler files).
      OutputGroupInfo topLevelProvider = OutputGroupInfo.get(target);
      if (topLevelProvider != null) {
        for (Artifact temp : topLevelProvider.getOutputGroup(OutputGroupInfo.TEMP_FILES).toList()) {
          if (temp.getPath().exists()) {
            outErr.printErrLn(
                "  See temp at " + prettyPrinter.getPrettyPath(temp.getPath().asFragment()));
          }
        }
      }
    }
  }

  private static void outputAspects(
      OutErr outErr,
      PathPrettyPrinter prettyPrinter,
      ArrayList<AspectKey> succeeded,
      ArrayList<ArrayList<Artifact>> artifactsToPrintPerAspect,
      ArrayList<AspectKey> failed,
      boolean omitNothingToBuild) {
    for (int i = 0; i < succeeded.size(); ++i) {
      AspectKey aspect = succeeded.get(i);
      Label label = aspect.getLabel();
      String aspectName = aspect.getAspectClass().getName();
      ArrayList<Artifact> artifacts = artifactsToPrintPerAspect.get(i);
      if (artifacts.isEmpty()) {
        if (!omitNothingToBuild) {
          outErr.printErr(
              "Aspect " + aspectName + " of " + label + " up-to-date (nothing to build)\n");
        }
        continue;
      }
      outErr.printErr("Aspect " + aspectName + " of " + label + " up-to-date:\n");
      for (Artifact artifact : artifacts) {
        outErr.printErrLn(formatArtifactForShowResults(prettyPrinter, artifact));
      }
    }
    for (AspectKey aspect : failed) {
      Label label = aspect.getLabel();
      String aspectName = aspect.getAspectClass().getName();
      outErr.printErr("Aspect " + aspectName + " of " + label + " failed to build\n");
    }
  }

  private static String formatArtifactForShowResults(
      PathPrettyPrinter prettyPrinter, Artifact artifact) {
    return "  " + prettyPrinter.getPrettyPath(artifact.getPath().asFragment());
  }

  /**
   * Returns a list of configured targets that should participate in printing.
   *
   * <p>Hidden rules and other inserted targets are ignored.
   */
  private Collection<ConfiguredTarget> filterTargetsToPrint(
      Collection<ConfiguredTarget> configuredTargets) {
    ImmutableList.Builder<ConfiguredTarget> result = ImmutableList.builder();
    for (ConfiguredTarget configuredTarget : configuredTargets) {
      if (!TopLevelArtifactHelper.shouldConsiderForDisplay(configuredTarget)) {
        continue;
      }
      if (configuredTarget instanceof OutputFileConfiguredTarget) {
        // Suppress display of generated files (because they appear underneath
        // their generating rule), EXCEPT those ones which are not part of the
        // filesToBuild of their generating rule (e.g. .par, _deploy.jar
        // files), OR when a user explicitly requests an output file but not
        // its rule.
        TransitiveInfoCollection generatingRule =
            ((OutputFileConfiguredTarget) configuredTarget).getGeneratingRule();
        if (generatingRule
                .getProvider(FileProvider.class)
                .getFilesToBuild()
                .toSet()
                .containsAll(
                    configuredTarget.getProvider(FileProvider.class).getFilesToBuild().toList())
            && configuredTargets.contains(generatingRule)) {
          continue;
        }
      }

      result.add(configuredTarget);
    }
    return result.build();
  }
}
