package com.yida.data.log.aspect;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yida.data.common.core.entity.CurrentUser;
import com.yida.data.common.core.exception.FebsException;
import com.yida.data.common.core.utils.FebsUtil;
import com.yida.data.log.service.LogService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 操作日志切面类
 *
 * @author ZYJ
 * @date 2021/1/8
 */
@Aspect
@Component
@Slf4j
@EnableAsync
@RequiredArgsConstructor
public class OperationLogAspect {

    private final LogService logService;

    /**
     * 处理操作日志数据
     *
     * @param joinPoint ProceedingJoinPoint类
     * @return java.lang.Object
     * @author ZYJ
     * @date 2021/3/19 11:06
     */
    @Around("@annotation(com.yida.data.log.annotation.OperationLog)")
    public Object insertOperationLog(ProceedingJoinPoint joinPoint) throws Throwable {
        //返回结果
        Object result;
        HttpServletRequest request = ((ServletRequestAttributes) Objects
            .requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        //请求参数
        String params = getRequestParams(joinPoint, request);
        //执行接口
        result = joinPoint.proceed();
        //异步保存日志
        Long createId = null;
        String createName = null;
        if (FebsUtil.isLogin()) {
            CurrentUser currentUser = FebsUtil.getCurrentUser();
            if (currentUser != null) {
                createId = currentUser.getUserId();
                createName = currentUser.getUsername();
            }
        }
        logService.saveOperationLog(joinPoint, FebsUtil.getHttpServletRequestIpAddress(), params, result, createId,
            createName);
        return result;
    }

    /**
     * 获取请求参数
     *
     * @param joinPoint ProceedingJoinPoint类
     * @param request   HttpServletRequest类
     * @return java.lang.String
     * @author ZYJ
     * @date 2021/1/11 14:21
     */
    private static String getRequestParams(ProceedingJoinPoint joinPoint, HttpServletRequest request) {
        //得到请求参数值
        Object[] args = joinPoint.getArgs();

        //获取请求头
        String contentType = request.getContentType();
        //判断是否为application/json请求
        if (StrUtil.isNotBlank(contentType) && (MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(contentType) || contentType
            .equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE))) {
            //设置请求参数
            List<Object> objList = new ArrayList<>();
            //循环获取参数值
            for (Object arg : args) {
                if (arg instanceof HttpServletRequest
                    || arg instanceof HttpServletResponse
                    || arg instanceof MultipartFile) {
                    continue;
                }
                objList.add(arg);
            }
            return JSON.toJSONString(objList);
        }
        //得到请求参数名称
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        String[] parameterNames = methodSignature.getParameterNames();
        //返回值
        JSONObject jsonObject = new JSONObject();
        //循环获取参数值
        for (int i = 0; i < args.length; i++) {
            Object arg = args[i];
            if (arg instanceof HttpServletRequest
                || arg instanceof HttpServletResponse
                || arg instanceof MultipartFile) {
                continue;
            }
            jsonObject.put(parameterNames[i], arg);
        }
        return jsonObject.toJSONString();
    }
}
