

package com.unis.crk.utils;

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.unis.crk.basic.entity.UserOperationlog;
import com.unis.crk.basic.entity.UserOperationtype;
import com.unis.crk.basic.service.IUserInfoService;
import com.unis.crk.basic.service.IUserOperationlogService;
import com.unis.crk.basic.service.IUserOperationtypeService;
import com.unis.crk.basic.util.TokenUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
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.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

@Aspect
@Component
public class WebLogAspect {

    @Autowired
    private IUserOperationlogService userOperationlogService;
    @Autowired
    private IUserOperationtypeService userOperationtypeService;
    @Autowired
    private IUserInfoService userInfoService;

    private final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);

    @Pointcut("execution(public * com.unis.crk.*.controller.*.*(..))")//切入点描述 这个是controller包的切入点
    public void controllerLog() {
    }//签名，可以理解成这个切入点的一个名称


    /**
     * 获取参数名以及参数值
     *
     * @param entityName
     * @return
     * @throws Exception
     */
    public static String getProperty(Object entityName) throws Exception {

        Class c = entityName.getClass();
        String s = "实体类："+c.getName();
        /*Field field[] = c.getDeclaredFields();
        for (Field f : field) {
            Object v = invokeMethod(entityName, f.getName(), null);
            s += f.getName() + "  : " + v  + ";";
        }*/
        return s;
    }

    private static Object invokeMethod(Object owner, String methodName,
                                       Object[] args) throws Exception {
        Class ownerClass = owner.getClass();
        methodName = methodName.substring(0, 1).toUpperCase()
                + methodName.substring(1);
        Method method = null;
        try {
            method = ownerClass.getMethod("get" + methodName);
        } catch (SecurityException e) {
        } catch (NoSuchMethodException e) {
            return null;
        }
        return method.invoke(owner);
    }

    @Before("controllerLog() ") //在切入点的方法run之前要干的
    public void logBeforeController(JoinPoint joinPoint) throws Exception {


        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();//这个RequestContextHolder是Springmvc提供来获得请求的东西
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        StringBuffer requestURL = request.getRequestURL();
        String token = request.getHeader("token");
        String reMethod = request.getMethod();
            //判断是否有token
           if(StrUtil.isNotBlank(token)){


        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取方法的参数，是数组，这里获取第一个参数
        Method method = signature.getMethod();
        ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
        //获取类注解
        Api annotation = AnnotationUtils.findAnnotation(signature.getMethod().getDeclaringClass(), Api.class);
        String value = annotation.value();
        //获取方法上@ApiOperation注解的value值
               String apiOperationValue = apiOperation.value();
        UserOperationlog userOperationlog = new UserOperationlog();
        UserOperationtype userOperationtype = new UserOperationtype();


        DecodedJWT decodedJWT = TokenUtil.getDecodedJWT(token);
        if (decodedJWT != null && !requestURL.toString().contains("get") && !requestURL.toString().contains("find")) {
          //根据请求方式获取参数
            String property = null;
            if ("POST".equals(request.getMethod()) || "PATCH".equals(request.getMethod())) {
                Object[] args = joinPoint.getArgs();
                property = getProperty(args[0]);
            } else {
                Object[] args = joinPoint.getArgs();
                String[] argNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames();
                if(args!=null && args.length>0 && argNames!=null && argNames.length>0){
                    String s = argNames[0];
                    String s1 = args[0].toString();
                    property=s+":"+s1;
                }
            }
            //获取用户信息
            String username = decodedJWT.getClaim("username").asString();
            String userId = decodedJWT.getClaim("userId").asString();
            //保存操作类型
            userOperationtype.setParameterName(value + "" + apiOperationValue);
            userOperationtype.setOperationUrl(requestURL.toString());
            userOperationtype.setDescribes("");
           // userOperationtype.setDescribes(property);
            userOperationtype.setUpdatetime(new Date());
            userOperationtypeService.save(userOperationtype);
            String uotId = userOperationtype.getUotId();
            //保存操作记录
            userOperationlog.setParameter("");
            //userOperationtype.setDescribes(property);
            userOperationlog.setUotId(uotId);
            userOperationlog.setUserId(Integer.parseInt(userId));
            userOperationlog.setOperationTime(new Date());
            userOperationlogService.save(userOperationlog);
        }
           }


    }

    /**
     * 将异常输入日志中
     * @param joinPoint
     * @param e
     */
    @AfterThrowing(pointcut = "controllerLog()", throwing = "e")
    public void saveExceptionLog(JoinPoint joinPoint, Throwable e) {
        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes
                .resolveReference(RequestAttributes.REFERENCE_REQUEST);
        String token = request.getHeader("token");
        StringBuffer requestURL = request.getRequestURL();
        UserOperationlog userOperationlog = new UserOperationlog();
        UserOperationtype userOperationtype = new UserOperationtype();

        try {
            // 从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            // 获取切入点所在的方法
            Method method = signature.getMethod();
            ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
            //获取类注解
            Api annotation = AnnotationUtils.findAnnotation(signature.getMethod().getDeclaringClass(), Api.class);
            String value = annotation.value();
            String apiOperationValue = apiOperation.value();
            // 获取请求的类名
            String className = joinPoint.getTarget().getClass().getName();
            // 获取请求的方法名
            String methodName = method.getName();
            methodName = className + "." + methodName;
            // 请求的参数
            String property = null;
            if ("POST".equals(request.getMethod()) || "PATCH".equals(request.getMethod())) {
                Object[] args = joinPoint.getArgs();
                property = getProperty(args[0]);
            } else {
                String[] parameterNames = ((MethodSignature) joinPoint.getSignature()).getParameterNames();
                if(parameterNames.length>0){
                property = parameterNames[0].toString();
                }
            }


            //保存操作类型
            userOperationtype.setParameterName(value + "" + apiOperationValue);
            userOperationtype.setOperationUrl(requestURL.toString());
            userOperationtype.setDescribes(property);
            userOperationtype.setUpdatetime(new Date());
            userOperationtypeService.saveOrUpdate(userOperationtype);
            String uotId = userOperationtype.getUotId();
            //保存操作记录
            userOperationlog.setParameter(e.getClass().getName() + ":" + stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()));
            userOperationlog.setUotId(uotId);
            userOperationlog.setOperationTime(new Date());

            if(StrUtil.isNotBlank(token)){
                DecodedJWT decodedJWT = TokenUtil.getDecodedJWT(token);
                Object userId = decodedJWT.getClaim("userId");
                if (!((Claim) userId).isNull()){
                    userOperationlog.setUserId(Integer.parseInt(userId.toString()));
                }
            }else{
                userOperationlog.setUserId(0);

            }
            userOperationlogService.save(userOperationlog);

        } catch (Exception e2) {
//            e2.printStackTrace();
        }

    }
    /**
     * 转换异常信息为字符串
     *
     * @param exceptionName    异常名称
     * @param exceptionMessage 异常信息
     * @param elements         堆栈信息
     */
    public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
        StringBuffer strbuff = new StringBuffer();
        for (StackTraceElement stet : elements) {
            boolean unis = stet.toString().contains("unis");
            if(unis){
            strbuff.append(stet + "\n");
            }

        }
        String message = exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString();
        return message;
    }
}
