package com.cedricziel.idea.typo3.persistence.codeInsight;

import com.cedricziel.idea.typo3.psi.PhpElementsUtil;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ProcessingContext;
import com.jetbrains.php.lang.psi.elements.MethodReference;
import com.jetbrains.php.lang.psi.elements.ParameterList;
import org.jetbrains.annotations.NotNull;

import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Matches
 * <p>
 * \TYPO3\CMS\Core\Database::getConnectionForTable()
 * \TYPO3\CMS\Core\Database::getQueryBuilderForTable()
 * <p>
 * and provides autocompletion
 */
public class DoctrineTablesContributor extends CompletionContributor {

    private static final String EXT_TABLES_SQL_FILENAME = "ext_tables.sql";

    public DoctrineTablesContributor() {
        extend(CompletionType.BASIC, PlatformPatterns.psiElement(), new CompletionProvider<CompletionParameters>() {
            @Override
            protected void addCompletions(@NotNull CompletionParameters completionParameters, ProcessingContext processingContext, @NotNull CompletionResultSet completionResultSet) {
                PsiElement element = completionParameters.getPosition().getParent();
                ParameterList parameterList = PsiTreeUtil.getParentOfType(element, ParameterList.class);
                if (parameterList == null) {
                    return;
                }

                MethodReference methodReference = PsiTreeUtil.getParentOfType(element, MethodReference.class);
                if (PhpElementsUtil.isMethodWithFirstStringOrFieldReference(methodReference, "getConnectionForTable")) {
                    completeAvailableTables(methodReference, completionResultSet);
                }
                if (PhpElementsUtil.isMethodWithFirstStringOrFieldReference(methodReference, "getQueryBuilderForTable")) {
                    completeAvailableTables(methodReference, completionResultSet);
                }
            }
        });
    }

    private void completeAvailableTables(MethodReference element, @NotNull CompletionResultSet completionResultSet) {
        PsiFile[] extSqlFiles = FilenameIndex.getFilesByName(element.getProject(), EXT_TABLES_SQL_FILENAME, GlobalSearchScope.allScope(element.getProject()));

        Set<String> tableNames = new HashSet<>();

        for (PsiFile psiFile : extSqlFiles) {

            if (psiFile != null) {

                CharSequence charSequence = LoadTextUtil.loadText(psiFile.getVirtualFile());

                final Matcher matcher = Pattern
                        .compile("create\\s+table\\s+(if\\s+not\\s+exists\\s+)?([a-zA-Z_0-9]+)", Pattern.CASE_INSENSITIVE)
                        .matcher(charSequence);

                try {
                    while (matcher.find()) {
                        if (matcher.groupCount() < 2) {
                            return;
                        }

                        tableNames.add(matcher.group(2));
                    }
                } catch (IllegalStateException e) {
                    // no matches
                }
            }
        }

        for (String name : tableNames) {
            completionResultSet.addElement(new LookupElement() {
                @NotNull
                @Override
                public String getLookupString() {

                    return name;
                }
            });
        }
    }
}

@@ -592,41 +592,16 @@
 php.
-lang.psi.elements.MethodReference
+PhpIndex
 ;%0Aim
@@ -641,29 +641,17 @@
 lements.
-ParameterList
+*
 ;%0Aimport
@@ -687,16 +687,45 @@
 tNull;%0A%0A
+import java.util.Collection;%0A
 import j
@@ -1898,32 +1898,126 @@
 ference.class);%0A
+                if (methodReference == null) %7B%0A                    return;%0A                %7D%0A%0A
                 
@@ -2195,32 +2195,61 @@
 etionResultSet);
+%0A%0A                    return;
 %0A               
@@ -2243,32 +2243,33 @@
               %7D%0A
+%0A
                 
@@ -2367,32 +2367,32 @@
 erForTable%22)) %7B%0A
-
                 
@@ -2457,16 +2457,1627 @@
 ultSet);
+%0A%0A                    return;%0A                %7D%0A%0A                String methodName = methodReference.getName();%0A                ClassReference classReference = PsiTreeUtil.getChildOfType(methodReference, ClassReference.class);%0A                if (classReference != null && methodName != null) %7B%0A                    String name = classReference.getFQN();%0A%0A                    // there can be multiple classes in one project scope that share the same FQN%0A                    Collection%3CPhpClass%3E phpClasses = PhpIndex.getInstance(element.getProject()).getClassesByFQN(name);%0A                    for (PhpClass c : phpClasses) %7B%0A                        Method method = c.findMethodByName(methodName);%0A%0A                        ParameterList originalMethodParameterList = PsiTreeUtil.getChildOfType(method, ParameterList.class);%0A                        if (originalMethodParameterList != null) %7B%0A                            Parameter firstParameter = PsiTreeUtil.getChildOfType(originalMethodParameterList, Parameter.class);%0A%0A                            // completion on method with no arguments%0A                            if (firstParameter == null) %7B%0A                                return;%0A                            %7D%0A%0A                            String parameterName = firstParameter.getName();%0A                            if (parameterName.equals(%22table%22) %7C%7C parameterName.equals(%22tableName%22)) %7B%0A                                completeAvailableTables(methodReference, completionResultSet);%0A%0A                                return;%0A                            %7D%0A                        %7D%0A                    %7D
 %0A       

Complete methods that carry the $table and $tableName attribute