// Copyright 2021 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.packages;

import static com.google.common.collect.ImmutableList.toImmutableList;

import com.google.common.base.Function;
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.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.SerializationConstant;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Objects;
import javax.annotation.Nullable;
import net.starlark.java.eval.EvalException;
import net.starlark.java.eval.Starlark;

/**
 * AspectsList represents the list of aspects specified via --aspects command line option or
 * declared in attribute aspects list. The class is responsible for wrapping the information
 * necessary for constructing those aspects.
 */
public final class AspectsList {
  private final ImmutableList<AspectDetails<?>> aspects;

  private AspectsList(ImmutableList<AspectDetails<?>> aspects) {
    this.aspects = aspects;
  }

  public boolean hasAspects() {
    return !aspects.isEmpty();
  }

  /** Returns the list of aspects required for dependencies through this attribute. */
  public ImmutableList<Aspect> getAspects(Rule rule) {
    if (aspects.isEmpty()) {
      return ImmutableList.of();
    }
    ImmutableList.Builder<Aspect> builder = null;
    for (AspectDetails<?> aspect : aspects) {
      Aspect a = aspect.getAspect(rule);
      if (a != null) {
        if (builder == null) {
          builder = ImmutableList.builder();
        }
        builder.add(a);
      }
    }
    return builder == null ? ImmutableList.of() : builder.build();
  }

  public ImmutableList<AspectClass> getAspectClasses() {
    ImmutableList.Builder<AspectClass> result = ImmutableList.builder();
    for (AspectDetails<?> aspect : aspects) {
      result.add(aspect.getAspectClass());
    }
    return result.build();
  }

  /** Returns a list of Aspect objects for top level aspects. */
  public ImmutableList<Aspect> buildAspects(ImmutableMap<String, String> aspectsParameters)
      throws EvalException {
    Preconditions.checkArgument(aspectsParameters != null, "aspectsParameters cannot be null");

    ImmutableList.Builder<Aspect> aspectsList = ImmutableList.builder();
    for (AspectDetails<?> aspect : aspects) {
      aspectsList.add(aspect.getTopLevelAspect(aspectsParameters));
    }
    return aspectsList.build();
  }

  public void validateRulePropagatedAspectsParameters(RuleClass ruleClass) throws EvalException {
    for (AspectDetails<?> aspect : aspects) {
      ImmutableSet<String> requiredAspectParameters = aspect.getRequiredParameters();
      for (Attribute aspectAttribute : aspect.getAspectAttributes()) {
        String aspectAttrName = aspectAttribute.getPublicName();
        Type<?> aspectAttrType = aspectAttribute.getType();

        // When propagated from a rule, explicit aspect attributes must be of type boolean, int
        // or string. Integer and string attributes must have the `values` restriction.
        if (!aspectAttribute.isImplicit() && !aspectAttribute.isLateBound()) {
          if (aspectAttrType != Type.BOOLEAN && !aspectAttribute.checkAllowedValues()) {
            throw Starlark.errorf(
                "Aspect %s: Aspect parameter attribute '%s' must use the 'values' restriction.",
                aspect.getName(), aspectAttrName);
          }
        }

        // Required aspect parameters must be specified by the rule propagating the aspect with
        // the same parameter type.
        if (requiredAspectParameters.contains(aspectAttrName)) {
          if (!ruleClass.hasAttr(aspectAttrName, aspectAttrType)) {
            throw Starlark.errorf(
                "Aspect %s requires rule %s to specify attribute '%s' with type %s.",
                aspect.getName(), ruleClass.getName(), aspectAttrName, aspectAttrType);
          }
        }
      }
    }
  }

  /**
   * Validates top-level aspects parameters and reports error in the following cases:
   *
   * <p>If a parameter name is specified in command line but no aspect has a parameter with that
   * name.
   *
   * <p>If a mandatory aspect attribute is not given a value in the top-level parameters list.
   */
  public void validateTopLevelAspectsParameters(ImmutableMap<String, String> aspectsParameters)
      throws EvalException {
    Preconditions.checkArgument(aspectsParameters != null, "aspectsParameters cannot be null");

    ImmutableSet.Builder<String> usedParametersBuilder = ImmutableSet.builder();
    for (AspectDetails<?> aspectDetails : aspects) {
      if (aspectDetails instanceof StarlarkAspectDetails) {
        ImmutableList<Attribute> aspectAttributes =
            ((StarlarkAspectDetails) aspectDetails).aspect.getAttributes();
        for (Attribute attr : aspectAttributes) {
          if (attr.isImplicit() || attr.isLateBound()) {
            continue;
          }
          String attrName = attr.getName();
          if (aspectsParameters.containsKey(attrName)) {
            usedParametersBuilder.add(attrName);
          } else if (attr.isMandatory()) {
            throw Starlark.errorf(
                "Missing mandatory attribute '%s' for aspect '%s'.",
                attrName, aspectDetails.getName());
          }
        }
      }
    }
    ImmutableSet<String> usedParameters = usedParametersBuilder.build();
    ImmutableList<String> unusedParameters =
        aspectsParameters.keySet().stream()
            .filter(p -> !usedParameters.contains(p))
            .collect(toImmutableList());
    if (!unusedParameters.isEmpty()) {
      throw Starlark.errorf(
          "Parameters '%s' are not parameters of any of the top-level aspects but they are"
              + " specified in --aspects_parameters.",
          unusedParameters);
    }
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    AspectsList aspectsList = (AspectsList) o;
    return Objects.equals(aspects, aspectsList.aspects);
  }

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

