package org.example.Api;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.example.Entity.System.LoginUserInfo;
import org.example.Impl.BaseImpl;
import org.example.Utils.DateTimeUtil;
import org.example.Utils.DbOperator;
import org.example.Utils.NativeExtensionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;


import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 系统日志记录入口
 */
@Service
public class LoggerHandler {
    @Autowired
    private static JdbcTemplate jdbcTemplate;
    private static final Log log = LogFactory.getLog(LoggerHandler.class);
    private static final Lock lockObj = new ReentrantLock();
    private static Date lastCheckDate = new Date();

    public static void debug(Object happenobj, Object message) {
        if (log.isDebugEnabled()) {
            try {
                log.debug(new LogInfo(happenobj).setMsg(message));
            } catch (Exception e) {
                error(message, e);
            }
        }
    }

    public static void debug(Object happenobj, Object message, Exception exception) {
        if (log.isDebugEnabled()) {
            try {
                log.debug(new LogInfo(happenobj).setMsg(message).setException(exception));
            } catch (Exception e) {
                error(message, e);
            }
        }
    }

    public static void error(Object happenobj, Object message) {
        if (log.isErrorEnabled()) {
            try {
                log.error(new LogInfo(happenobj).setMsg(message));
            } catch (Exception e) {
                error(message, e);
            }
        }
    }

    public static void error(Object happenobj, Object message, Exception exception) {
        if (log.isErrorEnabled()) {
            try {
                log.error(new LogInfo(happenobj).setMsg(message).setException(exception));
            } catch (Exception ignored) {
            }
        }
    }

    public static void fatal(Object happenobj, Object message) {
        if (log.isFatalEnabled()) {
            try {
                log.fatal(new LogInfo(happenobj).setMsg(message));
            } catch (Exception e) {
                error(message, e);
            }
        }
    }

    public static void fatal(Object happenobj, Object message, Exception exception) {
        if (log.isFatalEnabled()) {
            try {
                log.fatal(new LogInfo(happenobj).setMsg(message).setException(exception));
            } catch (Exception e) {
                error(message, e);
            }
        }
    }

    public static void info(Object happenobj, Object message) {
        if (log.isInfoEnabled()) {
            try {
                log.info(new LogInfo(happenobj).setMsg(message));
            } catch (Exception e) {
                error(message, e);
            }
        }
    }

    public static void info(Object happenobj, Object message, Exception exception) {
        if (log.isInfoEnabled()) {
            try {
                log.info(new LogInfo(happenobj).setMsg(message).setException(exception));
            } catch (Exception e) {
                error(message, e);
            }
        }
    }

    public static void warn(Object happenobj, Object message) {
        if (log.isWarnEnabled()) {
            try {
                log.warn(new LogInfo(happenobj).setMsg(message));
            } catch (Exception e) {
                error(message, e);
            }
        }
    }

    public static void warn(Object happenobj, Object message, Exception exception) {
        if (log.isWarnEnabled()) {
            try {
                log.warn(new LogInfo(happenobj).setMsg(message).setException(exception));
            } catch (Exception e) {
                error(message, e);
            }
        }
    }

