package com.xhkjedu.sclass.aop;

import com.alibaba.fastjson.JSON;
import com.xhkjedu.annotation.Action;
import com.xhkjedu.constant.PlatformConstant;
import com.xhkjedu.model.slog.THandleLog;
import com.xhkjedu.sclass.config.ConfigKey;
import com.xhkjedu.sclass.mapper.system.UserMapper;
import com.xhkjedu.sclass.mq.HandleLogSender;
import com.xhkjedu.utils.IpRegionUtil;
import com.xhkjedu.utils.N_Utils;
import com.xhkjedu.vo.ResultVo;
import com.xhkjedu.vo.system.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/*
 * @Description: AOP 操作日志
 * @Author: WN
 * @Date: 2023/11/15 18:52:24
 **/
@Aspect
@Component
@Slf4j
public class WebControllerAop {
    @Resource
    private HandleLogSender handleLogSender;
    @Resource
    private UserMapper userMapper;

    private THandleLog handleLog;

    /*
     * @Description 指定切点 匹配 使用@Action修饰所有方法
     * @Date 2023/11/15 18:52:48
     * @Author WN
     * @Return void
     **/
    @Pointcut("execution(public * com.xhkjedu.sclass.controller..*.*(..))")
    public void handleLog() {
    }

    /*
     * @Description 前置通知，方法调用前被调用
     * @Date 2023/11/15 17:46:51
     * @Param [joinPoint]
     **/
    @Before("handleLog()")
    public void doBefore(JoinPoint joinPoint){

        //获取方法
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        // 获取AspectAnnotation注解
        Action action = method.getAnnotation(Action.class);
        if (action == null) {
            handleLog = null;
            return;
        }
        // 在此处初始化，避免某些方法不用记录报错
        handleLog = new THandleLog();

        try {
            // 获取方法名字
            String value = action.value();
            String[] valueStr = value.split("-");
            // 操作名称
            handleLog.setHandlemodel(valueStr[0]);
            handleLog.setHandleaction(valueStr[1]);

            if(joinPoint.getArgs() != null && joinPoint.getArgs().length > 0){
                Object[] args = joinPoint.getArgs();
                // 设置请求参数
                handleLog.setHandleparas(JSON.toJSONString(args[0]));
            }

            ServletRequestAttributes ss = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (ss != null) {
                HttpServletRequest request = ss.getRequest();
                Integer userid = request.getIntHeader(PlatformConstant.XH_USER_ID);
                // 用户名
                handleLog.setUserid(request.getIntHeader(PlatformConstant.XH_USER_ID));
                handleLog.setDevicetype(request.getHeader(PlatformConstant.XH_DEVICE));
                handleLog.setVersionnum(request.getHeader(PlatformConstant.XH_VERSION));
                // 请求地址
                handleLog.setHandleurl("/sclass" + request.getRequestURI());

                //获取请求ip并解析区域
                String ip = N_Utils.getIpAddress(request);
                String region = null;
                if (N_Utils.isNotEmpty(ip)) {
                    IpRegionUtil ipRegionUtil = new IpRegionUtil();
                    region = ipRegionUtil.getIpForAddress(ip, ConfigKey.ipregiondb);
                }
                handleLog.setHandleip(ip);
                handleLog.setHandleaddress(region);
                if(N_Utils.isTrueInteger(userid)){
                    UserVo user = userMapper.getUserInfoForHandleLog(userid);
                    if(user != null){
                        handleLog.setUsertype(user.getUsertype());
                        handleLog.setSchoolid(user.getSchoolid());
                        handleLog.setUsername(user.getUsername());
                        handleLog.setLoginname(user.getLoginname());
                        if(N_Utils.isNotEmpty(handleLog.getDevicetype()) && "p_web".equals(handleLog.getDevicetype())){
                            if(user.getUsertype() == 2){
                                handleLog.setDevicetype(handleLog.getDevicetype()+"_s");
                            }else{
                                handleLog.setDevicetype(handleLog.getDevicetype()+"_t");
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("操作日志doBefore执行异常：" + e.getMessage());
        }
    }

    /*
     * @Description 处理完请求返回内容 发送mq消息
     * @Date 2023/11/15 17:47:12
     * @Author WN
     * @Param [ret]
     **/
    @AfterReturning(returning = "ret", pointcut = "handleLog()")
    public void doAfterReturning(Object ret){
        if (ret == null) {
            return;
        }
        if (handleLog == null) {
            return;
        }

        if (ret instanceof ResultVo) {
            ResultVo result = (ResultVo) ret;
            if (result.getCode() == 0) {
                handleLog.setHandlestate(1);
            } else {
                handleLog.setHandlestate(2);
            }
        }
    }

    /*
     * @Description  后置异常
     * @Date 2023/11/15 17:47:28
     * @Author WN
     * @Param [jp, e] (JoinPoint jp, Exception e)
     **/
    @AfterThrowing(pointcut = "handleLog()", throwing = "e")
    public void throwss(Exception e) {

        if (handleLog == null) {
            return;
        }

        handleLog.setHandlestate(2);
    }

    /*
     * @Description 后置最终通知,final增强，不管是抛出异常或者正常退出都会执行
     * @Date 2023/11/15 17:49:15
     * @Author WN
     * @Param [jp](JoinPoint jp)
     **/
    @After("handleLog()")
    public void after() {
        if (handleLog == null) {
            return;
        }
        sendOut();
    }

    /*
     * @Description 环绕通知,环绕增强，相当于MethodInterceptor
     * @Date 2023/11/15 17:49:34
     * @Author WN
     * @Param [pjp]
     * @Return java.lang.Object
     **/
    // @Around("handleLog()")
    // public Object arround(ProceedingJoinPoint pjp) {
    //     try {
    //         return pjp.proceed();
    //     } catch (Throwable e) {
    //         e.printStackTrace();
    //     }
    //     return null;
    // }

    /**
     * 发送消息
     */
    public void sendOut() {
        THandleLog logHandlelogNew = handleLog;
        // log.info("记录操作日志,给rabbitmq发送消息：" + logHandlelogNew.toString());
        handleLogSender.handleLogSend(logHandlelogNew);
    }

}