  /** Wraps the information necessary to construct an Aspect. */
  private abstract static class AspectDetails<C extends AspectClass> {
    final C aspectClass;
    final Function<Rule, AspectParameters> parametersExtractor;
    final String requiredByAspect;

    private AspectDetails(C aspectClass, Function<Rule, AspectParameters> parametersExtractor) {
      this.aspectClass = aspectClass;
      this.parametersExtractor = parametersExtractor;
      this.requiredByAspect = null;
    }

    private AspectDetails(
        C aspectClass,
        Function<Rule, AspectParameters> parametersExtractor,
        String requiredByAspect) {
      this.aspectClass = aspectClass;
      this.parametersExtractor = parametersExtractor;
      this.requiredByAspect = requiredByAspect;
    }

    public String getName() {
      return this.aspectClass.getName();
    }

    public ImmutableSet<String> getRequiredParameters() {
      return ImmutableSet.of();
    }

    public ImmutableList<Attribute> getAspectAttributes() {
      return ImmutableList.of();
    }

    protected abstract Aspect getAspect(Rule rule);

    protected abstract Aspect getTopLevelAspect(ImmutableMap<String, String> aspectParameters)
        throws EvalException;

    C getAspectClass() {
      return aspectClass;
    }
  }

  private static class NativeAspectDetails extends AspectDetails<NativeAspectClass> {
    NativeAspectDetails(
        NativeAspectClass aspectClass, Function<Rule, AspectParameters> parametersExtractor) {
      super(aspectClass, parametersExtractor);
    }

    NativeAspectDetails(
        NativeAspectClass aspectClass,
        Function<Rule, AspectParameters> parametersExtractor,
        String requiredByAspect) {
      super(aspectClass, parametersExtractor, requiredByAspect);
    }

    @Nullable
    @Override
    public Aspect getAspect(Rule rule) {
      AspectParameters params = parametersExtractor.apply(rule);
      return params == null ? null : Aspect.forNative(aspectClass, params);
    }

    @Override
    protected Aspect getTopLevelAspect(ImmutableMap<String, String> aspectParameters)
        throws EvalException {
      // Native aspects ignore their top-level parameters values for now.
      return Aspect.forNative(aspectClass, AspectParameters.EMPTY);
    }
  }

  private static class StarlarkAspectDetails extends AspectDetails<StarlarkAspectClass> {
    private final StarlarkDefinedAspect aspect;

    private StarlarkAspectDetails(StarlarkDefinedAspect aspect, String requiredByAspect) {
      super(aspect.getAspectClass(), aspect.getDefaultParametersExtractor(), requiredByAspect);
      this.aspect = aspect;
    }

    @Override
    public ImmutableSet<String> getRequiredParameters() {
      return aspect.getParamAttributes();
    }

    @Override
    public ImmutableList<Attribute> getAspectAttributes() {
      return aspect.getAttributes();
    }

    @Override
    public Aspect getAspect(Rule rule) {
      AspectParameters params = parametersExtractor.apply(rule);
      return Aspect.forStarlark(aspectClass, aspect.getDefinition(params), params);
    }

    @Override
    public Aspect getTopLevelAspect(ImmutableMap<String, String> aspectParameters)
        throws EvalException {
      AspectParameters params = aspect.extractTopLevelParameters(aspectParameters);
      return Aspect.forStarlark(aspectClass, aspect.getDefinition(params), params);
    }
  }

  /** Aspect details that just wrap a pre-existing Aspect that doesn't vary with the Rule. */
  private static class PredefinedAspectDetails extends AspectDetails<AspectClass> {
    private final Aspect aspect;

    PredefinedAspectDetails(Aspect aspect) {
      super(aspect.getAspectClass(), null);
      this.aspect = aspect;
    }

    @Override
    public Aspect getAspect(Rule rule) {
      return aspect;
    }

    @Override
    public Aspect getTopLevelAspect(ImmutableMap<String, String> aspectParameters)
        throws EvalException {
      return aspect;
    }
  }

  @SerializationConstant @VisibleForSerialization
  static final Function<Rule, AspectParameters> EMPTY_FUNCTION = input -> AspectParameters.EMPTY;

