package com.mini.capi.utils;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.locks.ReentrantLock;


public class LoggerUtils {

    // 日志级别
    public enum Level {
        DEBUG, INFO, WARN, ERROR
    }

    // 单例实例
    private static volatile LoggerUtils instance;

    // 日志文件根路径（默认：/ogsapp/logs/cApi）
    private String baseLogPath;

    // 日期格式（文件名：yyyyMMdd，日志内容时间戳：yyyy-MM-dd HH:mm:ss.SSS）
    private final SimpleDateFormat fileDateFormat = new SimpleDateFormat("yyyyMMdd");
    private final SimpleDateFormat logDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

    // 线程安全锁
    private final ReentrantLock lock = new ReentrantLock();

    // 禁止外部实例化
    private LoggerUtils(String baseLogPath) {
        this.baseLogPath = baseLogPath;
        initLogDir(); // 初始化日志目录
    }

    /**
     * 获取单例实例（使用默认日志目录：/ogsapp/logs/cApi）
     */
    public static LoggerUtils getInstance() {
        return getInstance("/ogsapp/logs/cApi");
    }

    /**
     * 获取单例实例（自定义日志路径）
     *
     * @param baseLogPath 日志根目录（支持相对路径或绝对路径）
     */
    public static LoggerUtils getInstance(String baseLogPath) {
        if (instance == null) {
            synchronized (LoggerUtils.class) {
                if (instance == null) {
                    instance = new LoggerUtils(baseLogPath);
                }
            }
        }
        return instance;
    }

    /**
     * 初始化日志目录（若不存在则创建多级目录）
     */
    private void initLogDir() {
        try {
            Files.createDirectories(Paths.get(baseLogPath));
        } catch (IOException e) {
            throw new RuntimeException("初始化日志目录失败：" + baseLogPath, e);
        }
    }

    /**
     * 获取当前日志文件路径（按日期拆分：baseLogPath/log_yyyyMMdd.txt）
     */
    private String getCurrentLogFilePath(Level level) {
        String fileName = level + "_" + fileDateFormat.format(new Date()) + ".log";
        return baseLogPath + File.separator + fileName;
    }

    // ------------------------------ 日志方法（支持多类型可变参数） ------------------------------

    /**
     * 记录DEBUG级别日志（支持1到多个任意类型参数）
     */
    public void debug(Object... messages) {
        log(Level.DEBUG, joinMessages(messages), null);
    }

    /**
     * 记录INFO级别日志（支持1到多个任意类型参数）
     */
    public void info(Object... messages) {
        log(Level.INFO, joinMessages(messages), null);
    }

    /**
     * 记录WARN级别日志（支持1到多个任意类型参数）
     */
    public void warn(Object... messages) {
        log(Level.WARN, joinMessages(messages), null);
    }

    /**
     * 记录WARN级别日志（支持1到多个任意类型参数+异常）
     */
    public void warn(Object[] messages, Throwable throwable) {
        log(Level.WARN, joinMessages(messages), throwable);
    }

    /**
     * 记录ERROR级别日志（支持1到多个任意类型参数）
     */
    public void error(Object... messages) {
        log(Level.ERROR, joinMessages(messages), null);
    }

    /**
     * 记录ERROR级别日志（支持1到多个任意类型参数+异常）
     */
    public void error(Object[] messages, Throwable throwable) {
        log(Level.ERROR, joinMessages(messages), throwable);
    }

    // ------------------------------ 核心方法 ------------------------------

    /**
     * 核心日志写入逻辑
     */
    private void log(Level level, String message, Throwable throwable) {
        // 构建日志内容
        StringBuilder logContent = new StringBuilder();
        logContent.append("[").append(logDateFormat.format(new Date())).append("] "); // 时间戳
        logContent.append("[").append(level.name()).append("] "); // 日志级别
        logContent.append("[Thread-").append(Thread.currentThread().getId()).append("] "); // 线程ID
        logContent.append(message); // 拼接后的消息

        // 追加异常堆栈信息（如果有）
        if (throwable != null) {
            logContent.append("\n").append(getStackTrace(throwable));
        }
        logContent.append("\n"); // 每条日志换行

        // 加锁写入文件（保证线程安全）
        lock.lock();
        try (BufferedWriter writer = new BufferedWriter(
                new OutputStreamWriter(
                        new FileOutputStream(getCurrentLogFilePath(level), true), // 追加模式
                        StandardCharsets.UTF_8 // 避免中文乱码
                )
        )) {
            writer.write(logContent.toString());
            writer.flush();
        } catch (IOException e) {
            System.err.println("日志写入失败：" + e.getMessage());
        } finally {
            lock.unlock();
        }
    }

    /**
     * 拼接多类型可变参数为单个字符串（自动转换任意类型为字符串，处理null）
     *
     * @param messages 1到多个任意类型参数（不可为空数组）
     * @return 拼接后的字符串
     */
    private String joinMessages(Object... messages) {
        if (messages == null || messages.length == 0) {
            throw new IllegalArgumentException("日志消息至少需要1个参数");
        }
        StringBuilder sb = new StringBuilder();
        for (Object msg : messages) {
            // 任意类型转换为字符串：null转为"null"，其他类型调用String.valueOf()
            sb.append(String.valueOf(msg));
        }
        return sb.toString();
    }

    /**
     * 异常堆栈信息转为字符串
     */
    private String getStackTrace(Throwable throwable) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        throwable.printStackTrace(pw);
        return sw.toString();
    }

    /**
     * 动态修改日志路径
     */
    public void setBaseLogPath(String baseLogPath) {
        this.baseLogPath = baseLogPath;
        initLogDir();
    }
}