package pers.fw.tplugin.config;

import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.lang.Language;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.PsiElement;
import com.jetbrains.php.PhpIndex;
import com.jetbrains.php.lang.PhpLanguage;
import com.jetbrains.php.lang.parser.PhpElementTypes;
import com.jetbrains.php.lang.psi.elements.*;
import pers.fw.tplugin.inter.GotoCompletionLanguageRegistrar;
import pers.fw.tplugin.inter.GotoCompletionProvider;
import pers.fw.tplugin.inter.GotoCompletionRegistrarParameter;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import pers.fw.tplugin.util.PhpElementsUtil;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;

/**
 * @author Daniel Espendiller <[email protected]>
 */
public class ProviderGotoCompletion implements GotoCompletionLanguageRegistrar {

    @Override
    public void register(GotoCompletionRegistrarParameter registrar) {
        registrar.register(PlatformPatterns.psiElement(), psiElement -> {
            if (psiElement == null || !psiElement.getContainingFile().getName().contains("app.php")) {
                return null;
            }

            // array('providers' => array('foo'))
            PsiElement literal = psiElement.getParent();
            if (literal instanceof StringLiteralExpression) {
                PsiElement arrayValue = literal.getParent();
                if (arrayValue.getNode().getElementType() == PhpElementTypes.ARRAY_VALUE) {
                    PsiElement arrayCreation = arrayValue.getParent();
                    if (arrayCreation instanceof ArrayCreationExpression) {
                        PsiElement arrayValueKey = arrayCreation.getParent();
                        if (arrayValueKey.getNode().getElementType() == PhpElementTypes.ARRAY_VALUE) {
                            PsiElement hashArrayElement = arrayValueKey.getParent();
                            if (hashArrayElement instanceof ArrayHashElement) {
                                PhpPsiElement key = ((ArrayHashElement) hashArrayElement).getKey();
                                if (key instanceof StringLiteralExpression && "providers".equals(((StringLiteralExpression) key).getContents())) {
                                    return new ProviderName(psiElement);
                                }

                            }
                        }
                    }
                }
            }

            return null;
        });

    }

    @Override
    public boolean support(@NotNull Language language) {
        return PhpLanguage.INSTANCE == language;
    }

    private class ProviderName extends GotoCompletionProvider {

        public ProviderName(PsiElement element) {
            super(element);
        }

        @NotNull
        @Override
        public Collection<LookupElement> getLookupElements() {

            return PhpIndex.getInstance(getProject()).getAllSubclasses("\\Illuminate\\Support\\ServiceProvider")
                    .stream()
                    .map(phpClass -> LookupElementBuilder.create(phpClass.getPresentableFQN())
                            .withIcon(phpClass.getIcon())).collect(Collectors.toCollection(ArrayList::new)
                    );
        }

        @NotNull
        @Override
        public Collection<PsiElement> getPsiTargets(StringLiteralExpression element) {

            String contents = element.getContents();
            if (StringUtils.isBlank(contents)) {
                return Collections.emptyList();
            }

            Collection<PsiElement> psiElements = new ArrayList<>();
            for (PhpClass phpClass : PhpElementsUtil.getClassesOrInterfaces(element.getProject(), contents)) {
                psiElements.add(phpClass);
            }

            return psiElements;
        }
    }
}