package com.reason.ide.hints;

import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.lang.parameterInfo.*;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.reason.lang.core.HMSignature;
import com.reason.lang.core.psi.*;
import com.reason.lang.reason.RmlTypes;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collection;
import java.util.Collections;
import java.util.Set;

public class ORParameterInfoHandlerWithTabActionSupport implements ParameterInfoHandlerWithTabActionSupport<PsiFunctionCallParams, Object, PsiElement> {

    @NotNull
    @Override
    public PsiElement[] getActualParameters(@NotNull PsiFunctionCallParams callParams) {
        Collection<PsiFunctionParameter> childrenOfType = PsiTreeUtil.findChildrenOfType(callParams, PsiFunctionParameter.class);
        return childrenOfType.toArray(new PsiFunctionParameter[0]);
    }

    @NotNull
    @Override
    public IElementType getActualParameterDelimiterType() {
        return RmlTypes.INSTANCE.COMMA;
    }

    @NotNull
    @Override
    public IElementType getActualParametersRBraceType() {
        return RmlTypes.INSTANCE.RBRACE;
    }

    @NotNull
    @Override
    public Set<Class> getArgumentListAllowedParentClasses() {
        return Collections.singleton(PsiFunctionCallParams.class);
    }

    @NotNull
    @Override
    public Set<? extends Class> getArgListStopSearchClasses() {
        return java.util.Collections.emptySet();
    }

    @NotNull
    @Override
    public Class<PsiFunctionCallParams> getArgumentListClass() {
        return PsiFunctionCallParams.class;
    }

    @Override
    public boolean couldShowInLookup() {
        return false;
    }

    @Nullable
    @Override
    public Object[] getParametersForLookup(LookupElement item, ParameterInfoContext context) {
        return null;
    }

    @Nullable
    @Override
    public PsiFunctionCallParams findElementForParameterInfo(@NotNull CreateParameterInfoContext context) {
        return getPsiFunctionCallParams(context);
    }

    @Nullable
    @Override
    public PsiFunctionCallParams findElementForUpdatingParameterInfo(@NotNull UpdateParameterInfoContext context) {
        return getPsiFunctionCallParams(context);
    }

    private PsiFunctionCallParams getPsiFunctionCallParams(ParameterInfoContext context) {
        PsiElement elementAt = context.getFile().findElementAt(context.getOffset());
        return PsiTreeUtil.getParentOfType(elementAt, PsiFunctionCallParams.class);
    }

    @Override
    public void showParameterInfo(@NotNull PsiFunctionCallParams params, @NotNull CreateParameterInfoContext context) {
        PsiLowerSymbol functionName = PsiTreeUtil.getPrevSiblingOfType(params, PsiLowerSymbol.class);
        if (functionName != null) {
            PsiReference reference = functionName.getReference();
            PsiElement resolvedElement = reference == null ? null : reference.resolve();
            if (resolvedElement instanceof PsiLowerSymbol) {
                PsiElement parent = resolvedElement.getParent();
                if (parent instanceof PsiLet && ((PsiLet) parent).isFunction()) {
                    PsiLet psiLet = (PsiLet) parent;
                    PsiSignature sig = psiLet.getSignature();
                    if (sig != null) {
                        context.setItemsToShow(new Object[]{sig});
                        context.showHint(params, params.getTextOffset(), this);
                    }
                }
            }
        }
    }

    @Override
    public void updateParameterInfo(@NotNull PsiFunctionCallParams psiFunctionCallParams, @NotNull UpdateParameterInfoContext context) {
        Collection<PsiFunctionParameter> parameters = psiFunctionCallParams.getParameterList();
        if (!parameters.isEmpty()) {
            int offset = context.getOffset();
            int i = 0;

            for (PsiFunctionParameter parameter : parameters) {
                TextRange textRange = parameter.getTextRange();
                if (textRange.getStartOffset() <= offset && offset <= textRange.getEndOffset()) {
                    context.setCurrentParameter(i);
                    break;
                }
                i++;
            }
        }
    }

    @Override
    public void updateUI(Object element, @NotNull ParameterInfoUIContext context) {
        if (element == null) {
            context.setUIComponentEnabled(false);
            return;
        }

        if (element instanceof PsiSignature) {
            PsiSignature st = (PsiSignature) element;
            HMSignature.SignatureType[] types = st.asHMSignature().getTypes();

            int currentParameterIndex = context.getCurrentParameterIndex();
            boolean grayedOut = currentParameterIndex != -1 && types.length <= currentParameterIndex;
            context.setUIComponentEnabled(!grayedOut);
            TextRange paramRange = getSignatureTextRange(types, currentParameterIndex);

            context.setupUIComponentPresentation(st.asHMSignature().toString(),
                    paramRange.getStartOffset(),
                    paramRange.getEndOffset(),
                    !context.isUIComponentEnabled(),
                    false,
                    false,
                    context.getDefaultParameterColor());
        }
    }

    private TextRange getSignatureTextRange(HMSignature.SignatureType[] types, int index) {
        if (index == -1 || types.length <= index) {
            return TextRange.EMPTY_RANGE;
        }
        return TextRange.EMPTY_RANGE;
    }
}

@@ -395,24 +395,79 @@
 core.psi.*;%0A
+import com.reason.lang.core.psi.impl.PsiSignatureItem;%0A
 import com.r
@@ -5109,24 +5109,26 @@
 grayedOut);%0A
+%0A%0A
             
@@ -5172,21 +5172,18 @@
 xtRange(
-type
 s
+t
 , curren
@@ -5397,16 +5397,25 @@
         
+false, //
 !context
@@ -5611,18 +5611,19 @@
 xtRange(
-HM
+Psi
 Signatur
@@ -5627,44 +5627,130 @@
 ture
-.SignatureType%5B%5D types, int index) %7B
+ st, int index) %7B%0A        Collection%3CPsiSignatureItem%3E items = PsiTreeUtil.findChildrenOfType(st, PsiSignatureItem.class);
 %0A   
@@ -5773,28 +5773,28 @@
 = -1 %7C%7C 
-types.length
+items.size()
  %3C= inde
@@ -5842,32 +5842,345 @@
 ANGE;%0A        %7D%0A
+%0A        int i = 0;%0A        for (PsiSignatureItem item : items) %7B%0A            if (i == index) %7B%0A                TextRange textRange = TextRange.create(item.getStartOffsetInParent(), item.getStartOffsetInParent() + item.getTextLength());%0A                return textRange;%0A            %7D%0A            i++;%0A        %7D%0A%0A
         return T

Update param info