@Nullable
  private static TypeConversionDescriptorBase getOneMethodDescriptor(@NotNull @NlsSafe String methodName,
                                                                     @NotNull PsiMethod method,
                                                                     @NotNull PsiType from,
                                                                     @Nullable PsiExpression context) {
    TypeConversionDescriptor descriptorBase = null;
    PsiType conversionType = null;
    boolean needSpecifyType = true;
    switch (methodName) {
      case "of" -> descriptorBase = new TypeConversionDescriptor("'_FluentIterable?.of($arr$)", "java.util.Arrays.stream($arr$)");
      case "from" -> descriptorBase = new TypeConversionDescriptor("'_FluentIterable?.from($it$)", null) {
        @Override
        public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) {
          final PsiMethodCallExpression methodCall = (PsiMethodCallExpression)expression;
          PsiExpression argument =
            PseudoLambdaReplaceTemplate.replaceTypeParameters(methodCall.getArgumentList().getExpressions()[0]);
          if (argument == null) {
            return expression;
          }
          boolean isCollection =
            InheritanceUtil.isInheritor(PsiTypesUtil.getPsiClass(argument.getType()), CommonClassNames.JAVA_UTIL_COLLECTION);
          setReplaceByString(isCollection ? "($it$).stream()" : "java.util.stream.StreamSupport.stream(($it$).spliterator(), false)");
          final PsiExpression replaced = super.replace(expression, evaluator);
          ParenthesesUtils.removeParentheses(replaced, false);
          return replaced;
        }
      };
      case "filter" -> descriptorBase = FluentIterableConversionUtil.getFilterDescriptor(method, context);
      case "isEmpty" -> {
        descriptorBase = new TypeConversionDescriptor("$q$.isEmpty()", null) {
          @Override
          public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) {
            final PsiElement parent = expression.getParent();
            boolean isDoubleNegation = false;
            if (parent instanceof PsiExpression && DoubleNegationInspection.isNegation((PsiExpression)parent)) {
              isDoubleNegation = true;
              expression = (PsiExpression)parent.replace(expression);
            }
            setReplaceByString((isDoubleNegation ? "" : "!") + "$q$.findAny().isPresent()");
            return super.replace(expression, evaluator);
          }
        };
        needSpecifyType = false;
      }
      case "transformAndConcat" -> descriptorBase = new FluentIterableConversionUtil.TransformAndConcatConversionRule(context);
      case "toArray" -> {
        descriptorBase = FluentIterableConversionUtil.getToArrayDescriptor(from, context);
        needSpecifyType = false;
      }
      case "copyInto" -> {
        descriptorBase = new FluentIterableConversionUtil.CopyIntoConversionDescriptor();
        needSpecifyType = false;
      }
      case "append" -> descriptorBase = createDescriptorForAppend(method, context);
      case "get" -> {
        descriptorBase = new TypeConversionDescriptor("$it$.get($p$)", null) {
          @Override
          public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) {
            PsiMethodCallExpression methodCall = (PsiMethodCallExpression)expression;
            final PsiExpression[] arguments = methodCall.getArgumentList().getExpressions();
            setReplaceByString("$it$.skip($p$).findFirst().get()");
            if (arguments.length == 1 && arguments[0] instanceof PsiLiteralExpression) {
              final Object value = ((PsiLiteralExpression)arguments[0]).getValue();
              if (value != null && value.equals(0)) {
                setReplaceByString("$it$.findFirst().get()");
              }
            }
            return super.replace(expression, evaluator);
          }
        };
        needSpecifyType = false;
      }
      case "contains" -> {
        descriptorBase = new TypeConversionDescriptor("$it$.contains($o$)", null) {
          @Override
          public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) {
            final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
            final PsiExpression qualifier = methodCallExpression.getMethodExpression().getQualifierExpression();
            LOG.assertTrue(qualifier != null);
            final PsiClassType qualifierType = (PsiClassType)qualifier.getType();
            LOG.assertTrue(qualifierType != null);
            final PsiType[] parameters = qualifierType.getParameters();

            final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(expression.getProject());
            final SuggestedNameInfo suggestedNameInfo = codeStyleManager
              .suggestVariableName(VariableKind.LOCAL_VARIABLE, null, null, parameters.length == 1 ? parameters[0] : null, false);
            final String suggestedName = codeStyleManager.suggestUniqueVariableName(suggestedNameInfo, expression, false).names[0];

            setReplaceByString("$it$.anyMatch(" + suggestedName + " -> java.util.Objects.equals(" + suggestedName + ", $o$))");

            return super.replace(expression, evaluator);
          }
        };
        needSpecifyType = false;
      }
      case "last" -> descriptorBase = new TypeConversionDescriptor("$it$.last()", null) {
        @Override
        public PsiExpression replace(PsiExpression expression, @NotNull TypeEvaluator evaluator) {
          final JavaCodeStyleManager codeStyleManager = JavaCodeStyleManager.getInstance(expression.getProject());
          String varA = suggestName("a", codeStyleManager, expression);
          String varB = suggestName("b", codeStyleManager, expression);
          setReplaceByString("$it$.reduce((" + varA + ", " + varB + ") -> " + varB + ")");
          return super.replace(expression, evaluator);
        }

        private static String suggestName(String baseName, JavaCodeStyleManager codeStyleManager, PsiElement place) {
          final SuggestedNameInfo suggestedNameInfo =
            codeStyleManager.suggestVariableName(VariableKind.LOCAL_VARIABLE, baseName, null, null, false);
          return codeStyleManager.suggestUniqueVariableName(suggestedNameInfo, place, false).names[0];
        }
      };
      default -> {
        final TypeConversionDescriptorFactory base = DESCRIPTORS_MAP.get(methodName);
        if (base != null) {
          final TypeConversionDescriptor descriptor = base.create(context);
          needSpecifyType = base.isChainedMethod();
          if (needSpecifyType && !base.isFluentIterableReturnType()) {
            conversionType = GuavaConversionUtil.addTypeParameters(GuavaOptionalConversionRule.JAVA_OPTIONAL, context.getType(), context);
          }
          descriptorBase = descriptor;
        }
      }
    }
    if (descriptorBase == null) {
      return FluentIterableConversionUtil.createToCollectionDescriptor(methodName, context);
    }
    if (needSpecifyType) {
      if (conversionType == null) {
        PsiMethodCallExpression methodCall =
          (PsiMethodCallExpression)(context instanceof PsiMethodCallExpression ? context : context.getParent());
        conversionType = GuavaConversionUtil.addTypeParameters(GuavaTypeConversionDescriptor.isIterable(methodCall)
                                                               ? CommonClassNames.JAVA_LANG_ITERABLE
                                                               : StreamApiConstants.JAVA_UTIL_STREAM_STREAM, context.getType(), context);
      }
      descriptorBase.withConversionType(conversionType);
    }
    return descriptorBase;
  }
@Nullable
  private static TypeConversionDescriptorBase getOneMethodDescriptor(@NotNull @NlsSafe String methodName,
                                                                     @NotNull PsiMethod method,
                                                                     @NotNull PsiType from,
                                                                     @Nullable PsiExpression context)