package cn.freemud.aop;

import cn.freemud.annotations.LogIgnore;
import cn.freemud.annotations.LogIgnoreFeign;
import cn.freemud.entities.vo.ThirdPartLogVo;
import cn.freemud.utils.AppLogUtil;
import com.freemud.application.sdk.api.base.SDKCommonBaseContextWare;
import com.freemud.application.sdk.api.log.LogThreadLocal;
import com.freemud.application.sdk.api.log.ThirdPartyLog;
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.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;

/**
 * @author freemud
 * @title: LogIgnoreFeignAop
 * @projectName order-group
 * @description: TODO
 * @date 2021/6/9上午10:53
 */

@Aspect
@Component
@Slf4j
public class LogIgnoreFeignAspect {
    /**
     * 是否打印响应报文日志，默认是false,若为true会覆盖注解里面的{@link LogIgnore}配置，输出响应报文里面所有的信息
     */
    @Value("${print-feign-response-body-log-order-application-service:true}")
    private volatile boolean printFeignResponseBodyLog = true;

    @Pointcut("execution(* cn.freemud.service.thirdparty..*.*(..))")
    public void clientLog() {
    }

    @Around("clientLog()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = null;
        try {
            result = joinPoint.proceed();
        } catch (Exception ex) {
            ThirdPartLogVo thirdPartLogVo = AppLogUtil.createThirdPartLogVo(joinPoint);
            AppLogUtil.thirdPartError(start, System.currentTimeMillis(), thirdPartLogVo, null);
            throw ex;
        }
        try {
            Signature sig = joinPoint.getSignature();
            MethodSignature msig = null;
            if (sig instanceof MethodSignature) {
                msig = (MethodSignature) sig;
                Method currentMethod = sig.getDeclaringType().getDeclaredMethod(msig.getName(), msig.getParameterTypes());
                Object logReult = result;
                ThirdPartLogVo thirdPartLogVo = AppLogUtil.createThirdPartLogVo(joinPoint);
                // 打印第三方出参日志
                if (!this.printFeignResponseBodyLog) {
                    LogIgnoreFeign logIgnore = currentMethod.getAnnotation(LogIgnoreFeign.class);
                    if (logIgnore != null && logIgnore.printLog()) {
                        String statusCodeValue = org.apache.commons.beanutils.BeanUtils.getProperty(result, logIgnore.statusCodeFieldName());
                        String messageValue = org.apache.commons.beanutils.BeanUtils.getProperty(result, logIgnore.messageFieldName());
                        String[] excludeStatusCodes = logIgnore.excludeStatusCodes();
                        //当排除了这个状态码不打印响应的具体内容只会打印状态码和状态描述信息
                        if (!StringUtils.isEmpty(statusCodeValue) && this.containStatusCode(excludeStatusCodes, statusCodeValue)) {
                            logReult = result.getClass().newInstance();
                            org.apache.commons.beanutils.BeanUtils.setProperty(logReult, logIgnore.statusCodeFieldName(), statusCodeValue);
                            org.apache.commons.beanutils.BeanUtils.setProperty(logReult, logIgnore.messageFieldName(), messageValue);
                        }
                    }
                }
                ThirdPartyLog.infoConvertJson(LogThreadLocal.getTrackingNo(), SDKCommonBaseContextWare.getAppName(), start, System.currentTimeMillis(),
                        thirdPartLogVo.getUri(), thirdPartLogVo.getRequestBody(), logReult);
            }
        } catch (Exception e) {
            AppLogUtil.errorLog("WebAspect Feign Log Ignore error {}", "","",e);
        }
        return result;
    }
//    @Around("clientLog()")
//    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
//        long start = System.currentTimeMillis();
//        Object result = null;
//        try {
//            result = joinPoint.proceed();
//        } catch (Exception ex) {
//            ThirdPartLogVo thirdPartLogVo = LogUtil.createThirdPartLogVo(joinPoint);
//            LogUtil.thirdPartError(start, System.currentTimeMillis(), thirdPartLogVo, null);
//            throw ex;
//        }
//        ThirdPartLogVo thirdPartLogVo = LogUtil.createThirdPartLogVo(joinPoint);
//        // 打印第三方出参日志
//        ThirdPartyLog.infoConvertJson(LogThreadLocal.getTrackingNo(), SDKCommonBaseContextWare.getAppName(),start,System.currentTimeMillis(),
//                thirdPartLogVo.getUri(),thirdPartLogVo.getRequestBody(),result);
//        return result;
//    }


    /**
     * 过滤返参code是否在excludeStatusCodes存在
     *
     * @param excludeStatusCodes
     * @param statusCodeValue
     * @return
     */
    private boolean containStatusCode(String[] excludeStatusCodes, String statusCodeValue) {
        if (excludeStatusCodes == null || excludeStatusCodes.length == 0) {
            return false;
        }
        for (int i = 0; i < excludeStatusCodes.length; i++) {
            if (excludeStatusCodes[i].equals(statusCodeValue)) {
                return true;
            }
        }
        return false;
    }

}
