// Copyright 2019 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.analysis.skylark;

import static com.google.devtools.build.lib.analysis.skylark.FunctionTransitionUtil.COMMAND_LINE_OPTION_PREFIX;
import static com.google.devtools.build.lib.packages.RuleClass.Builder.SKYLARK_BUILD_SETTING_DEFAULT_ATTR_NAME;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.config.StarlarkDefinedConfigTransition;
import com.google.devtools.build.lib.analysis.config.transitions.ComposingTransition;
import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.events.ExtendedEventHandler;
import com.google.devtools.build.lib.packages.NoSuchTargetException;
import com.google.devtools.build.lib.packages.Package;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.skyframe.PackageValue;
import com.google.devtools.build.lib.syntax.Type.ConversionException;
import com.google.devtools.build.skyframe.SkyFunction.Environment;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/** A marker class for configuration transitions that are defined in Starlark. */
public abstract class StarlarkTransition implements ConfigurationTransition {

  /** The two groups of build settings that are relevant for a {@link StarlarkTransition} */
  public enum Settings {
    /** Build settings that are read by a {@link StarlarkTransition} */
    INPUTS,
    /** Build settings that are written by a {@link StarlarkTransition} */
    OUTPUTS,
  }

  private final StarlarkDefinedConfigTransition starlarkDefinedConfigTransition;

  public StarlarkTransition(StarlarkDefinedConfigTransition starlarkDefinedConfigTransition) {
    this.starlarkDefinedConfigTransition = starlarkDefinedConfigTransition;
  }

  public void replayOn(ExtendedEventHandler eventHandler) {
    starlarkDefinedConfigTransition.getEventHandler().replayOn(eventHandler);
    starlarkDefinedConfigTransition.getEventHandler().clear();
  }

  public boolean hasErrors() {
    return starlarkDefinedConfigTransition.getEventHandler().hasErrors();
  }

  private List<String> getInputs() {
    return starlarkDefinedConfigTransition.getInputs();
  }

  private List<String> getOutputs() {
    return starlarkDefinedConfigTransition.getOutputs();
  }

  /** Exception class for exceptions thrown during application of a starlark-defined transition */
  public static class TransitionException extends Exception {
    private final String message;

    public TransitionException(String message) {
      this.message = message;
    }

    public TransitionException(Throwable cause) {
      this.message = cause.getMessage();
    }

    /** Returns the error message. */
    @Override
    public String getMessage() {
      return message;
    }
  }

  /**
   * For a given transition, find all relevant Starlark-defined build settings. Then return all
   * package keys for those flags.
   *
   * <p>Currently this method does not handle the possibility of aliased build settings. We may not
   * actually load the package that actually contains the build setting but we won't know until we
   * fetch the actual target.
   *
   * @param root transition to inspect
   * @param inputsOrOutputs whether to return inputs or outputs
   */
  // TODO(juliexxia): handle the possibility of aliased build settings.
  public static ImmutableSet<SkyKey> getBuildSettingPackageKeys(
      ConfigurationTransition root, Settings inputsOrOutputs) {
    ImmutableSet.Builder<SkyKey> keyBuilder = new ImmutableSet.Builder<>();
    try {
      root.visit(
          (StarlarkTransitionVisitor)
              transition -> {
                keyBuilder.addAll(
                    getBuildSettingPackageKeys(
                        getRelevantStarlarkSettingsFromTransition(transition, inputsOrOutputs)));
              });
    } catch (TransitionException e) {
      // Not actually thrown in the visitor, but declared.
    }
    return keyBuilder.build();
  }

  private static ImmutableSet<SkyKey> getBuildSettingPackageKeys(
      ImmutableSet<Label> buildSettings) {
    ImmutableSet.Builder<SkyKey> keyBuilder = new ImmutableSet.Builder<>();
    for (Label setting : buildSettings) {
      keyBuilder.add(PackageValue.key(setting.getPackageIdentifier()));
    }
    return keyBuilder.build();
  }

