package org.xyzh.system.log;

import org.apache.logging.log4j.core.LogEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.xyzh.common.dto.system.TbSysOperationLog;
import org.xyzh.common.utils.IDUtils;
import org.xyzh.system.mapper.SysOperationLogMapper;

import java.util.Date;

/**
 * @description 日志事件处理器 - 将日志事件转换并保存到数据库
 * @filename LogEventHandler.java
 * @author yslg
 * @copyright xyzh
 * @since 2025-10-30
 */
@Component
public class LogEventHandler {

    @Autowired
    private SysOperationLogMapper operationLogMapper;

    /**
     * @description 处理日志事件（异步）
     * @param context 日志事件上下文（包含HTTP上下文信息）
     */
    @Async("logExecutor")
    public void handleLogEvent(LogEventContext context) {
        try {
            // 处理 DEBUG 级别及以上的所有日志（由 ThresholdFilter 已过滤）
            // 这里不需要再次判断级别，直接保存即可
            TbSysOperationLog operationLog = buildOperationLog(context);
            operationLogMapper.insertOperationLog(operationLog);
        } catch (Exception e) {
            // 使用 System.err 而不是 logger，避免循环依赖
            System.err.println("保存日志到数据库失败: " + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * @description 构建操作日志对象
     */
    private TbSysOperationLog buildOperationLog(LogEventContext context) {
        LogEvent event = context.getLogEvent();
        TbSysOperationLog log = new TbSysOperationLog();
        
        log.setID(IDUtils.generateID());
        
        // 使用从主线程提取的用户信息
        log.setUserID(context.getUserId());
        log.setUsername(context.getUsername());
        
        // 日志基本信息
        log.setModule(event.getLoggerName());
        log.setOperation(event.getLevel().name());
        log.setMethod(event.getLoggerName());
        
        // 使用从主线程提取的请求信息
        log.setRequestUrl(context.getRequestUrl());
        log.setRequestMethod(context.getRequestMethod());
        log.setIpAddress(context.getIpAddress());
        log.setIpSource(context.getIpSource());
        log.setBrowser(context.getBrowser());
        log.setOs(context.getOs());
        
        // 日志消息和异常信息
        log.setResponseData(event.getMessage().getFormattedMessage());
        if (event.getThrown() != null) {
            log.setErrorMessage(getStackTrace(event.getThrown()));
            log.setStatus(0); // 失败
        } else {
            log.setStatus(1); // 成功
        }
        
        log.setExecuteTime(0); // 日志无执行时间
        log.setCreateTime(new Date(event.getTimeMillis()));
        
        return log;
    }

    /**
     * @description 获取异常堆栈信息
     */
    private String getStackTrace(Throwable throwable) {
        if (throwable == null) {
            return null;
        }
        
        StringBuilder sb = new StringBuilder();
        sb.append(throwable.getClass().getName()).append(": ").append(throwable.getMessage()).append("\n");
        
        StackTraceElement[] elements = throwable.getStackTrace();
        int maxLines = Math.min(elements.length, 10); // 只保留前10行
        for (int i = 0; i < maxLines; i++) {
            sb.append("\tat ").append(elements[i].toString()).append("\n");
        }
        
        if (elements.length > maxLines) {
            sb.append("\t... ").append(elements.length - maxLines).append(" more\n");
        }
        
        return sb.toString();
    }
}

