package com.thoughtworks.gauge.findUsages;

import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.indexing.FileBasedIndex;
import com.thoughtworks.gauge.annotator.FileManager;
import com.thoughtworks.gauge.language.psi.impl.ConceptStepImpl;
import com.thoughtworks.gauge.language.psi.impl.SpecStepImpl;
import com.thoughtworks.gauge.stub.FileStub;

import java.util.*;

public class StepCollector {

    private Project project;
    private HashMap<String, List<PsiElement>> stepTextToElement;

    public StepCollector(Project project) {
        this.project = project;
        stepTextToElement = new HashMap<>();
    }

    public void collect() {
        List<VirtualFile> conceptFiles = FileManager.getConceptFiles(project);
        List<VirtualFile> files = FileManager.getAllSpecFiles(project);
        files.addAll(conceptFiles);
        for (VirtualFile file : files) {
            List<Set<Integer>> values = FileBasedIndex.getInstance().getValues(FileStub.NAME, file.getPath(), GlobalSearchScope.allScope(project));
            PsiFile psiFile = PsiManager.getInstance(project).findFile(file);
            if (values.size() > 0) getSteps(psiFile, new HashSet<>(values.get(0)));
        }
    }

    public List<PsiElement> get(String stepText) {
        return stepTextToElement.get(stepText) == null ? new ArrayList<>() : stepTextToElement.get(stepText);
    }

    private void getSteps(PsiFile psiFile, Set<Integer> offsets) {
        for (Integer offset : offsets) {
            PsiElement stepElement = getStepElement(psiFile.findElementAt(offset));
            if (stepElement == null) continue;
            if (stepElement.getClass().equals(SpecStepImpl.class))
                addElement(stepElement, cleanText(((SpecStepImpl) stepElement).getStepValue().getStepText()));
            else
                addElement(stepElement, cleanText(((ConceptStepImpl) stepElement).getStepValue().getStepText()));
        }
    }

    private String cleanText(String text) {
        if (text == null || text.equals("")) return "";
        return text.charAt(0) == '*' || text.charAt(0) == '#' ? text.substring(1).trim() : text.trim();
    }

    private void addElement(PsiElement stepElement, String stepText) {
        List<PsiElement> elementsList = stepTextToElement.get(stepText);
        if (elementsList == null) {
            List<PsiElement> elements = new ArrayList<>();
            elements.add(stepElement);
            stepTextToElement.put(stepText, elements);
            return;
        }
        elementsList.add(stepElement);
    }

    private PsiElement getStepElement(PsiElement selectedElement) {
        if (selectedElement == null) return null;
        if (selectedElement.getClass().equals(SpecStepImpl.class) || selectedElement.getClass().equals(ConceptStepImpl.class))
            return selectedElement;
        return getStepElement(selectedElement.getParent());
    }
}