package net.detunized.unfuckjs;

import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.lang.javascript.JSElementTypes;
import com.intellij.lang.javascript.psi.*;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.intellij.idea.lang.javascript.psiutil.BinaryOperatorUtils;
import org.intellij.idea.lang.javascript.psiutil.JSElementFactory;
import org.jetbrains.annotations.NotNull;

public class UnfuckJsIntention extends PsiElementBaseIntentionAction {
    @Override
    public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement psiElement) throws IncorrectOperationException {
        JSStatement statement = PsiTreeUtil.getParentOfType(psiElement, JSStatement.class);
        if (statement != null)
            unfuckStatement(statement);
    }

    private void unfuckStatement(JSStatement s) {
        if (s instanceof JSExpressionStatement)
            unfuckExpressionStatement((JSExpressionStatement)s);
        else if (s instanceof JSReturnStatement) {
            unfuckReturnStatement((JSReturnStatement)s);
        }
    }

    private void unfuckExpressionStatement(JSExpressionStatement s) {
        JSExpression e = s.getExpression();
        if (e instanceof JSCommaExpression) {
            splitComma(s, (JSCommaExpression)e);
        } else if (e instanceof JSBinaryExpression) {
            JSBinaryExpression be = (JSBinaryExpression)e;
            String op = BinaryOperatorUtils.getOperatorText(be.getOperationSign());
            if (op.equals("&&")) {
                convertAndToIf(s, be);
            }
        }
    }

    private void unfuckReturnStatement(JSReturnStatement s) {
        JSExpression e = s.getExpression();
        if (e instanceof JSCommaExpression) {
            splitComma(s, (JSCommaExpression)e, "return");
        }
    }

    private void splitComma(JSStatement s, JSCommaExpression e) {
        splitComma(s, e, "");
    }

    // TODO: Add support for while, for and others
    // keyword: return, throw
    private void splitComma(JSStatement s, JSCommaExpression e, String keyword) {
        String lhs = e.getLOperand().getText() + ';';
        String rhs = appendSpace(keyword) + e.getROperand().getText() + ';';

        JSStatement parent = PsiTreeUtil.getParentOfType(s, JSStatement.class);
        if (parent instanceof JSIfStatement) {
            JSIfStatement ifStatement = (JSIfStatement)parent;
            if (s == ifStatement.getThen() || s == ifStatement.getElse()) {
                JSBlockStatement block = (JSBlockStatement)JSElementFactory.replaceStatement(s, '{' + lhs + rhs + '}');

                for (JSStatement i: block.getStatements())
                    unfuckStatement(i);
            }
        } else {
            JSStatement ns1 = JSElementFactory.replaceStatement(s, lhs);
            JSStatement ns2 = JSElementFactory.addStatementAfter(ns1, rhs);

            unfuckStatement(ns1);
            unfuckStatement(ns2);
        }
    }

    private void convertAndToIf(JSStatement s, JSBinaryExpression e) {
        JSElementFactory.replaceStatement(s, String.format(
                "if (%s) { %s; }",
                e.getLOperand().getText(),
                e.getROperand().getText()));
    }

    private String appendSpace(String text) {
        return text.isEmpty() ? text : text + ' ';
    }

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

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

    @NotNull
    @Override
    public String getText() {
        return "Unfuck some";
    }
}

@@ -3238,16 +3238,51 @@
         
+JSIfStatement ifs = (JSIfStatement)
 JSElemen
@@ -3307,16 +3307,33 @@
 atement(
+%0A                
 s, Strin
@@ -3358,16 +3358,24 @@
         
+       
+ 
 %22if (%25s)
@@ -3385,16 +3385,24 @@
 %25s; %7D%22,%0A
+        
         
@@ -3448,24 +3448,32 @@
             
+      
+  
 e.getROperan
@@ -3488,16 +3488,57 @@
 ext()));
+%0A%0A        unfuckStatement(ifs.getThen());
 %0A    %7D%0A%0A

Apply fixes recursively