package net.seesharpsoft.intellij.plugins.csv.editor;

import com.intellij.lang.annotation.*;
import com.intellij.openapi.editor.markup.TextAttributes;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.vcs.ui.FontUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.xml.util.XmlStringUtil;
import net.seesharpsoft.intellij.plugins.csv.CsvColumnInfo;
import net.seesharpsoft.intellij.plugins.csv.CsvHelper;
import net.seesharpsoft.intellij.plugins.csv.CsvValueSeparator;
import net.seesharpsoft.intellij.plugins.csv.psi.CsvFile;
import net.seesharpsoft.intellij.plugins.csv.psi.CsvTypes;
import net.seesharpsoft.intellij.plugins.csv.settings.CsvColorSettings;
import net.seesharpsoft.intellij.plugins.csv.settings.CsvEditorSettings;
import org.jetbrains.annotations.NotNull;

import static com.intellij.lang.annotation.HighlightSeverity.INFORMATION;

@SuppressWarnings("MagicNumber")
public class CsvAnnotator implements Annotator {

    protected static final Key<TextAttributes> TAB_SEPARATOR_HIGHLIGHT_COLOR_KEY = Key.create("CSV_PLUGIN_TAB_SEPARATOR_HIGHLIGHT_COLOR");
    protected static final Key<Boolean> TAB_SEPARATOR_HIGHLIGHT_COLOR_DETERMINED_KEY = Key.create("CSV_PLUGIN_TAB_SEPARATOR_HIGHLIGHT_COLOR_DETERMINED");
    protected static final Key<Boolean> SHOW_INFO_BALLOON_KEY = Key.create("CSV_PLUGIN_SHOW_INFO_BALLOON");

    public static final HighlightSeverity CSV_COLUMN_INFO_SEVERITY =
            new HighlightSeverity("CSV_COLUMN_INFO_SEVERITY", INFORMATION.myVal);

    @Override
    public void annotate(@NotNull final PsiElement element, @NotNull final AnnotationHolder holder) {
        IElementType elementType = CsvHelper.getElementType(element);
        if ((elementType != CsvTypes.FIELD && elementType != CsvTypes.COMMA) || !(element.getContainingFile() instanceof CsvFile)) {
            return;
        }

        CsvFile csvFile = (CsvFile) element.getContainingFile();
        if (handleSeparatorElement(element, holder, elementType, csvFile)) {
            return;
        }

        CsvColumnInfo<PsiElement> columnInfo = csvFile.getColumnInfoMap().getColumnInfo(element);

        if (columnInfo != null) {
            PsiElement headerElement = columnInfo.getHeaderElement();
            String message = FontUtil.getHtmlWithFonts(
                    XmlStringUtil.escapeString(headerElement == null ? "" : headerElement.getText(), true)
            );
            String tooltip = null;
            if (showInfoBalloon(holder.getCurrentAnnotationSession())) {
                tooltip = XmlStringUtil.wrapInHtml(
                        String.format("%s<br /><br />Header: %s<br />Index: %d",
                                FontUtil.getHtmlWithFonts(
                                        XmlStringUtil.escapeString(element.getText(), true)
                                ),
                                message,
                                columnInfo.getColumnIndex() + (CsvEditorSettings.getInstance().isZeroBasedColumnNumbering() ? 0 : 1)
                        )
                );
            }

            holder.newAnnotation(CSV_COLUMN_INFO_SEVERITY, message)
                    .range(element)
                    .tooltip(tooltip)
                    .enforcedTextAttributes(
                            CsvEditorSettings.getInstance().getValueColoring() == CsvEditorSettings.ValueColoring.RAINBOW ?
                                    CsvColorSettings.getTextAttributesOfColumn(columnInfo.getColumnIndex(), holder.getCurrentAnnotationSession()) :
                                    null
                    )
                    .needsUpdateOnTyping(false)
                    .create();
        }
    }