  /**
   * Method to be called after Starlark-transitions are applied. Handles events and checks outputs.
   *
   * <p>Logs any events (e.g. {@code print()}s, errors} to output and throws an error if we had any
   * errors. Right now, Starlark transitions are the only kind that knows how to throw errors so we
   * know this will only report and throw if a Starlark transition caused a problem.
   *
   * <p>We only do validation on Starlark-defined build settings. Native options (designated with
   * {@code COMMAND_LINE_OPTION_PREFIX}) already have their output values checked in {@link
   * FunctionTransitionUtil#applyTransition}.
   *
   * <p>Remove build settings in {@code toOptions} that have been set to their default value. This
   * is how we ensure that an unset build setting and a set-to-default build settings represent the
   * same configuration.
   *
   * @param root transition that was applied. Likely a {@link ComposingTransition} so we decompose
   *     and post-process all StarlarkTransitions out of whatever transition is passed here.
   * @param buildSettingPackages SkyKeys/Values of packages that contain all Starlark-defined build
   *     settings that were set by {@code root}
   * @param toOptions result of applying {@code root}
   * @return validated toOptions with default values filtered out
   * @throws TransitionException if an error occurred during Starlark transition application.
   */
  // TODO(juliexxia): the current implementation masks certain bad transitions and only checks the
  // final result. I.e. if a transition that writes a non int --//int-build-setting is composed
  // with another transition that writes --//int-build-setting (without reading it first), then
  // the bad output of transition 1 is masked.
  public static List<BuildOptions> validate(
      ConfigurationTransition root,
      Map<SkyKey, SkyValue> buildSettingPackages,
      List<BuildOptions> toOptions)
      throws TransitionException {
    // collect settings changed during this transition and their types
    Map<Label, Rule> changedSettingToRule = Maps.newHashMap();
    root.visit(
        (StarlarkTransitionVisitor)
            transition -> {
              ImmutableSet<Label> changedSettings =
                  getRelevantStarlarkSettingsFromTransition(transition, Settings.OUTPUTS);
              for (Label setting : changedSettings) {
                Target buildSettingTarget =
                    getAndCheckBuildSettingTarget(buildSettingPackages, setting);
                changedSettingToRule.put(setting, buildSettingTarget.getAssociatedRule());
              }
            });

    // verify changed settings were changed to something reasonable for their type and filter out
    // default values.
    Set<BuildOptions> cleanedOptionList = new LinkedHashSet<>(toOptions.size());
    for (BuildOptions options : toOptions) {
      BuildOptions.Builder cleanedOptions = options.toBuilder();
      boolean cleaned = false;
      for (Map.Entry<Label, Rule> changedSettingWithRule : changedSettingToRule.entrySet()) {
        Label setting = changedSettingWithRule.getKey();
        Rule rule = changedSettingWithRule.getValue();
        Object newValue = options.getStarlarkOptions().get(setting);
        Object convertedValue;
        try {
          convertedValue =
              rule.getRuleClassObject().getBuildSetting().getType().convert(newValue, setting);
        } catch (ConversionException e) {
          throw new TransitionException(e);
        }
        if (convertedValue.equals(
            rule.getAttributeContainer().getAttr(SKYLARK_BUILD_SETTING_DEFAULT_ATTR_NAME))) {
          cleanedOptions.removeStarlarkOption(setting);
          cleaned = true;
        }
      }
      // Keep the same instance if we didn't do anything to maintain reference equality later on.
      cleanedOptionList.add(cleaned ? cleanedOptions.build() : options);
    }
    return ImmutableList.copyOf(cleanedOptionList);
  }

  /**
   * For a given transition, find all Starlark build settings that are read while applying it, then
   * return a map of their label to their default values.
   */
  public static ImmutableMap<Label, Object> getDefaultInputValues(
      Environment env, ConfigurationTransition root)
      throws TransitionException, InterruptedException {
    ImmutableSet<SkyKey> buildSettingInputPackageKeys =
        getBuildSettingPackageKeys(root, Settings.INPUTS);
    Map<SkyKey, SkyValue> buildSettingPackages = env.getValues(buildSettingInputPackageKeys);
    if (env.valuesMissing()) {
      return null;
    }
    return getDefaultInputValues(buildSettingPackages, root);
  }

