package de.espend.idea.php.annotation.doctrine.reference.references;

import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementResolveResult;
import com.intellij.psi.PsiPolyVariantReferenceBase;
import com.intellij.psi.ResolveResult;
import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment;
import com.jetbrains.php.lang.psi.elements.Field;
import com.jetbrains.php.lang.psi.elements.PhpClass;
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
import de.espend.idea.php.annotation.dict.PhpDocCommentAnnotation;
import de.espend.idea.php.annotation.dict.PhpDocTagAnnotation;
import de.espend.idea.php.annotation.doctrine.util.DoctrineUtil;
import de.espend.idea.php.annotation.util.AnnotationUtil;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Daniel Espendiller <[email protected]>
 */
public class DoctrinePhpClassFieldReference extends PsiPolyVariantReferenceBase<PsiElement> {

    final PhpClass phpClass;
    final String content;

    public DoctrinePhpClassFieldReference(StringLiteralExpression psiElement, PhpClass phpClass) {
        super(psiElement);
        this.phpClass = phpClass;
        this.content = psiElement.getContents();
    }

    @NotNull
    @Override
    public ResolveResult[] multiResolve(boolean b) {
        List<PsiElement> psiElementList = this.phpClass.getFields().stream()
            .filter(field -> !field.isConstant() && content.equals(field.getName()))
            .collect(Collectors.toList());

        return PsiElementResolveResult.createResults(psiElementList);
    }

    @NotNull
    @Override
    public Object[] getVariants() {
        List<LookupElement> lookupElements = new ArrayList<>();

        for(Field field: this.phpClass.getFields()) {
            if(!field.isConstant()) {
                LookupElementBuilder lookupElement = LookupElementBuilder.createWithIcon(field);
                lookupElement = attachLookupInformation(field, lookupElement);
                lookupElements.add(lookupElement);
            }
        }

        return lookupElements.toArray();
    }

    private LookupElementBuilder attachLookupInformation(Field field, LookupElementBuilder lookupElement) {

        // get some more presentable completion information
        PhpDocComment docBlock = field.getDocComment();
        if(docBlock == null) {
            return lookupElement;
        }

        PhpDocCommentAnnotation phpDocCommentAnnotation = AnnotationUtil.getPhpDocCommentAnnotationContainer(docBlock);
        if(phpDocCommentAnnotation == null) {
            return lookupElement;
        }

        // search column type
        PhpDocTagAnnotation phpDocTagAnnotation = phpDocCommentAnnotation.getPhpDocBlock("Doctrine\\ORM\\Mapping\\Column");
        if(phpDocTagAnnotation != null) {
            String value = phpDocTagAnnotation.getPropertyValue("type");
            if(value != null) {
                lookupElement = lookupElement.withTypeText(value, true);
            }
        }

        // search for relations
        PhpDocTagAnnotation relation = phpDocCommentAnnotation.getFirstPhpDocBlock(DoctrineUtil.DOCTRINE_RELATION_FIELDS);
        if(relation != null) {

            String value = relation.getPropertyValue("targetEntity");
            if(value != null) {
                lookupElement = lookupElement.withTypeText(value, true);
                lookupElement = lookupElement.withBoldness(true);
            }

            lookupElement = lookupElement.withTailText(String.format("(%s)", relation.getPhpClass().getName()), true);
        }

        return lookupElement;
    }

}