// Copyright 2015 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).

package com.twitter.intellij.pants.service.project.resolver;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.externalSystem.model.DataNode;
import com.intellij.openapi.externalSystem.model.ProjectKeys;
import com.intellij.openapi.externalSystem.model.project.ModuleData;
import com.intellij.openapi.externalSystem.model.project.ModuleSdkData;
import com.intellij.openapi.externalSystem.model.project.ProjectData;
import com.intellij.openapi.externalSystem.model.project.ProjectSdkData;
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil;
import com.intellij.openapi.module.ModuleTypeId;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import com.twitter.intellij.pants.PantsException;
import com.twitter.intellij.pants.model.TargetAddressInfo;
import com.twitter.intellij.pants.service.PantsCompileOptionsExecutor;
import com.twitter.intellij.pants.service.project.PantsResolverExtension;
import com.twitter.intellij.pants.service.project.metadata.TargetMetadata;
import com.twitter.intellij.pants.service.project.model.ProjectInfo;
import com.twitter.intellij.pants.service.project.model.TargetInfo;
import com.twitter.intellij.pants.service.project.model.graph.BuildGraph;
import com.twitter.intellij.pants.service.project.model.graph.BuildGraphNode;
import com.twitter.intellij.pants.util.PantsConstants;
import com.twitter.intellij.pants.util.PantsUtil;
import icons.PantsIcons;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

public class PantsCreateModulesExtension implements PantsResolverExtension {

  private static Logger logger = Logger.getInstance("#" + PantsCreateModulesExtension.class.getName());

  private Integer depthToInclude = null;

  @Override
  public void resolve(
    @NotNull ProjectInfo projectInfo,
    @NotNull PantsCompileOptionsExecutor executor,
    @NotNull DataNode<ProjectData> projectDataNode,
    @NotNull Map<String, DataNode<ModuleData>> modules,
    @NotNull Optional<BuildGraph> buildGraph
  ) {
    Set<TargetInfo> targetInfoWithinLevel = null;
    if (buildGraph.isPresent()) {
      final int maxDepth = buildGraph.get().getMaxDepth();
      depthToInclude = executor.getIncrementalImportDepth().orElse(null);
      if (depthToInclude == null) {
        throw new PantsException("Task cancelled");
      }
      logger.info(String.format("TargetInfo level %s", depthToInclude));
      targetInfoWithinLevel = buildGraph
        .get()
        .getNodesUpToLevel(depthToInclude)
        .stream()
        .map(BuildGraphNode::getTargetInfo)
        .collect(Collectors.toSet());
    }

    for (Map.Entry<String, TargetInfo> entry : projectInfo.getSortedTargets()) {
      if (targetInfoWithinLevel != null && !targetInfoWithinLevel.contains(entry.getValue())) {
        continue;
      }
      final String targetName = entry.getKey();
      if (StringUtil.startsWith(targetName, ":scala-library")) {
        // we already have it in libs
        continue;
      }
      final TargetInfo targetInfo = entry.getValue();
      if (targetInfo.isEmpty()) {
        LOG.debug("Skipping " + targetName + " because it is empty");
        continue;
      }
      final DataNode<ModuleData> moduleData =
        createModuleData(
          projectDataNode,
          targetName,
          targetInfo,
          executor
        );
      modules.put(targetName, moduleData);
    }
  }

  @NotNull
  private DataNode<ModuleData> createModuleData(
    @NotNull DataNode<ProjectData> projectInfoDataNode,
    @NotNull String targetName,
    @NotNull TargetInfo targetInfo,
    @NotNull PantsCompileOptionsExecutor executor
  ) {
    final String moduleName = PantsUtil.getCanonicalModuleName(targetName);

    final ModuleData moduleData = new ModuleData(
      targetName,
      PantsConstants.SYSTEM_ID,
      ModuleTypeId.JAVA_MODULE,
      moduleName,
      projectInfoDataNode.getData().getIdeProjectFileDirectoryPath() + "/" + moduleName,
      new File(executor.getBuildRoot(), targetName).getAbsolutePath()
    );

    final DataNode<ModuleData> moduleDataNode = projectInfoDataNode.createChild(ProjectKeys.MODULE, moduleData);

    DataNode<ProjectSdkData> sdk = ExternalSystemApiUtil.find(projectInfoDataNode, ProjectSdkData.KEY);
    if(sdk != null){
      ModuleSdkData moduleSdk = new ModuleSdkData(sdk.getData().getSdkName());
      moduleDataNode.createChild(ModuleSdkData.KEY, moduleSdk);
    }

    final TargetMetadata metadata = new TargetMetadata(PantsConstants.SYSTEM_ID, moduleName);
    metadata.setTargetAddresses(ContainerUtil.map(targetInfo.getAddressInfos(), TargetAddressInfo::getTargetAddress));
    metadata.setTargetAddressInfoSet(targetInfo.getAddressInfos());
    metadata.setLibraryExcludes(targetInfo.getExcludes());
    moduleDataNode.createChild(TargetMetadata.KEY, metadata);

    return moduleDataNode;
  }
}

@@ -193,123 +193,8 @@
 r;%0A%0A
-import com.intellij.openapi.application.ApplicationManager;%0Aimport com.intellij.openapi.application.ModalityState;%0A
 impo
@@ -765,49 +765,8 @@
 Id;%0A
-import com.intellij.openapi.ui.Messages;%0A
 impo
@@ -1589,33 +1589,8 @@
 il;%0A
-import icons.PantsIcons;%0A
 impo
@@ -4392,24 +4392,297 @@
 duleData);%0A%0A
+    if(targetInfo.isPythonTarget()) %7B%0A      // FIXME this happens to work becuse a SDK with the matching name is created later. See PantsPythonSetupDataService.java:77%0A      moduleDataNode.createChild(ModuleSdkData.KEY, new ModuleSdkData(%22python%22)); //FIXME%0A    %7D else %7B%0A  
     DataNode
@@ -4773,16 +4773,18 @@
 a.KEY);%0A
+  
     if(s
@@ -4798,24 +4798,26 @@
 ull)%7B%0A      
+  
 ModuleSdkDat
@@ -4873,24 +4873,26 @@
 SdkName());%0A
+  
       module
@@ -4943,16 +4943,24 @@
 leSdk);%0A
+      %7D%0A
     %7D%0A%0A 

Set Python as the SDK for modules