  /** A builder for AspectsList */
  public static class Builder {
    private final HashMap<String, AspectDetails<?>> aspects = new LinkedHashMap<>();

    public Builder() {}

    public Builder(AspectsList aspectsList) {
      for (AspectDetails<?> aspect : aspectsList.aspects) {
        aspects.put(aspect.getName(), aspect);
      }
    }

    public AspectsList build() {
      return new AspectsList(ImmutableList.copyOf(aspects.values()));
    }

    /**
     * Adds a native aspect with its parameters extraction function to the aspects list.
     *
     * @param aspect the native aspect to be added
     * @param evaluator function that extracts aspect parameters from rule.
     */
    public void addAspect(NativeAspectClass aspect, Function<Rule, AspectParameters> evaluator) {
      NativeAspectDetails nativeAspectDetails = new NativeAspectDetails(aspect, evaluator);
      AspectDetails<?> oldAspect =
          this.aspects.put(nativeAspectDetails.getName(), nativeAspectDetails);
      if (oldAspect != null) {
        throw new AssertionError(
            String.format("Aspect %s has already been added", oldAspect.getName()));
      }
    }

    /**
     * Adds a native aspect that does not need a parameters extractor to the aspects list.
     *
     * @param aspect the native aspect to be added
     */
    public void addAspect(NativeAspectClass aspect) {
      addAspect(aspect, EMPTY_FUNCTION);
    }

    /** Attaches this aspect and its required aspects */
    public void addAspect(StarlarkAspect starlarkAspect) throws EvalException {
      addAspect(starlarkAspect, null);
    }

    private void addAspect(StarlarkAspect starlarkAspect, @Nullable String requiredByAspect)
        throws EvalException {
      if (starlarkAspect instanceof StarlarkDefinedAspect) {
        StarlarkDefinedAspect starlarkDefinedAspect = (StarlarkDefinedAspect) starlarkAspect;
        if (!starlarkDefinedAspect.isExported()) {
          throw Starlark.errorf(
              "Aspects should be top-level values in extension files that define them.");
        }

        for (StarlarkAspect requiredAspect : starlarkDefinedAspect.getRequiredAspects()) {
          addAspect(requiredAspect, starlarkDefinedAspect.getName());
        }
      }

      boolean needsToAdd = needsToBeAdded(starlarkAspect.getName(), requiredByAspect);
      if (needsToAdd) {
        final AspectDetails<?> aspectDetails;

        if (starlarkAspect instanceof StarlarkDefinedAspect) {
          aspectDetails =
              new StarlarkAspectDetails((StarlarkDefinedAspect) starlarkAspect, requiredByAspect);
        } else if (starlarkAspect instanceof StarlarkNativeAspect) {
          aspectDetails =
              new NativeAspectDetails(
                  (StarlarkNativeAspect) starlarkAspect,
                  starlarkAspect.getDefaultParametersExtractor(),
                  requiredByAspect);
        } else {
          throw new IllegalArgumentException();
        }
        this.aspects.put(starlarkAspect.getName(), aspectDetails);
      }
    }

    /** Should only be used for deserialization. */
    public void addAspect(final Aspect aspect) {
      PredefinedAspectDetails predefinedAspectDetails = new PredefinedAspectDetails(aspect);
      AspectDetails<?> oldAspect =
          this.aspects.put(predefinedAspectDetails.getName(), predefinedAspectDetails);
      if (oldAspect != null) {
        throw new AssertionError(
            String.format("Aspect %s has already been added", oldAspect.getName()));
      }
    }

    /**
     * Adds all aspect from the list.
     *
     * <p>The function is intended for extended Starlark rules, where aspect list is already built
     * and may include aspects required by other aspects.
     */
    public void addAspects(AspectsList aspectsList) throws EvalException {
      for (AspectDetails<?> aspect : aspectsList.aspects) {
        boolean needsToAdd = needsToBeAdded(aspect.getName(), aspect.requiredByAspect);
        if (needsToAdd) {
          aspects.put(aspect.getName(), aspect);
        }
      }
    }

    private boolean needsToBeAdded(String aspectName, @Nullable String requiredByAspect)
        throws EvalException {

      AspectDetails<?> oldAspect = this.aspects.get(aspectName);

      if (oldAspect != null) {
        if (requiredByAspect != null) {
          // If the aspect to be added already exists and it is required by another aspect, no need
          // to
          // add it again.
          return false;
        } else {
          // If the aspect to be added is not required by another aspect, then we should throw error
          String oldAspectBaseAspectName = oldAspect.requiredByAspect;
          if (oldAspectBaseAspectName != null) {
            throw Starlark.errorf(
                "aspect %s was added before as a required aspect of aspect %s",
                oldAspect.getName(), oldAspectBaseAspectName);
          }
          throw Starlark.errorf("aspect %s added more than once", oldAspect.getName());
        }
      }

      return true; // we need to add the new aspect
    }
  }
}
