package pers.fw.tplugin.view;

import com.google.gson.Gson;
import com.google.gson.JsonIOException;
import com.google.gson.JsonSyntaxException;
import com.intellij.ide.highlighter.HtmlFileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
import com.intellij.psi.search.FilenameIndex;
import com.intellij.psi.search.GlobalSearchScope;

import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;

import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import pers.fw.tplugin.util.VfsExUtil;
import pers.fw.tplugin.view.dict.JsonTemplatePaths;
import pers.fw.tplugin.view.dict.TemplatePath;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;

/**
 * @author Daniel Espendiller <[email protected]>
 */
public class ViewCollector {
    /**
     * Default "view" path based on laravel versions
     */
    public static String curModule = "";
    public static TemplatePath[] DEFAULT_TEMPLATE_PATH;

    @NotNull
    public static Collection<TemplatePath> getPaths(@NotNull Project project) {
        return getPaths(project, false, false); //fowModify: true,true->false.false
    }

    @NotNull
    public static Collection<TemplatePath> getPaths(@NotNull Project project, boolean includeSettings, boolean includeJson) {
        Collection<TemplatePath> templatePaths = new ArrayList<>(Arrays.asList(DEFAULT_TEMPLATE_PATH));
        return templatePaths;
    }

    private static void collectIdeJsonBladePaths(@NotNull Project project, @NotNull Collection<TemplatePath> templatePaths) {
        for (PsiFile psiFile : FilenameIndex.getFilesByName(project, "ide-blade.json", GlobalSearchScope.allScope(project))) {
            Collection<TemplatePath> cachedValue = CachedValuesManager.getCachedValue(psiFile, new MyJsonCachedValueProvider(psiFile));
            if (cachedValue != null) {
                templatePaths.addAll(cachedValue);
            }
        }
    }

    /**
     * Visit all templates in project path configuration
     */
    public static void visitFile(@NotNull Project project, @NotNull ViewVisitor visitor) {
        //fowModify
//        for(TemplatePath templatePath : getPaths(project)) {
        Collection<TemplatePath> paths = getPaths(project, false, false);
        for (TemplatePath templatePath : paths) {
            visitTemplatePath(project, templatePath, visitor);
        }
    }

    /**
     * Visit all templates in given path
     */
    private static void visitTemplatePath(@NotNull Project project, @NotNull TemplatePath templatePath, @NotNull ViewVisitor visitor) {
        final VirtualFile templateDir = VfsUtil.findRelativeFile(templatePath.getPath(), project.getBaseDir());
        if (templateDir == null) {
            return;
        }

        VfsUtil.visitChildrenRecursively(templateDir, new VirtualFileVisitor() {
            @Override
            public boolean visitFile(@NotNull VirtualFile virtualFile) {
//                if (virtualFile.isDirectory() || !isTemplateFile(virtualFile)) {
                //修改, 不匹配后缀,view下的文件全为视图文件
                if (virtualFile.isDirectory()) {
                    return true;
                }

                String filename = VfsUtil.getRelativePath(virtualFile, templateDir, '/');
                if (filename == null || !filename.contains("/")) {
                    return true;
                }
                //fowModify:
//                filename = BladeTemplateUtil.stripTemplateExtensions(filename);
//                filename = clearStr(filename);
                filename = filename.substring(0, filename.lastIndexOf("."));//去掉后缀
                String namespace = templatePath.getNamespace();
                if (namespace != null && StringUtils.isNotBlank(namespace)) {
                    visitor.visit(virtualFile, namespace + "::" + filename);
                } else {
                    visitor.visit(virtualFile, filename);
                }

                return true;
            }


            /**
             * 清理多余字符,
             */
            private String clearStr(String filename) {
                filename = filename.substring(0, filename.length() - ".html".length());
                //如果没有module
                String prefix = filename.substring(0, curModule.length());
                if (curModule.equals(prefix)) {
                    int len = filename.length();
                    filename = filename.substring(curModule.length() + 1, len);
                }
                return filename;
            }

            private boolean isTemplateFile(VirtualFile virtualFile) {
//                if(virtualFile.getFileType() ==  BladeFileType.INSTANCE || virtualFile.getFileType() == PhpFileType.INSTANCE) {
                if (virtualFile.getFileType() == HtmlFileType.INSTANCE) {
                    return true;
                }

                String extension = virtualFile.getExtension();
//                if (extension != null && (extension.equalsIgnoreCase("php") || extension.equalsIgnoreCase("twig"))) {
                if (extension != null && (extension.equalsIgnoreCase("html")
                        || extension.equalsIgnoreCase("php")
                        || extension.equalsIgnoreCase("tpl")
                )) {
                    return true;
                }

                return false;
            }
        });
    }

    public interface ViewVisitor {
        void visit(@NotNull VirtualFile virtualFile, @NotNull String name);
    }

    private static class MyJsonCachedValueProvider implements CachedValueProvider<Collection<TemplatePath>> {
        private final PsiFile psiFile;

        public MyJsonCachedValueProvider(PsiFile psiFile) {
            this.psiFile = psiFile;
        }

        @Nullable
        @Override
        public Result<Collection<TemplatePath>> compute() {

            Collection<TemplatePath> twigPaths = new ArrayList<>();

            String text = psiFile.getText();
            JsonTemplatePaths configJson = null;
            try {
                configJson = new Gson().fromJson(text, JsonTemplatePaths.class);
            } catch (JsonSyntaxException | JsonIOException | IllegalStateException ignored) {
            }

            if (configJson == null) {
                return Result.create(twigPaths, psiFile, psiFile.getVirtualFile());
            }

            Collection<JsonTemplatePaths.Path> namespaces = configJson.getNamespaces();
            if (namespaces == null || namespaces.size() == 0) {
                return Result.create(twigPaths, psiFile, psiFile.getVirtualFile());
            }

            for (JsonTemplatePaths.Path jsonPath : namespaces) {
                String path = jsonPath.getPath();
                if (path == null) {
                    path = "";
                }

                path = StringUtils.stripStart(path.replace("\\", "/"), "/");
                PsiDirectory parent = psiFile.getParent();
                if (parent == null) {
                    continue;
                }

                // current directory check and subfolder
                VirtualFile twigRoot;
                if (path.length() > 0) {
                    twigRoot = VfsUtil.findRelativeFile(parent.getVirtualFile(), path.split("/"));
                } else {
                    twigRoot = psiFile.getParent().getVirtualFile();
                }

                if (twigRoot == null) {
                    continue;
                }

                String relativePath = VfsExUtil.getRelativeProjectPath(psiFile.getProject(), twigRoot);
                if (relativePath == null) {
                    continue;
                }

                String namespace = jsonPath.getNamespace();

                String namespacePath = StringUtils.stripStart(relativePath, "/");

                if (StringUtils.isNotBlank(namespace)) {
                    twigPaths.add(new TemplatePath(namespacePath, namespace, true));
                } else {
                    twigPaths.add(new TemplatePath(namespacePath, true));
                }
            }

            return Result.create(twigPaths, psiFile, psiFile.getVirtualFile());
        }
    }
}