package com.digiwin.log4j.layout;

import com.alibaba.fastjson.JSON;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.layout.AbstractStringLayout;
import org.apache.logging.log4j.core.util.Throwables;

import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.*;

@Plugin(name = "DWLog4jJsonLayout", category = "Core", elementType = "layout", printObject = true)
public class DWLog4jJsonLayout extends AbstractStringLayout {

    private final String appId;

    private final String appName;

    private final String source;

    private final List<String> CUSTOM_CONTENT_KEY_LIST ;

    protected DWLog4jJsonLayout(Charset charset, String appId, String appName, String source, List<String> customContentKeyList) {
        super(charset);
        this.appId = appId;
        this.appName = appName;
        this.source = source;
        this.CUSTOM_CONTENT_KEY_LIST = customContentKeyList;
    }

    @PluginFactory
    public static DWLog4jJsonLayout createLayout(
            @PluginAttribute(value = "charset", defaultString = "UTF-8") Charset charset,
            @PluginAttribute("appId") String appId,
            @PluginAttribute("appName") String appName,
            @PluginAttribute("source") String source,
            @PluginAttribute("customContentKey") String customContentKey) {
        List<String> customContentKeyList = new ArrayList<>();
        if (null != customContentKey && customContentKey.length() != 0){
             customContentKeyList = Arrays.asList(customContentKey.split(","));
        }
        return new DWLog4jJsonLayout(charset, appId, appName, source, customContentKeyList);
    }

    @Override
    public String toSerializable(LogEvent event) {
        Map<String, String> contextDataMap = event.getContextData().toMap();
        String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(event.getTimeMillis()));
        String traceId;
        Map<String, String> customContent = new HashMap<>();
        if (!contextDataMap.isEmpty()) {
            String ptxId = contextDataMap.get("PtxId");
            if (ptxId != null && !"".equals(ptxId)) {
                traceId = ptxId;
            } else {
                traceId = getUUID();
            }
            CUSTOM_CONTENT_KEY_LIST.forEach(key -> {
                if (Objects.nonNull(contextDataMap.get(key)))
                    customContent.put(key, contextDataMap.get(key));
            });
        } else {
            traceId = getUUID();
        }

        String throwable = "";
        if (event.getThrown() != null) {
            StringBuilder sb = new StringBuilder();
            boolean isFirst = true;
            for (String s : Throwables.toStringList(event.getThrown())) {
                if (isFirst) {
                    isFirst = false;
                } else {
                    sb.append(System.getProperty("line.separator"));
                }
                sb.append(s);
            }
            throwable = sb.toString();
        }

        String spanId = contextDataMap.getOrDefault("spanId", "");
        String nodeType = contextDataMap.getOrDefault("nodeType", "");
        String type = contextDataMap.getOrDefault("nodeType", "");
        String nodeId = contextDataMap.getOrDefault("nodeId", "");
        String currentNodeSpanId = contextDataMap.getOrDefault("currentNodeSpanId", "");
        String timeConsume = contextDataMap.getOrDefault("timeConsume", "0");
        String paramSize = contextDataMap.getOrDefault("paramSize", "0");
        String message = event.getMessage().getFormattedMessage();

        DWJsonLogInfo dwJsonLogInfo = new DWJsonLogInfo();
        dwJsonLogInfo.setAppId(appId);
        dwJsonLogInfo.setAppName(appName);
        dwJsonLogInfo.setSource(source);
        dwJsonLogInfo.setTime(time);
        dwJsonLogInfo.setThread(event.getThreadName());
        dwJsonLogInfo.setAppender("business-log-logstash");
        dwJsonLogInfo.setTraceId(traceId);
        dwJsonLogInfo.setSpanId(spanId);
        dwJsonLogInfo.setLevel(event.getLevel().toString());
        dwJsonLogInfo.setLoggerName(event.getLoggerName());
        dwJsonLogInfo.setNodeType(nodeType);
        dwJsonLogInfo.setType(type);
        dwJsonLogInfo.setNodeId(nodeId);
        dwJsonLogInfo.setCurrentNodeSpanId(currentNodeSpanId);
        dwJsonLogInfo.setTimeConsume(timeConsume);
        dwJsonLogInfo.setParamSize(paramSize);
        dwJsonLogInfo.setCustomContent(customContent);
        dwJsonLogInfo.setMessage(message);
        dwJsonLogInfo.setThrowable(throwable);

        return JSON.toJSONString(dwJsonLogInfo) + "\n";
    }

    private String getUUID() {
        return UUID.randomUUID().toString().replace("-", "");
    }
}
