package com.jwipc.log.annotation.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.jwipc.log.annotation.AuditLogInter;
import com.jwipc.security.LoginUtil;
import com.jwipc.sys.entity.AuditLog;
import com.jwipc.sys.service.IAuditLogService;
import com.jwipc.util.RequestUtil;
import org.apache.catalina.connector.ResponseFacade;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author qizhicai
 * @version JDK 1.8
 * @date 2025/11/20
 * @description TODO
 */
@Aspect
@Component
@Order(1) // 优先级最高，确保先执行
public class AuditLogAspect {
    private static final Logger logger = LoggerFactory.getLogger(AuditLogAspect.class);

    @Autowired
    private IAuditLogService auditLogService;

    @Autowired
    private HttpServletRequest request;

    // 定义切点 - 标注了@AuditLogInter注解的方法
    @Pointcut("@annotation(com.jwipc.log.annotation.AuditLogInter)")
    public void auditLogPointCut() {}

    @Around("auditLogPointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long beginTime = System.currentTimeMillis();
        // 执行方法
        Object result = joinPoint.proceed();
        // 执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        // 保存日志
        saveAuditLog(joinPoint, time, result);
        return result;
    }

    private void saveAuditLog(ProceedingJoinPoint joinPoint, long time, Object result) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        AuditLog auditLog = new AuditLog();
        AuditLogInter annotation = method.getAnnotation(AuditLogInter.class);
        if (annotation != null) {
            // 注解上的描述
            auditLog.setOperation(annotation.value());
            auditLog.setModule(annotation.module());
        }

        // 请求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        auditLog.setMethod(className + "." + methodName + "()");

        // 请求的参数
        Object[] args = joinPoint.getArgs();
        List<Object> businessArgs = new ArrayList<>();
        // 过滤掉 Spring 内部对象
        for (Object arg : args) {
            if (arg instanceof BindingResult || arg instanceof ModelMap || arg instanceof Model
                    || arg instanceof HttpServletRequest ||
                    arg instanceof HttpServletResponse ||
                    arg instanceof HttpSession ||
                    arg instanceof ResponseFacade) {
                continue;
            }
            businessArgs.add(arg);
        }
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); // 允许空的bean
            String params = objectMapper.writeValueAsString(businessArgs);
            auditLog.setParams(params);
        } catch (Exception e) {
            logger.error("记录日志参数解析异常", e);
            String simpleParams = Arrays.toString(args);
            logger.info("简化参数: " + simpleParams);
        }

        // 获取request
        String ip = RequestUtil.getIpAddress(request);
        auditLog.setIp(ip);

        // 设置操作时间和执行时间
        auditLog.setOperationTime(LocalDateTime.now());
        auditLog.setExecutionTime(time);
        // 获取当前用户
        try {
            auditLog.setUserId(Long.valueOf(LoginUtil.getUserId()));
            auditLog.setUserName(LoginUtil.getName());
        } catch (Exception e) {
            auditLog.setUserId(0L);
            auditLog.setUserName("system");
        }
        // 使用异步服务保存
        auditLogService.saveAuditLogAsync(auditLog);
    }
}
