/*
 * Copyright 2016 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.idea.blaze.clwb.run.producers;

import com.google.common.collect.ImmutableList;
import com.google.idea.blaze.base.command.BlazeCommandName;
import com.google.idea.blaze.base.command.BlazeFlags;
import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.run.BlazeCommandRunConfiguration;
import com.google.idea.blaze.base.run.BlazeCommandRunConfigurationType;
import com.google.idea.blaze.base.run.TestTargetHeuristic;
import com.google.idea.blaze.base.run.producers.BlazeRunConfigurationProducer;
import com.google.idea.blaze.base.run.state.BlazeCommandRunConfigurationCommonState;
import com.google.idea.blaze.base.settings.Blaze;
import com.intellij.execution.Location;
import com.intellij.execution.actions.ConfigurationContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.util.Couple;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.cidr.execution.testing.CidrTestUtil;
import com.jetbrains.cidr.lang.psi.OCFile;
import com.jetbrains.cidr.lang.psi.OCFunctionDefinition;
import com.jetbrains.cidr.lang.psi.OCMacroCall;
import com.jetbrains.cidr.lang.psi.OCMacroCallArgument;
import com.jetbrains.cidr.lang.psi.OCStruct;
import com.jetbrains.cidr.lang.symbols.OCSymbol;
import com.jetbrains.cidr.lang.symbols.cpp.OCFunctionSymbol;
import com.jetbrains.cidr.lang.symbols.cpp.OCStructSymbol;
import com.jetbrains.cidr.lang.symbols.cpp.OCSymbolWithQualifiedName;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import javax.annotation.Nullable;

/** Producer for run configurations related to C/C++ test classes in Blaze. */
public class BlazeCidrTestConfigurationProducer
    extends BlazeRunConfigurationProducer<BlazeCommandRunConfiguration> {

  private static class TestTarget {
    @Nullable
    private static TestTarget createFromFile(@Nullable PsiElement element) {
      return createFromClassAndMethod(element, null, null);
    }

    @Nullable
    private static TestTarget createFromClass(@Nullable PsiElement element, String className) {
      return createFromClassAndMethod(element, className, null);
    }

    @Nullable
    private static TestTarget createFromClassAndMethod(
        @Nullable PsiElement element, String classOrSuiteName, @Nullable String testName) {
      Label label = TestTargetHeuristic.testTargetForPsiElement(element);
      if (label == null) {
        return null;
      }
      String filter = null;
      if (classOrSuiteName != null) {
        filter = classOrSuiteName;
        if (testName != null) {
          filter += "." + testName;
        }
      }
      return new TestTarget(element, label, filter);
    }

    private final PsiElement element;
    private final Label label;
    @Nullable private final String testFilterArg;
    private final String name;

    private TestTarget(PsiElement element, Label label, @Nullable String testFilter) {
      this.element = element;
      this.label = label;
      if (testFilter != null) {
        testFilterArg = BlazeFlags.TEST_FILTER + "=" + testFilter;
        name = String.format("%s (%s)", testFilter, label.toString());
      } else {
        testFilterArg = null;
        name = label.toString();
      }
    }
  }

  public BlazeCidrTestConfigurationProducer() {
    super(BlazeCommandRunConfigurationType.getInstance());
  }

  /** The single selected {@link PsiElement}. Returns null if multiple elements are selected. */
  @Nullable
  private static PsiElement selectedPsiElement(ConfigurationContext context) {
    PsiElement[] psi = LangDataKeys.PSI_ELEMENT_ARRAY.getData(context.getDataContext());
    if (psi != null && psi.length > 1) {
      return null; // multiple elements selected.
    }
    Location<?> location = context.getLocation();
    return location != null ? location.getPsiElement() : null;
  }

  @Override
  protected boolean doSetupConfigFromContext(
      BlazeCommandRunConfiguration configuration,
      ConfigurationContext context,
      Ref<PsiElement> sourceElement) {

    PsiElement element = selectedPsiElement(context);
    if (element == null) {
      return false;
    }
    TestTarget testObject = findTestObject(element);
    if (testObject == null) {
      return false;
    }
    sourceElement.set(testObject.element);
    configuration.setTarget(testObject.label);
    BlazeCommandRunConfigurationCommonState handlerState =
        configuration.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
    if (handlerState == null) {
      return false;
    }
    handlerState.setCommand(BlazeCommandName.TEST);

    ImmutableList.Builder<String> flags = ImmutableList.builder();
    if (testObject.testFilterArg != null) {
      flags.add(testObject.testFilterArg);
    }
    flags.add(BlazeFlags.TEST_OUTPUT_STREAMED);
    flags.addAll(handlerState.getBlazeFlags());

    handlerState.setBlazeFlags(flags.build());
    configuration.setName(
        String.format(
            "%s test: %s", Blaze.buildSystemName(configuration.getProject()), testObject.name));
    return true;
  }

  @Override
  protected boolean doIsConfigFromContext(
      BlazeCommandRunConfiguration configuration, ConfigurationContext context) {
    BlazeCommandRunConfigurationCommonState handlerState =
        configuration.getHandlerStateIfType(BlazeCommandRunConfigurationCommonState.class);
    if (handlerState == null) {
      return false;
    }
    if (!Objects.equals(handlerState.getCommand(), BlazeCommandName.TEST)) {
      return false;
    }
    PsiElement element = selectedPsiElement(context);
    if (element == null) {
      return false;
    }
    TestTarget testObject = findTestObject(element);
    if (testObject == null) {
      return false;
    }
    List<String> flags = handlerState.getBlazeFlags();
    return testObject.label.equals(configuration.getTarget())
        && (testObject.testFilterArg == null || flags.contains(testObject.testFilterArg));
  }

  @Nullable
  private static TestTarget findTestObject(PsiElement element) {
    // Copied from on CidrGoogleTestRunConfigurationProducer::findTestObject.
    // Precedence order (decreasing): class/function, macro, file
    PsiElement parent =
        PsiTreeUtil.getNonStrictParentOfType(element, OCFunctionDefinition.class, OCStruct.class);

    OCStructSymbol parentSymbol;
    if (parent instanceof OCStruct
        && ((parentSymbol = ((OCStruct) parent).getSymbol()) != null)
        && CidrTestUtil.isGoogleTestClass(parentSymbol)) {
      Couple<String> name = CidrTestUtil.extractGoogleTestName(parentSymbol);
      if (name != null) {
        return TestTarget.createFromClassAndMethod(parent, name.first, name.second);
      }
      String className = parentSymbol.getQualifiedName().getName();
      return TestTarget.createFromClass(parent, className);
    } else if (parent instanceof OCFunctionDefinition) {
      OCFunctionSymbol symbol = ((OCFunctionDefinition) parent).getSymbol();
      if (symbol != null) {
        OCSymbolWithQualifiedName<?> resolvedOwner = symbol.getResolvedOwner();
        if (resolvedOwner != null) {
          OCSymbol<?> owner = resolvedOwner.getDefinitionSymbol();
          if (owner instanceof OCStructSymbol
              && CidrTestUtil.isGoogleTestClass((OCStructSymbol) owner)) {
            OCStruct struct = (OCStruct) owner.locateDefinition();
            Couple<String> name = CidrTestUtil.extractGoogleTestName((OCStructSymbol) owner);
            if (name != null) {
              return TestTarget.createFromClassAndMethod(struct, name.first, name.second);
            }
            return TestTarget.createFromClass(
                struct, ((OCStructSymbol) owner).getQualifiedName().getName());
          }
        }
      }
    }

    // if we're still here, let's test for a macro and, as a last resort, a file.
    parent = PsiTreeUtil.getNonStrictParentOfType(element, OCMacroCall.class, OCFile.class);
    if (parent instanceof OCMacroCall) {
      OCMacroCall gtestMacro = CidrTestUtil.findGoogleTestMacros(parent);
      if (gtestMacro != null) {
        List<OCMacroCallArgument> arguments = gtestMacro.getArguments();
        if (arguments.size() >= 2) {
          OCMacroCallArgument suiteArg = arguments.get(0);
          OCMacroCallArgument testArg = arguments.get(1);

          // if the element is the first argument of macro call,
          // then running entire suite, otherwise only a current test
          boolean isSuite =
              isFirstArgument(PsiTreeUtil.getParentOfType(element, OCMacroCallArgument.class))
                  || isFirstArgument(element.getPrevSibling());
          String suiteName = CidrTestUtil.extractArgumentValue(suiteArg);
          String testName = CidrTestUtil.extractArgumentValue(testArg);
          OCStructSymbol symbol =
              CidrTestUtil.findGoogleTestSymbol(element.getProject(), suiteName, testName);
          if (symbol != null) {
            OCStruct targetElement = (OCStruct) symbol.locateDefinition();
            return TestTarget.createFromClassAndMethod(
                targetElement, suiteName, isSuite ? null : testName);
          }
        }
      }
      Couple<String> suite = CidrTestUtil.extractFullSuiteNameFromMacro(parent);
      if (suite != null) {
        Collection<OCStructSymbol> res =
            CidrTestUtil.findGoogleTestSymbolsForSuiteRandomly(
                element.getProject(), suite.first, true);
        if (res.size() != 0) {
          OCStruct struct = (OCStruct) res.iterator().next().locateDefinition();
          return TestTarget.createFromClassAndMethod(struct, suite.first, null);
        }
      }
    } else if (parent instanceof OCFile) {
      return TestTarget.createFromFile(parent);
    }
    return null;
  }

  private static boolean isFirstArgument(@Nullable PsiElement element) {
    OCMacroCall macroCall = PsiTreeUtil.getParentOfType(element, OCMacroCall.class);
    if (macroCall != null) {
      List<OCMacroCallArgument> arguments = macroCall.getArguments();
      return arguments.size() > 0 && arguments.get(0).equals(element);
    }
    return false;
  }
}
