package com.blueland.aop;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.blueland.annotation.Log;
import com.blueland.constant.CommonConstant;
import com.blueland.core.util.AccessUtil;
import com.blueland.core.util.StringUtil;
import com.blueland.core.util.UserUtils;
import com.blueland.bo.SysOplogEntity;
import com.blueland.bo.SysPvlogEntity;
import com.blueland.model.TPfSysOplog;
import com.blueland.model.TPfSysPvlog;
import com.blueland.service.impl.SysOplogServiceImpl;
import com.blueland.service.impl.SysPvlogServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

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

/**
 * @description: 日志记录
 * @author: bigTian
 * @create: 2021-10-28 14:48
 */
@Aspect
@Component
@Slf4j
public class LogAspect {
    private final String expCheckPoint = "@annotation(com.blueland.annotation.Log)";
    private final static String prefix = "执行方法：";

    @Autowired
    private SysOplogServiceImpl sysOplogService;

    @Autowired
    private SysPvlogServiceImpl sysPvlogService;

    /**
     * 配置切点
     */
    @Pointcut(expCheckPoint)
    public void expCheckPoint() {
    }


    /**
     * 抛出异常后
     *
     * @param point
     * @param ex
     */
    @AfterThrowing(pointcut = "expCheckPoint()", throwing = "ex")
    public void doAfterThrowing(JoinPoint point, Exception ex) throws Exception {
        log(point, false);
    }

    private void log(JoinPoint point, boolean isSuccess) throws Exception {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method currentMhd = signature.getMethod();
        String currentMethodName = point.getTarget().getClass().getSimpleName() + "." + currentMhd.getName();
        Log logs = currentMhd.getAnnotation(Log.class);
        String code = logs.logType().getCode();
        //操作日志
        if (CommonConstant.LogType.OPERATE.getCode().equals(code)) {
            operate(point, isSuccess, logs, currentMethodName);
        } else if (CommonConstant.LogType.PAGEVIEW.getCode().equals(code)) {
            //    浏览日志
            pageView(point, logs, currentMethodName);
        }
    }

    private void pageView(JoinPoint point, Log logs, String currentMtdName) throws Exception {
        HttpServletRequest request = UserUtils.getRequest();
        String aceessIp = AccessUtil.getAccessIp(request);
        String aceessUrl =  AccessUtil.getAccessUrl(request);
        String aceessSource = AccessUtil.getAccessSource(request);
        String aceessDevice = AccessUtil.getAccessDevice(request);
        String aceessBrowse =  AccessUtil.getAccessBrowse(request);
        //获取请求头的 iv_user
        String ivUser = UserUtils.getIvUser();
        TPfSysPvlog pvlog = new TPfSysPvlog();
        pvlog.setUserId(StringUtil.notEmpty(ivUser) ? ivUser : "unknown");
        pvlog.setUserName(StringUtil.notEmpty(ivUser) ? ivUser : "unknown");
        pvlog.setBizId(getBusiId(point, logs));
        pvlog.setBizType(currentMtdName);
        pvlog.setAceessTitle(logs.busiType());
        pvlog.setAceessIp(aceessIp);
        pvlog.setAceessUrl(aceessUrl);
        pvlog.setAceessTime(new Date());
        pvlog.setAceessSource(aceessSource);
        pvlog.setAceessDevice(aceessDevice);
        pvlog.setAceessBrowse(aceessBrowse);
        pvlog.setAppId(ObjectUtil.isNotEmpty(UserUtils.getTenantId())?UserUtils.getTenantId():"sys");
        pvlog.setRemark(prefix + point.getSignature().getName());
        try {
            sysPvlogService.save(pvlog);
        }catch (Exception e) {
            System.out.println(e);
        }
    }


    /**
     * 操作日志
     *
     * @param point
     * @param isSuccess
     * @param logs
     */
    private void operate(JoinPoint point, boolean isSuccess, Log logs, String currentMethodName) throws Exception {
        String ivUser = UserUtils.getIvUser();
        String type = logs.type();
        HttpServletRequest request = UserUtils.getRequest();
        String aceessIp = AccessUtil.getAccessIp(request);
        String aceessBrowse =  AccessUtil.getAccessBrowse(request);
        TPfSysOplog oplog = new TPfSysOplog();
        oplog.setAceessIp(aceessIp);
        oplog.setAceessBrowse(aceessBrowse);
        oplog.setCreateTime(new Date());
        oplog.setBizId(getBusiId(point, logs));
        oplog.setBizType(currentMethodName);
        String str = JSONUtil.toJsonStr(point.getArgs());
        if (str.length() > 4000) {
            str = StrUtil.sub(str, 0, 3900);
        }
        oplog.setContent(str);
        oplog.setStatus(isSuccess ? CommonConstant.RESULT_SUCCESS : CommonConstant.RESULT_FAILED);
        oplog.setType(type);
        oplog.setUserId(StringUtil.notEmpty(ivUser) ? ivUser : "unknown");
        oplog.setUserName(StringUtil.notEmpty(ivUser) ? ivUser : "unknown");
        oplog.setRemark(prefix + point.getSignature().getName());
        oplog.setAppId(ObjectUtil.isNotEmpty(UserUtils.getTenantId())?UserUtils.getTenantId():"sys");
        try {
            sysOplogService.save(oplog);
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    private static String getSysId(Object[] objects) {
        // 从请求参数中获取租户id
        if (ObjectUtil.isNotEmpty(objects) && objects.length > 1) {
            JSONObject jsonObject = JSONUtil.parseObj(objects[1]);
            if (ObjectUtil.isNotEmpty(jsonObject) && ObjectUtil.isNotEmpty(jsonObject.get("appId"))) {
                return jsonObject.get("appId").toString();
            } else {
                return "sys";
            }
        }
        return "sys";
    }

    /**
     * 正常执行
     *
     * @param point
     */
    @AfterReturning("expCheckPoint()")
    public void successLog(JoinPoint point) throws Exception {
        log(point, true);
    }

    /**
     * 获取BusiId
     *
     * @param point
     * @param logs
     * @return
     * @throws Exception
     */
    public String getBusiId(JoinPoint point, Log logs) throws Exception {
        Object[] args = point.getArgs();
        String busiId = "";
        if(ObjectUtil.isNotEmpty(args)) {
            if (args.length > 1) {
                busiId = JSONUtil.toJsonStr(args[1]);
            } else {
                busiId =  JSONUtil.toJsonStr(args[0]);
            }
            if (busiId.length() > 400) {
                busiId = StrUtil.sub(busiId, 0, 399);
            }
        }
        return busiId;
    }

}
