package com.lightd.ideap.maven.execution;

import com.intellij.execution.Location;
import com.intellij.execution.PsiLocation;
import com.intellij.execution.RunManager;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.actions.ConfigurationContext;
import com.intellij.execution.actions.ConfigurationFromContext;
import com.intellij.execution.actions.ConfigurationFromContextImpl;
import com.intellij.execution.actions.RunConfigurationProducer;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.lightd.ideap.maven.MvnRunConfiguration;
import com.lightd.ideap.maven.MvnRunConfigurationType;
import com.lightd.ideap.maven.RunType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.execution.MavenGoalLocation;
import org.jetbrains.idea.maven.execution.MavenRunnerParameters;
import org.jetbrains.idea.maven.model.MavenExplicitProfiles;
import org.jetbrains.idea.maven.project.MavenProject;
import org.jetbrains.idea.maven.project.MavenProjectsManager;
import org.jetbrains.idea.maven.utils.actions.MavenActionUtil;

import java.util.Collections;
import java.util.List;

/**
 * maven module support
 */
public abstract class MavenModuleConfigurationProducer extends RunConfigurationProducer<MvnRunConfiguration> {

    protected MavenProject mavenProject;
    protected PsiElement sourceElement;
    protected PsiFile psiFile;

    protected MavenModuleConfigurationProducer() {
        super(MvnRunConfigurationType.getInstance());
    }

    @Nullable
    @Override
    public ConfigurationFromContext createConfigurationFromContext(ConfigurationContext context) {
        RunnerAndConfigurationSettings settings = cloneTemplateConfiguration(context);
        sourceElement = context.getPsiLocation();
        final Ref<PsiElement> ref = new Ref<>(context.getPsiLocation());
        if (setupConfigurationFromContext((MvnRunConfiguration) settings.getConfiguration(), context, ref)) {
            return new ConfigurationFromContextImpl(this, settings, ref.get());
        }
        return null;
    }

    @Nullable
    @Override
    public RunnerAndConfigurationSettings findExistingConfiguration(ConfigurationContext context) {
        final RunManager runManager = RunManager.getInstance(context.getProject());
        final List<RunnerAndConfigurationSettings> configurations = getConfigurationSettingsList(runManager);
        for (RunnerAndConfigurationSettings config : configurations) {
            if (!(config.getConfiguration() instanceof MvnRunConfiguration)) continue;
            if (isConfigurationFromContext((MvnRunConfiguration)config.getConfiguration(), context))
                return config;
        }
        return null;
    }


    @Override
    public boolean isConfigurationFromContext(MvnRunConfiguration config, ConfigurationContext context) {
        if (isContext(context)) {
            MavenRunnerParameters parameters = config.getRunnerParameters();
            if (Comparing.strEqual(mavenProject.getDirectory(), parameters.getWorkingDirPath())) {
                List<String> testParameters = generateMvnParameters();
                return isSameParameters(testParameters, parameters.getGoals());
            }
        }
        return false;
    }

    @Override
    protected boolean setupConfigurationFromContext(MvnRunConfiguration config, ConfigurationContext context, Ref<PsiElement> ref) {
        if (context == null) return false;
        if (!initContext(context) || !isContext(context)) return false;

        final MavenRunnerParameters params = createMavenParameters(context.getLocation(), context.getDataContext());
        if (params != null) {
            config.setRunnerParameters(params);
            return setupMavenContext(config, config.getRunnerParameters().getGoals());
        }
        return false;
    }

    protected boolean initContext(ConfigurationContext context) {
        mavenProject = MavenActionUtil.getMavenProject(context.getDataContext());
        psiFile = LangDataKeys.PSI_FILE.getData(context.getDataContext());
        return true;
    }

    protected boolean isContext(ConfigurationContext context) {
        boolean isContext = mavenProject != null;
        if (isContext) {
            MavenProjectsManager projectsManager = MavenProjectsManager.getInstance(context.getProject());
            isContext = projectsManager.isMavenizedModule(context.getModule());
        }
        return isContext;
    }

    protected MavenRunnerParameters createMavenParameters(Location l, DataContext dataContext) {
        if (l instanceof PsiLocation) {
            MavenExplicitProfiles profiles = MavenActionUtil.getProjectsManager(dataContext).getExplicitProfiles();
            return new MavenRunnerParameters(true, mavenProject.getDirectory(), mavenProject.getFile().getName(), Collections.emptyList(), profiles);
        }
        return null;
    }

    protected boolean setupMavenContext(MvnRunConfiguration config, List<String> goals) {
        config.setName(generateName());
        config.setRunType(getRunType());
        goals.addAll(generateMvnParameters());
        return true;
    }

    protected abstract String generateName();

    protected abstract RunType getRunType();

    protected abstract List<String> generateMvnParameters();

    protected abstract boolean isSameParameters(List<String> parameters, List<String> configParameters);

}

@@ -70,163 +70,9 @@
 ion.
-Location;%0Aimport com.intellij.execution.PsiLocation;%0Aimport com.intellij.execution.RunManager;%0Aimport com.intellij.execution.RunnerAndConfigurationSettings
+*
 ;%0Aim
@@ -329,71 +329,8 @@
 er;%0A
-import com.intellij.execution.configurations.RunConfiguration;%0A
 impo
@@ -540,31 +540,20 @@
 lij.
-openapi.vfs.VirtualFile
+psi.PsiClass
 ;%0Aim
@@ -768,50 +768,8 @@
 pe;%0A
-import org.jetbrains.annotations.NotNull;%0A
 impo
@@ -811,69 +811,8 @@
 le;%0A
-import org.jetbrains.idea.maven.execution.MavenGoalLocation;%0A
 impo
@@ -2645,16 +2645,17 @@
 uration)
+ 
 config.g
@@ -2682,16 +2682,18 @@
 ontext))
+ %7B
 %0A       
@@ -2887,127 +2887,594 @@
     
-if (isContext(context)) %7B%0A            MavenRunnerParameters parameters = config.getRunnerParameters();%0A            if (
+final Location contextLocation = context.getLocation();%0A        if (contextLocation == null) %7B%0A            return false;%0A        %7D%0A        Location location = JavaExecutionUtil.stepIntoSingleClass(contextLocation);%0A        if (location == null) %7B%0A            return false;%0A        %7D%0A        final PsiElement element = location.getPsiElement();%0A        if (element instanceof PsiClass) %7B%0A            MavenRunnerParameters parameters = config.getRunnerParameters();%0A            if (isSameConfigByElement(config.getRunnerParameters().getGoals(), (PsiClass) element) &&%0A                    
 Comp
@@ -3752,24 +3752,295 @@
 lse;%0A    %7D%0A%0A
+    private boolean isSameConfigByElement(List%3CString%3E goals, PsiClass psiClass) %7B%0A        String runClass = %22=%22 + psiClass.getQualifiedName();%0A        return goals.stream()%0A                .map(s -%3E s.endsWith(runClass))%0A                .findAny().orElse(false);%0A    %7D%0A%0A
     @Overrid

Check the same configuration by maven parameters