package fr.adrienbrault.idea.symfony2plugin.templating.variable.resolver;

import com.google.common.collect.Iterables;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.php.lang.psi.elements.Method;
import com.jetbrains.php.lang.psi.elements.MethodReference;
import com.jetbrains.php.lang.psi.elements.PhpClass;
import com.jetbrains.php.lang.psi.elements.Variable;
import fr.adrienbrault.idea.symfony2plugin.Symfony2InterfacesUtil;
import fr.adrienbrault.idea.symfony2plugin.dic.MethodReferenceBag;
import fr.adrienbrault.idea.symfony2plugin.form.util.FormFieldNameReference;
import fr.adrienbrault.idea.symfony2plugin.form.util.FormUtil;
import fr.adrienbrault.idea.symfony2plugin.templating.variable.TwigTypeContainer;
import fr.adrienbrault.idea.symfony2plugin.templating.variable.dict.PsiVariable;
import fr.adrienbrault.idea.symfony2plugin.templating.variable.resolver.holder.FormDataHolder;
import fr.adrienbrault.idea.symfony2plugin.util.PhpElementsUtil;
import fr.adrienbrault.idea.symfony2plugin.util.PsiElementUtils;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class FormFieldResolver implements TwigTypeResolver {

    public void resolve(Collection<TwigTypeContainer> targets, Collection<TwigTypeContainer> previousElement, String typeName, Collection<List<TwigTypeContainer>> previousElements, @Nullable List<PsiVariable> psiVariables) {

        if(targets.size() == 0 || psiVariables == null || previousElements == null || previousElements.size() != 0) {
            return;
        }

        Symfony2InterfacesUtil symfony2InterfacesUtil = new Symfony2InterfacesUtil();
        TwigTypeContainer twigTypeContainer = targets.iterator().next();

        if(twigTypeContainer.getPhpNamedElement() instanceof PhpClass) {
            if(symfony2InterfacesUtil.isInstanceOf((PhpClass) twigTypeContainer.getPhpNamedElement(), "\\Symfony\\Component\\Form\\FormView")) {
                if(psiVariables.size() > 0) {
                    PsiElement var = psiVariables.get(0).getElement();

                    // $form->createView()
                    if(var instanceof MethodReference) {
                        PsiElement form = var.getFirstChild();
                        if(form instanceof Variable) {
                            PsiElement varDecl = ((Variable) form).resolve();
                            if(varDecl instanceof Variable) {
                                MethodReference methodReference = PsiTreeUtil.getNextSiblingOfType(varDecl, MethodReference.class);
                                attachFormFields(methodReference, targets);
                            }
                        }
                    }

                    /*
                    // $form
                    if(var instanceof Variable) {
                        PsiElement varDecl = ((Variable) var).resolve();
                        if(varDecl instanceof Variable) {
                            MethodReference methodReference = PsiTreeUtil.getNextSiblingOfType(varDecl, MethodReference.class);
                            attachFormFields(methodReference, targets);
                        }
                    } */

                }
            }

        }
    }

    private static void attachFormFields(@Nullable MethodReference methodReference, Collection<TwigTypeContainer> targets) {

        if(methodReference == null) {
            return;
        }

        Symfony2InterfacesUtil symfony2InterfacesUtil = new Symfony2InterfacesUtil();
        if(symfony2InterfacesUtil.isCallTo(methodReference, "\\Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller", "createForm")) {
            PsiElement formType = PsiElementUtils.getMethodParameterPsiElementAt(methodReference, 0);
            if(formType != null) {
                PhpClass phpClass = FormUtil.getFormTypeClassOnParameter(formType);

                if(phpClass == null) {
                    return;
                }

                Method method = PhpElementsUtil.getClassMethod(phpClass, "buildForm");
                if(method == null) {
                    return;
                }

                targets.addAll(getTwigTypeContainer(method));
            }

        }

    }

    public static List<TwigTypeContainer> getTwigTypeContainer(Method method) {

        MethodReference[] formBuilderTypes = FormUtil.getFormBuilderTypes(method);
        List<TwigTypeContainer> twigTypeContainers = new ArrayList<TwigTypeContainer>();

        for(MethodReference methodReference: formBuilderTypes) {

            String fieldName = PsiElementUtils.getMethodParameterAt(methodReference, 0);
            PsiElement psiElement = PsiElementUtils.getMethodParameterPsiElementAt(methodReference, 1);
            TwigTypeContainer twigTypeContainer = new TwigTypeContainer(fieldName);

            // find form field type
            if(psiElement != null) {
                PhpClass phpClass = FormUtil.getFormTypeClassOnParameter(psiElement);
                if(phpClass != null) {
                    twigTypeContainer.withDataHolder(new FormDataHolder(phpClass));
                }
            }

            twigTypeContainers.add(twigTypeContainer);
        }

        return twigTypeContainers;
    }

}

@@ -2879,32 +2879,33 @@
              %7D%0A%0A
+%0A
                 
@@ -2913,38 +2913,171 @@
    /
-*%0A                    // $form
+/ nested resolve of form view; @TODO: should be some nicer%0A                    // 'foo2' =%3E $form2 =%3E $form2 = $form-%3EcreateView() =%3E $this-%3EcreateForm(new Type();
 %0A   
@@ -3374,32 +3374,631 @@
 ference.class);%0A
+                            PsiElement scopeVar = methodReference.getFirstChild();%0A%0A                            // $form2 = $form-%3EcreateView()%0A                            if(scopeVar instanceof Variable) %7B%0A                                PsiElement varDeclParent = ((Variable) scopeVar).resolve();%0A                                if(varDeclParent instanceof Variable) %7B%0A%0A                                    // %22$form%22-%3EcreateView();%0A                                    PsiElement resolve = ((Variable) varDeclParent).resolve();%0A                                    if(resolve != null) %7B%0A            
                 
@@ -4018,33 +4018,75 @@
 ttachFormFields(
-m
+PsiTreeUtil.getNextSiblingOfType(resolve, M
 ethodReference, 
@@ -4075,32 +4075,39 @@
  MethodReference
+.class)
 , targets);%0A    
@@ -4094,32 +4094,164 @@
 ass), targets);%0A
+                                    %7D%0A%0A                                %7D%0A                            %7D%0A                            %0A
                 
@@ -4252,32 +4252,32 @@
               %7D%0A
+
                 
@@ -4285,11 +4285,8 @@
    %7D
- */
 %0A%0A  

add form variable resolve