    protected boolean showInfoBalloon(@NotNull AnnotationSession annotationSession) {
        Boolean showInfoBalloon = annotationSession.getUserData(SHOW_INFO_BALLOON_KEY);
        if (showInfoBalloon == null) {
            showInfoBalloon = CsvEditorSettings.getInstance().isShowInfoBalloon();
            annotationSession.putUserData(SHOW_INFO_BALLOON_KEY, showInfoBalloon);
        }
        return showInfoBalloon;
    }

    protected boolean handleSeparatorElement(@NotNull PsiElement element, @NotNull AnnotationHolder holder, IElementType elementType, CsvFile csvFile) {
        if (elementType == CsvTypes.COMMA) {
            TextAttributes textAttributes = holder.getCurrentAnnotationSession().getUserData(TAB_SEPARATOR_HIGHLIGHT_COLOR_KEY);
            if (!Boolean.TRUE.equals(holder.getCurrentAnnotationSession().getUserData(TAB_SEPARATOR_HIGHLIGHT_COLOR_DETERMINED_KEY))) {
                CsvValueSeparator separator = CsvHelper.getValueSeparator(csvFile);
                if (CsvEditorSettings.getInstance().isHighlightTabSeparator() && separator.equals(CsvValueSeparator.TAB)) {
                    textAttributes = new TextAttributes(null,
                            CsvEditorSettings.getInstance().getTabHighlightColor(),
                            null, null, 0);
                    holder.getCurrentAnnotationSession().putUserData(TAB_SEPARATOR_HIGHLIGHT_COLOR_KEY, textAttributes);
                    holder.getCurrentAnnotationSession().putUserData(TAB_SEPARATOR_HIGHLIGHT_COLOR_DETERMINED_KEY, Boolean.TRUE);
                }
            }
            if (textAttributes != null) {
                holder.newAnnotation(CSV_COLUMN_INFO_SEVERITY, showInfoBalloon(holder.getCurrentAnnotationSession()) ? "↹" : null)
                        .range(element)
                        .enforcedTextAttributes(textAttributes)
                        .needsUpdateOnTyping(false)
                        .create();
            }
            return true;
        }
        return false;
    }
}

@@ -3116,32 +3116,70 @@
   %7D%0A%0A           
+ AnnotationBuilder annotationBuilder =
  holder.newAnnot
@@ -3280,98 +3280,53 @@
    .
-tooltip(tooltip)%0A                    .enforcedTextAttributes(%0A                            
+needsUpdateOnTyping(false);%0A%0A            if (
 CsvE
@@ -3414,18 +3414,19 @@
 .RAINBOW
- ?
+) %7B
 %0A       
@@ -3434,36 +3434,57 @@
         
-                    
+annotationBuilder.enforcedTextAttributes(
 CsvColor
@@ -3584,18 +3584,18 @@
 ssion())
- :
+);
 %0A       
@@ -3591,32 +3591,34 @@
 ));%0A            
+%7D%0A
                 
@@ -3613,32 +3613,38 @@
         
-           
+if (tooltip !=
  null
+) %7B
 %0A       
@@ -3648,38 +3648,72 @@
             
+annotationBuilder.tooltip(tooltip);%0A
     
-)%0A
         
             
@@ -3692,32 +3692,35 @@
 p);%0A            
+%7D%0A%0A
             .nee
@@ -3719,56 +3719,25 @@
     
-.needsUpdateOnTyping(false)%0A                    
+annotationBuilder
 .cre
@@ -5362,32 +5362,89 @@
 tributes != null
+ && showInfoBalloon(holder.getCurrentAnnotationSession())
 ) %7B%0A            
@@ -5498,74 +5498,11 @@
 TY, 
-showInfoBalloon(holder.getCurrentAnnotationSession()) ? %22%E2%86%B9%22 : null
+%22%E2%86%B9%22
 )%0A  

Fix "Exception when Show info balloon is not selected"