  /**
   * For a given transition, find all Starlark build settings that are read while applying it, then
   * return a map of their label to their default values.
   */
  public static ImmutableMap<Label, Object> getDefaultInputValues(
      Map<SkyKey, SkyValue> buildSettingPackages, ConfigurationTransition root)
      throws TransitionException {
    ImmutableMap.Builder<Label, Object> defaultValues = new ImmutableMap.Builder<>();
    root.visit(
        (StarlarkTransitionVisitor)
            transition -> {
              ImmutableSet<Label> settings =
                  getRelevantStarlarkSettingsFromTransition(transition, Settings.INPUTS);
              for (Label setting : settings) {
                Target buildSettingTarget =
                    getAndCheckBuildSettingTarget(buildSettingPackages, setting);
                defaultValues.put(
                    setting,
                    buildSettingTarget
                        .getAssociatedRule()
                        .getAttributeContainer()
                        .getAttr(SKYLARK_BUILD_SETTING_DEFAULT_ATTR_NAME));
              }
            });
    return defaultValues.build();
  }

  private static Target getAndCheckBuildSettingTarget(
      Map<SkyKey, SkyValue> buildSettingPackages, Label setting) throws TransitionException {
    Package buildSettingPackage =
        ((PackageValue) buildSettingPackages.get(PackageValue.key(setting.getPackageIdentifier())))
            .getPackage();
    Preconditions.checkNotNull(
        buildSettingPackage, "Reading build setting for which we don't have a package");
    Target buildSettingTarget;
    try {
      buildSettingTarget = buildSettingPackage.getTarget(setting.getName());
    } catch (NoSuchTargetException e) {
      throw new TransitionException(e);
    }
    if (buildSettingTarget.getAssociatedRule() == null
        || buildSettingTarget.getAssociatedRule().getRuleClassObject().getBuildSetting() == null) {
      throw new TransitionException(
          String.format("attempting to transition on '%s' which is not a build setting", setting));
    }
    return buildSettingTarget;
  }

  // TODO(juliexxia): use an enum for "inputs"/"outputs" here and elsewhere in starlark transitions.
  private static ImmutableSet<Label> getRelevantStarlarkSettingsFromTransition(
      StarlarkTransition transition, Settings inputOrOutput) {
    List<String> toGet =
        inputOrOutput.equals(Settings.INPUTS) ? transition.getInputs() : transition.getOutputs();
    return ImmutableSet.copyOf(
        toGet.stream()
            .filter(setting -> !setting.startsWith(COMMAND_LINE_OPTION_PREFIX))
            .map(Label::parseAbsoluteUnchecked)
            .collect(Collectors.toSet()));
  }

  /**
   * For a given transition, for any Starlark-defined transitions that compose it, replay events. If
   * any events were errors, throw an error.
   */
  public static void replayEvents(ExtendedEventHandler eventHandler, ConfigurationTransition root)
      throws TransitionException {
    root.visit(
        (StarlarkTransitionVisitor)
            transition -> {
              // Replay events and errors and throw if there were errors
              boolean hasErrors = transition.hasErrors();
              transition.replayOn(eventHandler);
              if (hasErrors) {
                throw new TransitionException(
                    "Errors encountered while applying Starlark transition");
              }
            });
  }

  @Override
  public boolean equals(Object object) {
    if (object == this) {
      return true;
    }
    if (object instanceof StarlarkTransition) {
      StarlarkDefinedConfigTransition starlarkDefinedConfigTransition =
          ((StarlarkTransition) object).starlarkDefinedConfigTransition;
      return Objects.equals(starlarkDefinedConfigTransition, this.starlarkDefinedConfigTransition);
    }
    return false;
  }

  @Override
  public int hashCode() {
    return Objects.hashCode(starlarkDefinedConfigTransition);
  }

  @FunctionalInterface
  // This is only used in this class to handle the cast and the exception
  @SuppressWarnings("FunctionalInterfaceMethodChanged")
  private interface StarlarkTransitionVisitor
      extends ConfigurationTransition.Visitor<TransitionException> {
    @Override
    default void accept(ConfigurationTransition transition) throws TransitionException {
      if (transition instanceof StarlarkTransition) {
        this.accept((StarlarkTransition) transition);
      }
    }

    void accept(StarlarkTransition transition) throws TransitionException;
  }
}
