package com.cm.common.aspect;

import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.fastjson.JSON;
import com.cm.common.component.SecurityComponent;
import com.cm.common.plugin.pojo.vos.systemlogger.SystemLoggerVO;
import com.cm.common.plugin.service.systemlogger.ISystemLoggerService;
import com.cm.common.pojo.bos.UserInfoBO;
import com.cm.common.utils.DateUtil;
import com.cm.common.utils.RequestUtil;
import com.cm.common.utils.UUIDUtil;
import com.cm.common.utils.WMapUtil;
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.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.InputStreamSource;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;

/**
 * @ClassName: ApiLogAspect
 * @Description: 接口日志切面
 * @Author: WangGeng
 * @Date: 2019/3/14 9:33 AM
 * @Version: 1.0
 **/
@Aspect
@Component
@Order(2)
public class ApiLogAspect {

    @Autowired
    private SecurityComponent securityComponent;
    @Autowired
    private ISystemLoggerService systemLoggerService;
    @Value("${logging.enable-syslog:false}")
    private Boolean enableSyslog;

    /**
     * api切入点
     */
    @Pointcut("execution(public * com.cm.*.controller.apis..*.*(..))")
    public void apiCutPoint() {
    }

    @Around("apiCutPoint()")
    public Object apiLogAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        if (enableSyslog == null || !enableSyslog) {
            return proceedingJoinPoint.proceed();
        }
        return logAroundForApi(proceedingJoinPoint);
    }

    /**
     * resources切入点
     */
    @Pointcut("execution(public * com.cm.*.controller.resources..*.*(..))")
    public void resourceCutPoint() {
    }

    @Around("resourceCutPoint()")
    public Object resourcesLogAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        if (enableSyslog == null || !enableSyslog) {
            return proceedingJoinPoint.proceed();
        }
        return logAroundForResource(proceedingJoinPoint);
    }

    /**
     * app切入点
     */
    @Pointcut("execution(public * com.cm.*.controller.app..*.*(..))")
    public void appCutPoint() {
    }

    @Around("appCutPoint()")
    public Object appLogAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        if (enableSyslog == null || !enableSyslog) {
            return proceedingJoinPoint.proceed();
        }
        return logAroundForApp(proceedingJoinPoint);
    }

    /**
     * api日志环绕
     *
     * @param proceedingJoinPoint
     * @return
     */
    private Object logAroundForApi(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        HttpServletRequest request = RequestUtil.getRequest();
        Signature signature = proceedingJoinPoint.getSignature();
        StringBuilder paramValue = getParams(proceedingJoinPoint);
        return apiResult(proceedingJoinPoint, request, signature, paramValue);
    }

    /**
     * resource日志环绕
     *
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    private Object logAroundForResource(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        HttpServletRequest request = RequestUtil.getRequest();
        String accessToken = request.getParameter("access_token");
        Signature signature = proceedingJoinPoint.getSignature();
        StringBuilder paramValue = getParams(proceedingJoinPoint);
        return resourceAndAppResult(proceedingJoinPoint, request, signature, paramValue, accessToken);
    }

    /**
     * app日志环绕
     *
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    private Object logAroundForApp(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        HttpServletRequest request = RequestUtil.getRequest();
        String accessToken = request.getHeader("accessToken");
        Signature signature = proceedingJoinPoint.getSignature();
        StringBuilder paramValue = getParams(proceedingJoinPoint);
        return resourceAndAppResult(proceedingJoinPoint, request, signature, paramValue, accessToken);
    }

    private StringBuilder getParams(ProceedingJoinPoint proceedingJoinPoint) {
        StringBuilder paramValue = new StringBuilder();
        Object[] args = proceedingJoinPoint.getArgs();
        for (Object arg : args) {
            // 去除无效的参数
            if (arg instanceof WebStatFilter.StatHttpServletResponseWrapper) {
                continue;
            }
            // 文件过滤
            if (arg instanceof InputStreamSource) {
                continue;
            }
            if (paramValue.length() > 0) {
                paramValue.append("_wg_");
            }
            try {
                paramValue.append(JSON.toJSONString(arg));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return paramValue;
    }

    private Object apiResult(ProceedingJoinPoint proceedingJoinPoint, HttpServletRequest request, Signature signature, StringBuilder paramValue) throws Throwable {
        Object result;
        try {
            long startTime = System.currentTimeMillis();
            result = proceedingJoinPoint.proceed();
            long endTime = System.currentTimeMillis();
            long usedTime = endTime - startTime;
            String currentTime = DateUtil.getTime();
            SystemLoggerVO systemLoggerVO = new SystemLoggerVO();
            systemLoggerVO.setHost(request.getRemoteAddr());
            systemLoggerVO.setPort(request.getLocalPort());
            systemLoggerVO.setRequestIp(RequestUtil.getRequestIp());
            systemLoggerVO.setContextPath(request.getContextPath());
            systemLoggerVO.setUri(request.getRequestURI().replace(request.getContextPath(), ""));
            systemLoggerVO.setParameterValues(paramValue.toString());
            systemLoggerVO.setClassNameFull(signature.getDeclaringTypeName());
            systemLoggerVO.setClassName(signature.getDeclaringType().getSimpleName());
            systemLoggerVO.setMethodName(signature.getName());
            systemLoggerVO.setStartTime(startTime);
            systemLoggerVO.setEndTime(endTime);
            systemLoggerVO.setUsedTime(usedTime);
            // systemLoggerVO.setResponseResult(result == null ? "null" : JSON.toJSONString(result));
            Map<String, Object> params = WMapUtil.beanToMapObj(systemLoggerVO);
            params.put("systemLoggerId", UUIDUtil.getUUID());
            params.put("gmtCreate", currentTime);
            params.put("gmtModified", currentTime);
            UserInfoBO userInfoBO = securityComponent.getCurrentUser();
            if (null != userInfoBO) {
                String userId = userInfoBO.getUserId();
                String userUsername = userInfoBO.getUserUsername();
                params.put("creator", userId);
                params.put("creatorName", userUsername);
            }
            systemLoggerService.saveSystemLogger(params);
        } catch (Throwable e) {
            throw e;
        }
        return result;
    }

    private Object resourceAndAppResult(ProceedingJoinPoint proceedingJoinPoint, HttpServletRequest request, Signature signature, StringBuilder paramValue, String accessToken) throws Throwable {
        Object result;
        long startTime = System.currentTimeMillis();
        result = proceedingJoinPoint.proceed();
        long endTime = System.currentTimeMillis();
        long usedTime = endTime - startTime;
        String currentTime = DateUtil.getTime();
        SystemLoggerVO systemLoggerVO = new SystemLoggerVO();
        systemLoggerVO.setHost(request.getRemoteAddr());
        systemLoggerVO.setPort(request.getLocalPort());
        systemLoggerVO.setRequestIp(RequestUtil.getRequestIp());
        systemLoggerVO.setContextPath(request.getContextPath());
        systemLoggerVO.setUri(request.getRequestURI().replace(request.getContextPath(), ""));
        systemLoggerVO.setParameterValues(paramValue.toString());
        systemLoggerVO.setClassNameFull(signature.getDeclaringTypeName());
        systemLoggerVO.setClassName(signature.getDeclaringType().getSimpleName());
        systemLoggerVO.setMethodName(signature.getName());
        systemLoggerVO.setStartTime(startTime);
        systemLoggerVO.setEndTime(endTime);
        systemLoggerVO.setUsedTime(usedTime);
        // systemLoggerVO.setResponseResult(result == null ? "null" : JSON.toJSONString(result));
        Map<String, Object> params = WMapUtil.beanToMapObj(systemLoggerVO);
        params.put("systemLoggerId", UUIDUtil.getUUID());
        params.put("gmtCreate", currentTime);
        params.put("gmtModified", currentTime);
        params.put("creator", accessToken);
        params.put("creatorName", "client");
        systemLoggerService.saveSystemLogger(params);
        return result;
    }

}