    public static void dbLog(Object happenobj, DbOperator dbOperator, String level, String dllcoid,
                             String method, String args, double passT, String msg, Exception exception) {
//        String conStr = dbOperator.ConnectionString;
//        if (conStr == null || conStr.isEmpty()) {
//            return;
//        }

        LogInfo info = new LogInfo(happenobj).setMsg(msg).setException(exception);
        String sql = String.format(
                "insert into %s (level, operatorId, operatorName, dllcoid, className, method, args, passTime, msg) " +
                        "values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s'); select @@identity;",
                "p_sysWebProLogTab",
                level,
                info.getUserFId(),
                info.getOperatorName(),
                dllcoid,
                info.getClassname(),
                method,
                args.replace("'", "\""),
                passT,
                msg.replace("'", "\"")
        );

//        if (dbOperator.hasLogTab())
        if (NativeExtensionUtils.isNullOrEmpty(jdbcTemplate)) {
            DateTimeUtil.setTimeOut(() -> {
                try {
//                    DbOperator _dbOperator = new DbOperator(jdbcTemplate);
                    String id = jdbcTemplate.queryForObject(sql, String.class) + "";
                    if ("error".equals(level)) {
                        error(happenobj, "请到日志表p_sysWebProLogTab中查看详细信息，日志id" + id);
                    }
                } catch (Exception ignored) {
                }
            }, 1);
        } else if ("error".equals(level) && (new Date().getTime() - lastCheckDate.getTime()) > 600000) {
            lastCheckDate = new Date();
            error(happenobj, "日志表p_sysWebProLogTab未创建，请先创建，然后重启应用程序，再在日志表中查看详细信息！创建语句如下：\n" +
                    "CREATE TABLE [dbo].[p_sysWebProLogTab](\n" +
                    "    [id] [bigint] PRIMARY KEY IDENTITY(1,1) NOT NULL,\n" +
                    "    [level] varchar(10),\n" +
                    "    [className] varchar(100),\n" +
                    "    [operatorId] varchar(100),\n" +
                    "    [operatorName] varchar(100),\n" +
                    "    [dllcoId] varchar(100) NULL,\n" +
                    "    [passTime] decimal(18,2) NULL,\n" +
                    "    [method] varchar(100) NULL,\n" +
                    "    [args] text NULL,\n" +
                    "    [msg] text NULL,\n" +
                    "    [happenTime] datetime not NULL default getdate())");
        }
    }

    static class LogInfo {
        private final Object happenobj;
        private Object msg;
        private Exception exception;
        private String classname;
        private LoginUserInfo user;
        private String userId;

        public LogInfo(Object happenobj) {
            this.happenobj = happenobj;
        }

        public LogInfo setMsg(Object msg) {
            this.msg = msg;
            return this;
        }

        public LogInfo setException(Exception exception) {
            this.exception = exception;
            return this;
        }

        public String getClassname() {
            if (classname == null && happenobj != null) {
                String hname = happenobj.getClass().getName();
                String[] parts = hname.split("\\.");
                hname = parts[parts.length - 1];
                if (!hname.isEmpty()) {
                    classname = hname.substring(0, 1) +
                            hname.substring(hname.length() - 2, hname.length() - 1) +
                            "_" + hname.length();
                    classname = classname.toUpperCase();
                } else {
                    classname = "";
                }
            }
            return classname;
        }

        private LoginUserInfo getUser() {
            if (user == null) {
                if (happenobj != null) {
                    try {
                        Field field = happenobj.getClass().getDeclaredField("user");
                        field.setAccessible(true);
                        user = (LoginUserInfo) field.get(happenobj);
                    } catch (Exception ignored) {
                    }
                }
                if (user == null) {
                    user = new BaseImpl().getUser();
                }
            }
            return user;
        }

        public String getUserId() {
            if (userId == null) {
                String actualUserId = getUserFId();
                if (actualUserId != null && !actualUserId.isEmpty()) {
                    userId = actualUserId.substring(0, 1) +
                            "**************************".substring(0, actualUserId.length() - 1);
                    userId = userId.toUpperCase();
                } else {
                    userId = "";
                }
            }
            return userId;
        }

        public String getUserFId() {
            if (userId == null) {
                LoginUserInfo u = getUser();
                if (u != null) {
                    userId = u.UserId != null ? u.UserId : u.UserName;
                } else {
                    userId = "";
                }
            }
            return userId;
        }

        public String getOperatorName() {
            LoginUserInfo u = getUser();
            if (u != null) {
                return u.UserName != null ? u.UserName : u.UserId;
            }
            return "";
        }

        public String getOperatorId() {
            String name = getOperatorName();
            if (!name.isEmpty()) {
                return name.substring(0, 1) +
                        "**************************".substring(0, name.length() - 1);
            }
            return "";
        }

        @Override
        public String toString() {
            return msg != null ? msg.toString() : "";
        }
    }
}