package cn.superdesk.uniorder.interceptor.monitor;

import cn.hutool.core.date.DateUtil;
import cn.superdesk.uniorder.common.json.AnJsonUtils;
import cn.superdesk.uniorder.dao.entity.sys.logger.SysMonitorFunctionLog;
import cn.superdesk.uniorder.service.sys.logger.SysMonitorFunctionLogService;
import lombok.extern.slf4j.Slf4j;
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.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Description: Java类作用描述
 * @Author: linjinyu
 * @CreateDate: 2021/7/5 下午12:09
 * @UpdateUser: linjinyu
 * @UpdateDate: 2021/7/5 下午12:09
 * @UpdateRemark: 修改内容
 * @Version: 1.0
 */
@Slf4j
@Aspect
public class MonitorLoggerAspect implements Ordered {

	@Autowired
	private SysMonitorFunctionLogService sysMonitorFunctionLogService;

	@Around("@within(cn.superdesk.uniorder.interceptor.monitor.annotation.MonitorLogger)")
//	@Around("@target(cn.superdesk.uniorder.interceptor.monitor.annotation.MonitorLogger)")
	public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {

		log.info("****AtWithinAspect.crossCuttingCode() : {} : Before Method Execution", joinPoint.getSignature().getName());

		// 操作时间
		Date startTime        = DateUtil.date();
		long startMilliSecond = startTime.getTime();

		// 1.获取切入点所在目标对象
		Object targetObj = joinPoint.getTarget();
//		System.out.println(targetObj.getClass().getName());
		// 2.获取切入点方法的名字
		String methodName = joinPoint.getSignature().getName();
//		System.out.println("切入方法名字:" + methodName);
		// 3.获取方法上的注解
		Signature       signature       = joinPoint.getSignature();
		MethodSignature methodSignature = (MethodSignature) signature;
		Method          method          = methodSignature.getMethod();
		Annotation[]    annotations     = null;
		// 4.获取方法的参数 请求参数 TODO 目录 系统 不统一 有的可能会报错 不用理
		Object[] args    = joinPoint.getArgs();
		Object   proceed = null;


		log.info("\n开始捕获用户操作日志 aroundMethod :" +
						"\n1.获取切入点所在目标对象-{} " +
						"\n2.获取切入点方法的名字  -{} " +
						"\n3.获取方法上的注解     -{} " +
						"\n4.获取方法的参数       -{}" +
						"\n 排除 ",
				targetObj.getClass().getName(), methodName, annotations, args
		);

		SysMonitorFunctionLog monitorEntity = new SysMonitorFunctionLog();


		try {

			monitorEntity.setStartTime(startTime);
			// 类名
			monitorEntity.setClazzName(targetObj.getClass().getName());
//			monitorEntity.setAnnotations(annotations);

			String param = AnJsonUtils.toJson(args);
			monitorEntity.setArgs(param);
			// 方法名
			monitorEntity.setMethodName(joinPoint.getSignature().getName());

			proceed = joinPoint.proceed();

			return proceed;

		} catch (Exception e) {

			// 堆栈错误信息
			String stackTrace = Arrays.toString(e.getStackTrace());
			// 错误信息
			String                            message  = e.getMessage();
			ConcurrentHashMap<String, String> errorMsg = new ConcurrentHashMap<>();
			errorMsg.put("stackTrace", stackTrace);
			errorMsg.put("message", e.getClass().getName() + ": " + message);

			throw e;

		} finally {

			try {
				if (null != proceed) {
					// 返回结果
//					monitorEntity.setResponseResult(JsonUtils.toJson(proceed));
				}

				// 请求结束时间
				Date endDate        = DateUtil.date();
				long endMilliSecond = endDate.getTime();

				monitorEntity.setEndTime(endDate);
				monitorEntity.setTimeConsuming(endMilliSecond-startMilliSecond);

			} catch (Exception e) {

				e.printStackTrace();

				log.error("获取返回结果异常{}", e);
			}

			// 异步将操作日志保存
			CompletableFuture.runAsync(() -> {
				try {
					// 保存日志,具体方法自定义
					sysMonitorFunctionLogService.addSysMonitorFunctionLog(monitorEntity);
				} catch (Exception e2) {

					e2.printStackTrace();

					log.error("用户操作日记记录异常:{}", e2);
				}
			});

			log.info("****AtWithinAspect.crossCuttingCode() : {} : After Method Execution \n", joinPoint.getSignature().getName());
		}


	}

	@Override
	public int getOrder() {
		return 0;
	}
}
