package com.stdproject.common;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.stdproject.entity.AppOptLog;
import com.stdproject.service.IAppOptLogService;
import com.stdproject.utils.JwtUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;


import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;

/**
 * 操作日志切面
 *
 * @author StdProject
 */
@Aspect
@Component
@Slf4j
public class OperationLogAspect {

    @Autowired
    private IAppOptLogService appOptLogService;

    @Autowired
    private JwtUtils jwtUtils;

    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 定义切点
     */
    @Pointcut("@annotation(com.stdproject.common.OperationLog)")
    public void operationLogPointcut() {
    }

    /**
     * 正常返回通知
     */
    @AfterReturning(pointcut = "operationLogPointcut()", returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, Object result) {
        handleLog(joinPoint, null, result);
    }

    /**
     * 异常通知
     */
    @AfterThrowing(pointcut = "operationLogPointcut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
        handleLog(joinPoint, e, null);
    }

    /**
     * 处理日志记录
     */
    private void handleLog(JoinPoint joinPoint, Exception e, Object result) {
        try {
            // 获取注解信息
            OperationLog operationLog = getAnnotationLog(joinPoint);
            if (operationLog == null) {
                return;
            }

            // 获取请求信息
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes == null) {
                return;
            }
            HttpServletRequest request = attributes.getRequest();

            // 创建操作日志对象
            AppOptLog optLog = new AppOptLog();
            
            // 设置基本信息
            optLog.setOpttype(operationLog.type());
            optLog.setModule(operationLog.module());
            optLog.setDescription(operationLog.description());
            optLog.setMethod(request.getMethod() + " " + request.getRequestURI());
            optLog.setRequestip(getIpAddress(request));
            optLog.setBrowser(request.getHeader("User-Agent"));
            optLog.setLogtime(LocalDateTime.now());

            // 设置操作用户
            String token = request.getHeader("Authorization");
            if (token != null && token.startsWith("Bearer ")) {
                token = token.substring(7);
                try {
                    String username = jwtUtils.getUsernameFromToken(token);
                    optLog.setUsername(username);
                } catch (Exception ex) {
                    log.warn("解析JWT token失败: {}", ex.getMessage());
                }
            }

            // 设置请求参数
            if (operationLog.recordParams()) {
                String methodParams = getMethodParams(joinPoint);
                optLog.setParams(methodParams);
            }            

            // 保存日志
            appOptLogService.save(optLog);

        } catch (Exception ex) {
            log.error("记录操作日志异常: {}", ex.getMessage(), ex);
        }
    }

    /**
     * 获取注解信息
     */
    private OperationLog getAnnotationLog(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        return method.getAnnotation(OperationLog.class);
    }

    /**
     * 获取方法参数
     */
    private String getMethodParams(JoinPoint joinPoint) {
        try {
            Object[] args = joinPoint.getArgs();
            if (args == null || args.length == 0) {
                return "";
            }
            String params = objectMapper.writeValueAsString(Arrays.asList(args));
            if (params.length() > 2000) {
                params = params.substring(0, 2000) + "...";
            }
            return params;
        } catch (Exception e) {
            return "参数序列化失败";
        }
    }

    /**
     * 获取客户端IP地址
     */
    private String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}