// Copyright 2023 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.producers;


import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.ConfiguredTargetValue;
import com.google.devtools.build.lib.analysis.InconsistentNullConfigException;
import com.google.devtools.build.lib.analysis.TransitiveDependencyState;
import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
import com.google.devtools.build.lib.packages.NoSuchTargetException;
import com.google.devtools.build.lib.packages.NoSuchThingException;
import com.google.devtools.build.lib.packages.Package;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData;
import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
import com.google.devtools.build.lib.skyframe.ConfiguredValueCreationException;
import com.google.devtools.build.lib.skyframe.PackageValue;
import com.google.devtools.build.skyframe.SkyValue;
import com.google.devtools.build.skyframe.state.StateMachine;
import java.util.function.Consumer;
import javax.annotation.Nullable;

/**
 * Determines {@link ConfiguredTargetAndData} from {@link ConfiguredTargetKey}.
 *
 * <p>The resulting package and configuration are based on the resulting {@link ConfiguredTarget}
 * and may be different from what is in the key, for example, if there is an alias.
 */
public final class ConfiguredTargetAndDataProducer
    implements StateMachine,
        Consumer<SkyValue>,
        StateMachine.ValueOrException3Sink<
            ConfiguredValueCreationException,
            NoSuchThingException,
            InconsistentNullConfigException> {
  /** Interface for accepting values produced by this class. */
  public interface ResultSink {
    void acceptConfiguredTargetAndData(ConfiguredTargetAndData value, int index);

    void acceptConfiguredTargetAndDataError(ConfiguredValueCreationException error);

    void acceptConfiguredTargetAndDataError(NoSuchThingException error);

    void acceptConfiguredTargetAndDataError(InconsistentNullConfigException error);
  }

  // -------------------- Input --------------------
  private final ConfiguredTargetKey key;
  private final ImmutableList<String> transitionKeys;
  private final TransitiveDependencyState transitiveState;

  // -------------------- Output --------------------
  private final ResultSink sink;
  private final int outputIndex;

  // -------------------- Internal State --------------------
  private ConfiguredTarget configuredTarget;
  @Nullable // Null if the configured target key's configuration key is null.
  private BuildConfigurationValue configurationValue;
  private Package pkg;

  public ConfiguredTargetAndDataProducer(
      ConfiguredTargetKey key,
      ImmutableList<String> transitionKeys,
      TransitiveDependencyState transitiveState,
      ResultSink sink,
      int outputIndex) {
    this.key = key;
    this.transitionKeys = transitionKeys;
    this.transitiveState = transitiveState;
    this.sink = sink;
    this.outputIndex = outputIndex;
  }

  @Override
  public StateMachine step(Tasks tasks) {
    tasks.lookUp(
        key,
        ConfiguredValueCreationException.class,
        NoSuchThingException.class,
        InconsistentNullConfigException.class,
        (ValueOrException3Sink<
                ConfiguredValueCreationException,
                NoSuchThingException,
                InconsistentNullConfigException>)
            this);
    return this::fetchConfigurationAndPackage;
  }

  @Override
  public void acceptValueOrException3(
      @Nullable SkyValue value,
      @Nullable ConfiguredValueCreationException error,
      @Nullable NoSuchThingException missingTargetError,
      @Nullable InconsistentNullConfigException visibilityError) {
    if (value != null) {
      var configuredTargetValue = (ConfiguredTargetValue) value;
      this.configuredTarget = configuredTargetValue.getConfiguredTarget();
      if (transitiveState.storeTransitivePackages()) {
        transitiveState.updateTransitivePackages(
            ConfiguredTargetKey.fromConfiguredTarget(configuredTarget),
            configuredTargetValue.getTransitivePackages());
      }
      return;
    }
    if (error != null) {
      transitiveState.addTransitiveCauses(error.getRootCauses());
      sink.acceptConfiguredTargetAndDataError(error);
      return;
    }
    if (missingTargetError != null) {
      sink.acceptConfiguredTargetAndDataError(missingTargetError);
      return;
    }
    if (visibilityError != null) {
      sink.acceptConfiguredTargetAndDataError(visibilityError);
      return;
    }
    throw new IllegalArgumentException("both value and error were null");
  }

  private StateMachine fetchConfigurationAndPackage(Tasks tasks) throws InterruptedException {
    if (configuredTarget == null) {
      return DONE; // There was a previous error.
    }

    var configurationKey = configuredTarget.getConfigurationKey();
    if (configurationKey != null) {
      tasks.lookUp(configurationKey, (Consumer<SkyValue>) this);
    }

    // An alternative to this is to optimistically fetch the package using the label of the
    // configured target key. However, the actual package may differ when this is an
    // AliasConfiguredTarget and would need to be refetched.

    // TODO(shahan): This lookup should be skipped when the ConfiguredTarget is fetched remotely.
    var packageId = configuredTarget.getLabel().getPackageIdentifier();
    this.pkg = transitiveState.getDependencyPackage(packageId);
    if (pkg == null) {
      // In incremental builds, it is possible that the package won't be present in the cache. For
      // example, suppose that a configured target A has two children B and C. If B is dirty, it
      // causes A's re-evaluation, which causes this fetch to be performed for C. However, C has not
      // been evaluated this build.
      tasks.lookUp(packageId, (Consumer<SkyValue>) this);
    }

    return this::constructResult;
  }

  @Override
  public void accept(SkyValue value) {
    if (value instanceof BuildConfigurationValue) {
      this.configurationValue = (BuildConfigurationValue) value;
      return;
    }
    if (value instanceof PackageValue) {
      this.pkg = ((PackageValue) value).getPackage();
      return;
    }
    throw new IllegalArgumentException("unexpected value: " + value);
  }

  private StateMachine constructResult(Tasks tasks) {
    Target target;
    try {
      target = pkg.getTarget(configuredTarget.getLabel().getName());
    } catch (NoSuchTargetException e) {
      // The package was fetched based on the label of the configured target. Since the configured
      // target exists, it must have existed in the package when it was created.
      throw new IllegalStateException("Target already verified for " + configuredTarget, e);
    }
    sink.acceptConfiguredTargetAndData(
        new ConfiguredTargetAndData(configuredTarget, target, configurationValue, transitionKeys),
        outputIndex);
    return DONE;
  }
}
