package aicare.net.cn.sdk.ailinksdkdemoandroid.utils;

import android.content.Context;
import android.os.Handler;
import android.os.HandlerThread;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;

import com.google.gson.Gson;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

/**
 * 打印日志工具
 */
public class L {
    /**
     * 是否开启log日志
     */
    private static boolean isLog = false;
    private static String TAG = "TagOther";
    private static MyDiskLogStrategy myDiskLogStrategy;
    private static int MAX_BYTES = 2048 * 1024;//2M
    /**
     * 缓存行数量
     */
    private static int CACHE_NUMBER_LINES = 100;//list大小
    private static HandlerThread mHandlerThread;
    private static Gson mGson;
    private static long mId = 0;

    /**
     * 获取默认日志路径,不是以/ 结尾
     *
     * @param context 上下文
     * @return {@link String}
     */
    public static String getDefaultLogPath(Context context) {
        if (myDiskLogStrategy!=null) {
            myDiskLogStrategy.saveCache();
        }
        return context.getFilesDir().getPath() + File.separatorChar + "logger";
    }

    public static String getDefaultLogName() {
        return "logs.txt";
    }

    /**
     * 日志初始化
     * 注意:路径只能是内置缓存路径,否则可能会导致写入失败
     *
     * @param isShowLog 是否打印日志
     * @param diskPath  磁盘路径
     * @param fileName  文件名称
     */
    public static void init(String diskPath, String fileName, boolean isShowLog) {
        isLog = isShowLog;
        mGson = new Gson();
        mHandlerThread = new HandlerThread(TAG);
        mHandlerThread.start();

        Handler mHandler = new MyDiskLogStrategy.WriteHandler(mHandlerThread.getLooper(), diskPath, fileName, MAX_BYTES,CACHE_NUMBER_LINES);
        myDiskLogStrategy = new MyDiskLogStrategy(mHandler);
    }

    /**
     * 详细日志
     */
    public static void v(String tag, String msg) {
        if (isLog) {
            logContent(tag, msg, 4);
        }
    }

    public static void v(String msg) {
        v("", msg);
    }

    /**
     * 错误日志
     */
    public static void e(String tag, String msg) {
        if (isLog) {
            logContent(tag, msg, 1);
        }
        L.write(msg);
    }

    /**
     * 错误日志
     */
    public static void eJson(String tag, String msg, Class c) {
        e(tag, mGson.toJson(msg, c));
    }


    public static void e(String msg) {
        e("", msg);
    }

    /**
     * 警告日志
     */
    public static void w(String tag, String msg) {
        if (isLog) {
            logContent(tag, msg, 3);
        }
    }

    public static void w(String msg) {
        w("", msg);
    }

    public static void iJson(String msg, Class c) {
        i("", mGson.toJson(msg, c));
    }

    /**
     * 信息日志
     */
    public static void i(String tag, String msg) {
        if (isLog) {
            logContent(tag, msg, 0);
        }
    }

    public static void iStack(String msg) {
        if (isLog) {
            logContent("", msg+"\n"+Log.getStackTraceString(new Throwable()), 0);
        }
    }

    /**
     * 信息日志
     */
    public static void iw(String msg) {
        iw("", msg);
    }

    /**
     * 信息日志
     */
    public static void iw(String tag, String msg) {
        if (isLog) {
            logContent(tag, msg, 0);
        }
        L.write(msg);
    }

    /**
     * 信息日志
     */
    public static void iwJson(String tag, Object msg, Class c) {
        if (isLog) {
            logContent(tag, mGson.toJson(msg, c), 0);
        }
        L.writeJson(msg, c);
    }

    public static void write(String msg) {
        logContent(msg);
    }

    public static void writeJson(Object msg, Class c) {
        write(mGson.toJson(msg, c));
    }

    public static void iNoCode(Object msg) {
        String newMsg = "未识别的指令:" + msg;
        i("", newMsg);
    }

    public static void i(String msg) {
        i("", msg);
    }

    /**
     * 调试日志
     */
    public static void d(String tag, String msg) {
        if (isLog) {
            logContent(tag, msg, 2);
        }
    }

    public static void d(String msg) {
        d("", msg);
    }


    /**
     * 退出写文件线程
     */
    public static void quit() {
        if (mHandlerThread != null)
            mHandlerThread.quit();
    }


    private static void logContent(String msg) {
        logContent("", msg, 0, true);
    }

    /**
     * @param msg   内容
     * @param level 0=i;1=e;2=d;3=w;
     */
    private static void logContent(String tag, String msg, int level) {
        logContent(tag, msg, level, false);
    }


    /**
     * @param tag   tag
     * @param msg   内容
     * @param level 0=i;1=e;2=d;3=w;其他=v;
     * @param isW   是否写入文件
     */
    private static void logContent(String tag, String msg, int level, boolean isW) {
        try {
            StackTraceElement[] trace = Thread.currentThread().getStackTrace();
            int methodCount = 1;
            int stackOffset = getStackOffset(trace);
            if (methodCount + stackOffset > trace.length) {
                methodCount = trace.length - stackOffset - 1;
            }
            for (int i = methodCount; i > 0; i--) {
                int stackIndex = i + stackOffset;
                if (stackIndex >= trace.length) {
                    continue;
                }

                StackTraceElement element = trace[stackIndex];
                if (isW) {
                    if (myDiskLogStrategy != null) {
                        myDiskLogStrategy.log(getLogContent(msg, element));
                    }
                    return;
                }
                if (TextUtils.isEmpty(tag)) {
                    tag = getTag(element);
                }
                switch (level) {
                    case 0:
                        Log.i(tag, getLogContent(msg, element));
                        break;
                    case 1:
                        Log.e(tag, getLogContent(msg, element));
                        break;
                    case 2:
                        Log.d(tag, getLogContent(msg, element));
                        break;
                    case 3:
                        Log.w(tag, getLogContent(msg, element));
                        break;
                    default:
                        Log.v(tag, msg);
                        break;
                }


            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String getTag(StackTraceElement element) {
        String tag = "Tag_" + getModuleName(element.getClassName()) + "_" + getSimpleClassName(element.getClassName());
        return tag;
    }


    private static String getLogContent(String msg, StackTraceElement element) {
        StringBuilder builder = new StringBuilder();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
        String time = sdf.format(new Date());
        builder.append("-------------------------------------------------------\n")
                .append("|").append(" ID:").append(mId++).append("\n")
                .append("|").append(time).append("\n")
                .append("|").append(getSimpleClassName(element.getClassName())).append(".").append(element.getMethodName()).append(" ").append(" (").append(element.getFileName()).append(":")
                .append(element.getLineNumber()).append(")").append("\n")
                .append("||==>").append(msg).append("\n")
                .append("-------------------------------------------------------\n");
        return builder.toString();
    }


    private static int getStackOffset(StackTraceElement[] trace) {
        for (int i = 2; i < trace.length; i++) {
            StackTraceElement e = trace[i];
            String name = e.getClassName();
            String l = L.class.getName();
            if (!name.equals(l)) {
                return --i;
            }
        }
        return -1;
    }

    private static String getSimpleClassName(@NonNull String name) {
        int lastIndex = name.lastIndexOf(".");
        return name.substring(lastIndex + 1);
    }

    private static String getModuleName(@NonNull String name) {
        String[] split = name.split("\\.");
        String moduleName = "";
        if (split.length > 2) {
            moduleName = split[2];
        }
        return moduleName;
    }

}
