package com.jpsoft.shinestar.advice;

import com.jpsoft.shinestar.modules.common.dto.MessageResult;
import com.jpsoft.shinestar.modules.common.utils.HttpUtil;
import com.jpsoft.shinestar.modules.sys.entity.SysLog;
import com.jpsoft.shinestar.modules.sys.service.PermissionService;
import com.jpsoft.shinestar.modules.sys.service.SysLogService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
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.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
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 PermissionAdvice {
    private  Logger logger= LoggerFactory.getLogger("root");

    @Autowired
    private SysLogService sysLogService;

    @Autowired
    private PermissionService permissionService;

    @Pointcut("(execution(public * com.jpsoft.shinestar..controller.*.*(..)))")
    public void pointcut(){

    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long start = System.currentTimeMillis();

        String classType = point.getTarget().getClass().getName();
        Class<?> clazz = Class.forName(classType);
        String clazzName = clazz.getName();
        String clazzSimpleName = clazz.getSimpleName();
        String methodName = point.getSignature().getName();

        // 通过正则表达式判断当前url是否符合
        //PathMatcher matcher = new AntPathMatcher();

        StringBuilder pathBuilder = new StringBuilder();

        //查询类的RequestMapping注解
        RequestMapping classMapping = clazz.getAnnotation(RequestMapping.class);

        if(classMapping != null && classMapping.value().length>0){
            pathBuilder.append(classMapping.value()[0]);
        }

        //查询方法的RequestMapping注解
        MethodSignature methodSignature = (MethodSignature)point.getSignature();
        Method method = methodSignature.getMethod();

        RequestMapping methodMapping = method.getAnnotation(RequestMapping.class);

        if(methodMapping != null && methodMapping.value().length>0){
            String subPath = methodMapping.value()[0];

            if(!subPath.startsWith("/")){
                pathBuilder.append("/");
            }

            pathBuilder.append(subPath);
        }

        ServletRequestAttributes requestAttrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        Object obj = null;
        SysLog sysLog = new SysLog();

        if(requestAttrs!=null) {
            HttpServletRequest request = requestAttrs.getRequest();

            sysLog.setRemoteIp(HttpUtil.getIpAddress(request));
            sysLog.setUrl(request.getRequestURI());

            logger.warn("访问地址：" + request.getRequestURL().toString());
            logger.warn("path=" + pathBuilder.toString());

            //1.这里获取到所有的参数值的数组
            Object[] args = point.getArgs();
            String[] parameterNames = methodSignature.getParameterNames();

            StringBuilder argBuilder = new StringBuilder();

            for (int i = 0;i<Math.min(args.length, parameterNames.length);i++) {
                if (argBuilder.length()!=0){
                    argBuilder.append("&");
                }

                if(args[i] != null) {
                    String value = args[i].toString();
                    value = value.length() > 100 ? value.substring(0, 100) : value;

                    if (parameterNames[i].equals("password")){
                        value = "******";
                    }

                    argBuilder.append(parameterNames[i] + "=" + value);
                }
            }

            sysLog.setData(argBuilder.toString());

            String userId = (String)request.getAttribute("subject");

            boolean existed = permissionService.exist(pathBuilder.toString(), request.getMethod());

            // 查询该url是否加入到权限控制中,如果是则查询当前用户是否能访问该url
            if (existed) {
                logger.warn(pathBuilder.toString() + "已加入权限控制");

                boolean permitted = permissionService.hasPermitted(userId, pathBuilder.toString(), request.getMethod());
                logger.warn("是否许可当前用户访问:" + permitted);

                if(permitted){
                    // 执行切入方法
                    obj = point.proceed();
                }
                else{
                    MessageResult<String> msgResult = new MessageResult<>();
                    msgResult.setCode(401);
                    msgResult.setResult(false);
                    msgResult.setMessage(pathBuilder.toString() + "未授权当前用户访问!");

                    obj = msgResult;
                }
            }
            else{
                logger.warn(pathBuilder.toString() + "未加入权限控制");

                // 执行切入方法
                obj = point.proceed();
            }
        }

        long elapse = System.currentTimeMillis() - start;

        System.out.println(classType);
        logger.warn(String.format("调用类%s方法%s耗时%s毫秒",clazzSimpleName,methodName,elapse));

        if(elapse>3000) {
            //执行时间超过3秒则记录数据库
            sysLog.setElapse(elapse);
            sysLog.setPointcut(clazzSimpleName + "->" + methodName);
            sysLog.setRemark("方法耗时统计");
            sysLog.setCreateTime(new Date());

            sysLogService.insert(sysLog);
        }

        return obj;
    }
}
