package com.dayou.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.dayou.annotation.OperLog;
import com.dayou.entity.OperationLog;
import com.dayou.enums.OperationTypeEnum;
import com.dayou.service.IOperationLogService;
import com.dayou.utils.HttpKit;
import com.dayou.utils.IpUtils;
import com.dayou.utils.LoginContext;
import com.dayou.utils.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 类说明：
 *
 * @author: wucl
 * @since: 2023/1/16
 * created with IntelliJ IDEA.
 */
@Slf4j
@Component
@Aspect
public class OperationLogAop {

    @Autowired
    private IOperationLogService operationLogService;

    @AfterReturning("@annotation(operLog)")
    public void operationLogAround(JoinPoint joinPoint, OperLog operLog){
        try {
            OperationLog operationLog = new OperationLog();
            HttpServletRequest request = HttpKit.getRequest();
            Long userId = LoginContext.getUserId();
            String userName = LoginContext.getUserName();
            Object[] args = joinPoint.getArgs();
            getControllerMethodDescription(operLog,operationLog,args);
            operationLog.setUserId(userId);
            operationLog.setUserName(userName);
            operationLog.setOperationUrl(request.getRequestURI());
            operationLog.setIp(IpUtils.getIpAddr(request));
            operationLog.setOperationTime(LocalDateTime.now());
            operationLogService.save(operationLog);

        } catch (Exception e) {
            throw new RuntimeException(e);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取注解中对方法的描述信息 用于Controller层注解
     *
     * @param log     日志
     * @param operLog 操作日志
     * @throws Exception
     */
    public void getControllerMethodDescription(OperLog log, OperationLog operLog, Object[] args) throws Exception {
        String method = SpringContextHolder.currentReq().getMethod();
        OperationTypeEnum operationTypeEnum = null;
        if (log.businessType() == OperationTypeEnum.DEFAULT_OP) {
            if (HttpMethod.POST.name().equalsIgnoreCase(method)) {
                operationTypeEnum = OperationTypeEnum.ADD;
            } else if (HttpMethod.PUT.name().equalsIgnoreCase(method)) {
                operationTypeEnum = OperationTypeEnum.EDIT;
            } else if (HttpMethod.DELETE.name().equalsIgnoreCase(method)) {
                operationTypeEnum = OperationTypeEnum.DELETE;
            } else {
                operationTypeEnum = OperationTypeEnum.DEFAULT_OP;
            }
        } else {
            operationTypeEnum = log.businessType();
        }

        // 设置action动作
        operLog.setOperationType(operationTypeEnum.getCode());
        // 设置标题
        operLog.setTitle(log.title());
        // 是否需要保存request，参数和值
        // 获取参数的信息，传入到数据库中。
        setRequestValue(operLog, args);
    }

    /**
     * 获取请求的参数，放到log中
     *
     * @param operLog 操作日志
     * @throws Exception 异常
     */
    private void setRequestValue(OperationLog operLog, Object[] args) throws Exception {
        List<?> param = new ArrayList<>(Arrays.asList(args)).stream().filter(p -> !(p instanceof ServletResponse))
                .filter(e -> !(e instanceof MultipartFile))
                .collect(Collectors.toList());
        String params = "{}";
        try {
            params = JSON.toJSONString(param, true);
            log.debug("args:{}", param);
        } catch (JSONException e) {
            log.error("记录日志出错 请求参数param json 转换失败  ", e);
        }
        // 数据过长
        if (params.length() > 1500) {
            params = params.substring(0, 1500);
        }
        operLog.setOperationParam(params);
    }
}
