package fr.adrienbrault.idea.symfony2plugin.templating.annotation;

import com.intellij.codeInsight.navigation.actions.GotoDeclarationHandler;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.patterns.StandardPatterns;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.php.PhpIndex;
import com.jetbrains.php.lang.PhpLanguage;
import com.jetbrains.php.lang.documentation.phpdoc.parser.PhpDocElementTypes;
import com.jetbrains.php.lang.documentation.phpdoc.psi.PhpDocComment;
import com.jetbrains.php.lang.psi.elements.Method;
import com.jetbrains.php.lang.psi.elements.PhpClass;
import com.jetbrains.twig.TwigFile;
import fr.adrienbrault.idea.symfony2plugin.templating.TwigHelper;
import org.jetbrains.annotations.Nullable;

import java.util.*;

/**
 * @author Daniel Espendiller <daniel@espendiller.net>
 */
public class AnnotationGoToDeclarationHandler implements GotoDeclarationHandler {

    @Nullable
    @Override
    public PsiElement[] getGotoDeclarationTargets(PsiElement psiElement, int i, Editor editor) {

        if (PlatformPatterns.psiElement(PhpDocElementTypes.DOC_TAG_NAME).withText(StandardPatterns.string().equalTo("@Template")).withLanguage(PhpLanguage.INSTANCE).accepts(psiElement)) {

            PsiElement phpDocTagValue = psiElement.getNextSibling();
            if(null != phpDocTagValue) {

                String tagValue = psiElement.getNextSibling().getText();

                // ("MyAppBundle:Conversation:list/search.html.twig")
                if(tagValue.length() > 4 && tagValue.contains(":")) {
                    String strippedShortcutValue = tagValue.substring(2, tagValue.length() -2);
                    return getTwigDeclaration(psiElement.getProject(), strippedShortcutValue);
                }

                // empty template "()" which maps the controller and action name
                if(tagValue.equals("()")) {

                    PhpDocComment docComment = PsiTreeUtil.getParentOfType(psiElement, PhpDocComment.class);
                    if(null == docComment) {
                        return null;
                    }

                    Method method = PsiTreeUtil.getNextSiblingOfType(docComment, Method.class);
                    if(null == method) {
                        return null;
                    }

                    String shortcutName = getTwigShortcutName(method);
                    if(null == shortcutName) {
                        return null;
                    }

                    return getTwigDeclaration(psiElement.getProject(), shortcutName);
                }

            }

        }

        return new PsiElement[]{};
    }

    @Nullable
    protected PsiElement[] getTwigDeclaration(Project project, String shortcutName) {
        TwigFile twigFile = getTwigFileOnShortcut(project, shortcutName);
        if (twigFile == null) {
            return null;
        }

        return new PsiElement[] { twigFile };
    }

    protected TwigFile getTwigFileOnShortcut(Project project, String shortcutName) {
        Map<String, TwigFile> twigFilesByName = TwigHelper.getTwigFilesByName(project);
        TwigFile twigFile = twigFilesByName.get(shortcutName);

        if (null == twigFile) {
            return null;
        }
        return twigFile;
    }

    @Nullable
    protected String getTwigShortcutName(Method method) {

        // indexAction
        String methodName = method.getName();
        if(!methodName.endsWith("Action")) {
            return null;
        }

        // \ns\ns\HomeBundle\Controller\
        String namespace = method.getNamespaceName();
        if(namespace.lastIndexOf("Bundle\\Controller\\") < 0) {
            return null;
        }

        PhpClass phpClass = method.getContainingClass();
        if(null == phpClass) {
            return null;
        }

        // defaultController
        String className = phpClass.getName();
        if(!className.endsWith("Controller")) {
            return null;
        }

        // HomeBundle:default:index
        String shortcutName = getContainingBundleName(phpClass) + ":" + className.substring(0, className.lastIndexOf("Controller")) + ":" + methodName.substring(0, methodName.lastIndexOf("Action"));

        // we should support types later on
        // HomeBundle:default:index.html.twig
        return shortcutName + ".html.twig";
    }

    @Nullable
    protected String getContainingBundleName(PhpClass phpClassSearch) {

        PhpIndex phpIndex = PhpIndex.getInstance(phpClassSearch.getProject());
        Collection<PhpClass> phpClasses = phpIndex.getAllSubclasses("\\Symfony\\Component\\HttpKernel\\Bundle\\Bundle");

        for (PhpClass phpClass : phpClasses) {
            if(phpClassSearch.getNamespaceName().startsWith(phpClass.getNamespaceName())) {
              return phpClass.getName();
            }
        }

        return null;
    }

    @Nullable
    @Override
    public String getActionText(DataContext dataContext) {
        return null;
    }
}

@@ -3689,203 +3689,8 @@
  %7D%0A%0A
-        // %5Cns%5Cns%5CHomeBundle%5CController%5C%0A        String namespace = method.getNamespaceName();%0A        if(namespace.lastIndexOf(%22Bundle%5C%5CController%5C%5C%22) %3C 0) %7B%0A            return null;%0A        %7D%0A%0A
     
@@ -3838,16 +3838,59 @@
 troller%0A
+        // default/Folder/FolderController%0A
         
@@ -4027,32 +4027,677 @@
  // 
-HomeBundle:default:index
+find the bundle name of file%0A        PhpClass BundleClass = getContainingBundleClass(phpClass);%0A        if(null == BundleClass) %7B%0A            return null;%0A        %7D%0A%0A        // check if files is in %3CBundle%3E/Controller/*%0A        if(!phpClass.getNamespaceName().startsWith(BundleClass.getNamespaceName() + %22Controller%5C%5C%22)) %7B%0A            return null;%0A        %7D%0A%0A        // strip the controller folder name%0A        String templateFolderName = phpClass.getNamespaceName().substring(BundleClass.getNamespaceName().length() + 11);%0A%0A        // HomeBundle:default:index%0A        // HomeBundle:default/Test:index%0A        templateFolderName = templateFolderName.replace(%22%5C%5C%22, %22/%22);
 %0A   
@@ -4764,16 +4764,37 @@
  + %22:%22 +
+ templateFolderName +
  classNa
@@ -5115,32 +5115,307 @@
 leName(PhpClass 
+phpClass) %7B%0A%0A        PhpClass phpBundleClass = getContainingBundleClass(phpClass);%0A        if(null == phpBundleClass) %7B%0A            return null;%0A        %7D%0A%0A        return phpBundleClass.getName();%0A    %7D%0A%0A    @Nullable%0A    protected PhpClass getContainingBundleClass(PhpClass 
 phpClassSearch) 
@@ -5763,32 +5763,34 @@
 %7B%0A              
+  
 return phpClass.
@@ -5784,34 +5784,24 @@
 urn phpClass
-.getName()
 ;%0A          

support also controller in subfolder for empty @Template annotation value