package fr.adrienbrault.idea.symfony2plugin.intentions.yaml;

import com.intellij.codeInsight.hint.HintManager;
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.util.IncorrectOperationException;
import com.jetbrains.php.lang.psi.elements.PhpClass;
import fr.adrienbrault.idea.symfony2plugin.Symfony2ProjectComponent;
import fr.adrienbrault.idea.symfony2plugin.stubs.ContainerCollectionResolver;
import fr.adrienbrault.idea.symfony2plugin.translation.util.TranslationInsertUtil;
import fr.adrienbrault.idea.symfony2plugin.util.dict.ServiceTag;
import fr.adrienbrault.idea.symfony2plugin.util.dict.ServiceUtil;
import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper;
import org.apache.commons.lang.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.yaml.YAMLFileType;
import org.jetbrains.yaml.YAMLUtil;
import org.jetbrains.yaml.psi.YAMLCompoundValue;
import org.jetbrains.yaml.psi.YAMLKeyValue;
import org.jetbrains.yaml.psi.YAMLSequence;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @author Daniel Espendiller <daniel@espendiller.net>
 */
public class YamlServiceTagIntention extends PsiElementBaseIntentionAction {

    @Override
    public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement psiElement) {

        if(psiElement.getContainingFile().getFileType() != YAMLFileType.YML || !Symfony2ProjectComponent.isEnabled(psiElement.getProject())) {
            return false;
        }

        return YamlHelper.findServiceInContext(psiElement) != null;
    }

    @Override
    public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement psiElement) throws IncorrectOperationException {

        YAMLKeyValue serviceKeyValue = YamlHelper.findServiceInContext(psiElement);
        if(serviceKeyValue == null) {
            return;
        }

        Pair<PhpClass, Set<String>> invoke = invoke(project, serviceKeyValue);
        if(invoke == null) {
            return;
        }

        Set<String> phpClassServiceTags = invoke.getSecond();
        if(phpClassServiceTags.size() == 0) {
            HintManager.getInstance().showErrorHint(editor, "Ops, no possible Tag found");
            return;
        }

        PhpClass resolvedClassDefinition = invoke.getFirst();

        int appendEndOffset = -1;
        String insertString = null;

        YAMLKeyValue argumentsKeyValue = YamlHelper.getYamlKeyValue(serviceKeyValue, "tags");
        if(argumentsKeyValue == null) {

            // we dont an "tags" key so we need to create one

            String indent = StringUtil.repeatSymbol(' ', YAMLUtil.getIndentToThisElement(serviceKeyValue));

            List<String> yamlSequences = new ArrayList<>();
            for (String item : phpClassServiceTags) {
                ServiceTag serviceTag = new ServiceTag(resolvedClassDefinition, item);
                ServiceUtil.decorateServiceTag(serviceTag);
                yamlSequences.add(indent + " " + serviceTag.toYamlString());
            }

            appendEndOffset = serviceKeyValue.getTextRange().getEndOffset();

            String eol = TranslationInsertUtil.findEol(serviceKeyValue);
            insertString = eol + indent + "tags:" + eol + StringUtils.join(yamlSequences, eol);

        } else {

            // we found a "tags" key so update
            PsiElement value = argumentsKeyValue.getValue();
            if(!(value instanceof YAMLCompoundValue)) {
                HintManager.getInstance().showErrorHint(editor, "Sry, not supported tags definition");
                return;
            }

            PsiElement firstChild = value.getFirstChild();
            if(firstChild instanceof YAMLSequence) {

                String indent = StringUtil.repeatSymbol(' ', YAMLUtil.getIndentToThisElement(argumentsKeyValue));

                List<String> yamlSequences = new ArrayList<>();
                for (String item : phpClassServiceTags) {
                    ServiceTag serviceTag = new ServiceTag(resolvedClassDefinition, item);
                    ServiceUtil.decorateServiceTag(serviceTag);
                    yamlSequences.add(indent + serviceTag.toYamlString());
                }

                appendEndOffset = argumentsKeyValue.getTextRange().getEndOffset();

                String eol = TranslationInsertUtil.findEol(argumentsKeyValue);
                insertString = eol + StringUtils.join(yamlSequences, eol);
            }

        }

        if(appendEndOffset == -1) {
            HintManager.getInstance().showErrorHint(editor, "Sry, not supported service definition");
            return;
        }

        PsiDocumentManager manager = PsiDocumentManager.getInstance(project);
        Document document = manager.getDocument(serviceKeyValue.getContainingFile());
        if (document == null) {
            return;
        }

        document.insertString(appendEndOffset, insertString);
        manager.doPostponedOperationsAndUnblockDocument(document);
        manager.commitDocument(document);
    }

    @NotNull
    @Override
    public String getFamilyName() {
        return "Symfony";
    }

    @NotNull
    @Override
    public String getText() {
        return "Symfony: Add Tags";
    }

    @Nullable
    private static Pair<PhpClass, Set<String>> invoke(@NotNull Project project, @NotNull YAMLKeyValue serviceKeyValue) {

        String aClass = YamlHelper.getYamlKeyValueAsString(serviceKeyValue, "class");
        if(aClass == null|| StringUtils.isBlank(aClass)) {
            return null;
        }

        PhpClass resolvedClassDefinition = ServiceUtil.getResolvedClassDefinition(project, aClass, new ContainerCollectionResolver.LazyServiceCollector(project));
        if(resolvedClassDefinition == null) {
            return null;
        }

        Set<String> phpClassServiceTags = ServiceUtil.getPhpClassServiceTags(resolvedClassDefinition);

        Set<String> strings = YamlHelper.collectServiceTags(serviceKeyValue);
        if(strings.size() > 0) {
            for (String s : strings) {
                if(phpClassServiceTags.contains(s)) {
                    phpClassServiceTags.remove(s);
                }
            }
        }

        return Pair.create(resolvedClassDefinition, phpClassServiceTags);
    }

}

@@ -5863,16 +5863,17 @@
  == null
+ 
 %7C%7C Strin
@@ -5894,24 +5894,351 @@
 (aClass)) %7B%0A
+            PsiElement key = serviceKeyValue.getKey();%0A            if (key != null) %7B%0A                String text = key.getText();%0A                if (StringUtils.isNotBlank(text) && YamlHelper.isClassServiceId(text)) %7B%0A                    aClass = text;%0A                %7D%0A            %7D%0A        %7D%0A%0A        if(aClass == null) %7B%0A
             

add support for service class inside tag adding indention