package me.dadus33.chatitem.json;


import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.bukkit.ChatColor;

//Based on DarkSeraphim's system, but using Gson and supporting some more edge cases
public class Translator {

    private static final String STYLES = "klmnor"; //All style codes

    public static JsonArray toJson(String old){
        if(old.lastIndexOf(ChatColor.COLOR_CHAR) == -1){
            JsonArray arr = new JsonArray();
            JsonObject obj = new JsonObject();
            obj.addProperty("text", old);
            arr.add(obj);
            return arr;
        }
        boolean startsWithCode = old.startsWith(Character.toString(ChatColor.COLOR_CHAR));
        JsonArray message = new JsonArray();
        String[] parts = old.split(Character.toString(ChatColor.COLOR_CHAR));
        JsonObject next = null; //refers to the object we created before (in time) but next in the message, as we're going from end to start
        for(int i = parts.length-1; i >= 0; --i){ //We go in reverse order
            String part = parts[i];

            if(part.isEmpty()){
                continue;
            }

            if(i == 0 && !startsWithCode){
                JsonObject toAdd = new JsonObject();
                toAdd.addProperty("text", part);
                message.add(toAdd);
                break;
            }

            char code = Character.toLowerCase(part.charAt(0));

            if(!isColorOrStyle(code)){
                if(next != null){
                    String text = next.get("text").getAsString();
                    text = ChatColor.COLOR_CHAR + part + text;
                    next.addProperty("text", text);
                }else{
                    JsonObject added = new JsonObject();
                    added.addProperty("text", ChatColor.COLOR_CHAR + part);
                    message.add(added);
                    next = added;
                }
                continue;
            }

            if(part.length() == 1){ //If it's just format and no text, we try to format the next element, if it wasn't formatted already (and it's not null)
                if(next == null){
                    continue;
                }

                if(isStyle(code)){
                    next.addProperty(getStyleName(code), true);
                }else{ //it's a color
                    if(isAlreadyColored(next)){
                        continue;
                    }
                    next.addProperty("color", getColorName(code));
                }
                continue;
            }
            //Last possibility that remains is that we have a normal color/format + text situation
            JsonObject added = new JsonObject();
            added.addProperty("text", part.substring(1));
            if(isStyle(code)){
                added.addProperty(getStyleName(code), true);
                message.add(added);
                next = added;
                continue;
            }
            //else it can only be a color
            added.addProperty("color", getColorName(code));
            //also try to color the next element if not colored already
            if(next != null){
                if(!isAlreadyColored(next)){
                    next.addProperty("color", getColorName(code));
                }
            }
            message.add(added);
            next = added;
        }

        int i = message.size()-1;
        JsonArray orderedMessage = new JsonArray();//This is where we'll store the reverted message (in proper order for being sent to the client)
        //First we have to copy all elements
        for(JsonElement el : message){
            orderedMessage.add(el);
        }
        for(JsonElement element : message){
            JsonObject obj = (JsonObject) element;
            orderedMessage.set(i, obj); //And then we add the object to the properly ordered array
            --i;
        }

        return orderedMessage;
    }

    private static String getColorName(char code){
        return ChatColor.getByChar(code).name().toLowerCase();
    }

    private static String getStyleName(char code){
        switch(code){
            case 'k': return "obfuscated";
            case 'l': return "bold";
            case 'm': return "strikethrough";
            case 'n': return "underlined";
            case 'o': return "italic";
            case 'r': return "reset";
            default: return null; //Should never happen. Made it return null to throw errors if a new format pops up and it really happens
        }
    }

    private static boolean isColorOrStyle(char code){
        return ChatColor.getByChar(code) != null;
    }

    private static boolean isStyle(char c){
        return STYLES.indexOf(c) != -1;
    }

    private static boolean isAlreadyColored(JsonObject obj){
        return obj.has("color");
    }

}