/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.github.cameltooling.idea.completion.extension;

import java.util.Collection;
import java.util.List;
import static java.util.stream.Collectors.toList;
import com.github.cameltooling.idea.util.CamelIdeaUtils;
import com.github.cameltooling.idea.util.JavaMethodUtils;
import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.completion.CompletionProvider;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.codeInsight.completion.CompletionUtil;
import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;

/**
 * Camel Java bean reference smart completion for lookup bean methods.
 * <pre>
 *     Caret inside {@code bean(MyClass.class,"<caret>")} will look up all public methods for the
 *     class and it's super classes. If the a bean method is marked with @Handle it will bold and
 *     for deprecated methods will be with strike through.
 * </pre>
 */
public class CamelJavaBeanReferenceSmartCompletion extends CompletionProvider<CompletionParameters> {

    @Override
    protected void addCompletions(@NotNull CompletionParameters completionParameters, ProcessingContext processingContext, @NotNull CompletionResultSet completionResultSet) {
        final PsiElement element = completionParameters.getPosition();
        final PsiClass psiClass = getCamelIdeaUtils().getBean(element);

        if (psiClass != null) {
            Collection<PsiMethod> methods = getJavaMethodUtils().getMethods(psiClass);

            List<LookupElement> answer = getJavaMethodUtils().getBeanAccessibleMethods(methods)
                .stream()
                .map(method -> buildLookupElement(method, getJavaMethodUtils().getPresentableMethodWithParameters(method)))
                .collect(toList());

            // are there any results then add them
            if (!answer.isEmpty()) {
                String hackVal = element.getText();
                hackVal = hackVal.substring(1, hackVal.indexOf(CompletionUtil.DUMMY_IDENTIFIER_TRIMMED));
                completionResultSet.withPrefixMatcher(hackVal).addAllElements(answer);
                completionResultSet.stopHere();
            }
        }
    }

    @NotNull
    private LookupElement buildLookupElement(PsiMethod method, String presentableMethod) {
        LookupElementBuilder builder = LookupElementBuilder.create(method);
        builder = builder.withPresentableText(presentableMethod);
        builder = builder.withTypeText(method.getContainingClass().getName(), true);
        builder = builder.withIcon(AllIcons.Nodes.Method);
        if (getCamelIdeaUtils().isAnnotatedWithHandler(method)) {
            //@Handle methods are marked with
            builder = builder.withBoldness(true);
        }
        if (method.isDeprecated()) {
            // mark as deprecated
            builder = builder.withStrikeoutness(true);
        }
        return  builder.withAutoCompletionPolicy(AutoCompletionPolicy.GIVE_CHANCE_TO_OVERWRITE);
    }

    private CamelIdeaUtils getCamelIdeaUtils() {
        return ServiceManager.getService(CamelIdeaUtils.class);
    }

    private JavaMethodUtils getJavaMethodUtils() {
        return ServiceManager.getService(JavaMethodUtils.class);
    }

}