/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file LICENSE.rst or https://cmake.org/licensing for details.  */

#include "cmFastbuildUtilityTargetGenerator.h"

#include <set>
#include <string>
#include <utility>
#include <vector>

#include "cmFastbuildTargetGenerator.h"
#include "cmGeneratorTarget.h"
#include "cmGlobalFastbuildGenerator.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmStateTypes.h"
#include "cmTarget.h"
#include "cmTargetDepend.h"

cmFastbuildUtilityTargetGenerator::cmFastbuildUtilityTargetGenerator(
  cmGeneratorTarget* gt, std::string configParam)
  : cmFastbuildTargetGenerator(gt, std::move(configParam))
{
}

void cmFastbuildUtilityTargetGenerator::Generate()
{
  std::string targetName = GeneratorTarget->GetName();

  if (this->GeneratorTarget->GetType() == cmStateEnums::GLOBAL_TARGET) {
    targetName = GetGlobalGenerator()->GetTargetName(GeneratorTarget);
  }

  FastbuildAliasNode fastbuildTarget;
  fastbuildTarget.Name = targetName;

  LogMessage("<-------------->");
  LogMessage("Generate Utility target: " + targetName);
  LogMessage("Config: " + Config);
  for (auto const& dep : TargetDirectDependencies) {
    LogMessage("Dep: " + dep->GetName());
  }

  std::vector<std::string> nonImportedUtils;
  for (BT<std::pair<std::string, bool>> const& util :
       this->GeneratorTarget->GetUtilities()) {
    if (util.Value.first == targetName) {
      continue;
    }
    auto const& utilTargetName =
      this->ConvertToFastbuildPath(util.Value.first);
    LogMessage("Util: " + utilTargetName);
    auto* const target = this->Makefile->FindTargetToUse(utilTargetName);
    if (target && target->IsImported()) {
      LogMessage("Skipping imported util target: " + utilTargetName);
      continue;
    }
    // Since interface target don't appear in the generated build files,
    // transitively propagate their deps (if any).
    // Tested in "ExternalProjectSubdir" test.
    if (target && target->GetType() == cmStateEnums::INTERFACE_LIBRARY) {
      for (auto const& dep : target->GetUtilities()) {
        auto const& depName = this->ConvertToFastbuildPath(dep.Value.first);
        LogMessage("Transitively propagating iface dep: " + depName +
                   ", is cross: " + std::to_string(dep.Value.second));
        nonImportedUtils.emplace_back(depName);
        fastbuildTarget.PreBuildDependencies.emplace(
          this->ConvertToFastbuildPath(depName));
      }
    } else {
      nonImportedUtils.emplace_back(utilTargetName);
      fastbuildTarget.PreBuildDependencies.emplace(utilTargetName);
    }
  }
  if (this->GetGlobalGenerator()->IsExcluded(this->GetGeneratorTarget())) {
    LogMessage("Excluding " + targetName + " from ALL");
    fastbuildTarget.ExcludeFromAll = true;
  }
  auto preBuild = GenerateCommands(FastbuildBuildStep::PRE_BUILD);

  // Tested in "RunCMake.CPack*" tests.
  // Utility target "package" has packaging steps as "POST_BUILD".
  for (auto& exec : GenerateCommands(FastbuildBuildStep::POST_BUILD).Nodes) {
    fastbuildTarget.PreBuildDependencies.emplace(exec.Name);
    for (std::string const& util : nonImportedUtils) {
      LogMessage("Adding: util " + util);
      exec.PreBuildDependencies.emplace(util);
    }
    // So POST_BUILD is executed AFTER PRE_BUILD (tested in "CustomCommand"
    // test).
    for (auto const& pre : preBuild.Nodes) {
      LogMessage("Adding: " + pre.Name);
      exec.PreBuildDependencies.emplace(pre.Name);
    }
    this->GetGlobalGenerator()->AddTarget(std::move(exec));
  }

  for (auto& exec : preBuild.Nodes) {
    LogMessage("Adding exec " + exec.Name);
    fastbuildTarget.PreBuildDependencies.emplace(exec.Name);
    this->GetGlobalGenerator()->AddTarget(std::move(exec));
  }

  for (auto& exec : GenerateCommands(FastbuildBuildStep::REST).Nodes) {
    fastbuildTarget.PreBuildDependencies.emplace(exec.Name);
    for (auto const& dep : TargetDirectDependencies) {
      LogMessage("Direct dep " + dep->GetName() +
                 "-all propagating to CC: " + exec.Name);
      // All custom commands from within the target must be executed AFTER all
      // the target's deps.
      FastbuildTargetDep execDep{ dep->GetName() };
      execDep.Type = FastbuildTargetDepType::ALL;
      exec.PreBuildDependencies.emplace(std::move(execDep));
    }
    this->GetGlobalGenerator()->AddTarget(std::move(exec));
  }
  if (fastbuildTarget.PreBuildDependencies.empty()) {
    if (fastbuildTarget.ExcludeFromAll) {
      return;
    }
    fastbuildTarget.PreBuildDependencies.emplace(FASTBUILD_NOOP_FILE_NAME);
  }
  fastbuildTarget.Hidden = false;
  this->AdditionalCleanFiles();
  this->GetGlobalGenerator()->AddTarget(std::move(fastbuildTarget));
}
