package com.yanzuoguang.cloud.aop;

import com.yanzuoguang.cloud.service.TokenServiceCall;
import com.yanzuoguang.token.TokenHelper;
import com.yanzuoguang.util.exception.ExceptionHelper;
import com.yanzuoguang.util.log.Log;
import com.yanzuoguang.util.vo.ResponseResult;
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.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.lang.reflect.Type;

/**
 * LogsAspect(接口请求日志切面)
 *
 * @author: Kang
 * @time: 2018年04月25日 11:43
 */
@Aspect
@Component
public class WebAspect extends BaseRequestAspect {

    private static final String TAG = WebAspect.class.getSimpleName();

    @Autowired
    private TokenServiceCall tokenServiceCall;

    @Value("${yzg.logWeb:false}")
    private boolean logWeb;

    @Value("${yzg.gateway:^.*gateway.*$}")
    private String gateWay;

    @Autowired
    private ApplicationContext context;

    /**
     * 是否存在初始化方法
     */
    private WebAssecptInit webAssecptInit;

    /**
     * exec aop point aspect
     */
    @Pointcut("execution(* *..web..*Controller.*(..))")
    public void webAspect() {
    }


    /**
     * 执行环形切面
     *
     * @param joinPoint
     * @return
     */
    @Around(value = "webAspect()")
    public Object requestWebAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = null;
        boolean isGateWay = isGateWay();
        if (isGateWay) {
            result = executeMethod(joinPoint);
            return result;
        }
        boolean clear = requestLogInit();
        // 用户数据库记录
        long start = requestLog(TAG, joinPoint);
        Exception ex = null;
        boolean isInit = false;
        try {
            isInit = tokenServiceCall.tokenInit();
            if (webAssecptInit == null) {
                try {
                    webAssecptInit = context.getBean(WebAssecptInit.class);
                } catch (Exception e) {
                    webAssecptInit = new WebAssecptInit() {
                        @Override
                        public void init(Object req) {
                        }
                    };
                    Log.error(WebAspect.class, "请设置登录默认处理函数");
                    Log.error(WebAspect.class, e);
                }
            }
            if (webAssecptInit != null) {
                for (Object arg : joinPoint.getArgs()) {
                    webAssecptInit.init(arg);
                }
            }
            result = executeMethod(joinPoint);
            return result;
        } catch (Exception e) {
            ex = e;
            result = ExceptionHelper.getError(e);
            if (getReturnType(joinPoint).getTypeName().indexOf(ResponseResult.class.getName()) > -1) {
                return result;
            } else {
                throw e;
            }
        } finally {
            tokenServiceCall.tokenFinish();
            if (isInit) {
                TokenHelper.remove();
            }
            responseLog(logWeb, clear, TAG, HttpAspectUtil.getHttpRequestUrl(), joinPoint, start, result, ex);
        }
    }

    /**
     * 是否属于网关服务,网关服务不进行监控
     *
     * @return
     */
    private boolean isGateWay() {
        return this.applicationName.matches(this.gateWay);
    }


    /**
     * 获取返回的至类型
     *
     * @param joinPoint
     * @return
     * @throws NoSuchMethodException
     */
    private Type getReturnType(ProceedingJoinPoint joinPoint) {
        Method m = getMethod(joinPoint);
        Type t = m.getAnnotatedReturnType().getType();
        return t;
    }

    /**
     * 获取返回的至类型
     *
     * @param joinPoint
     * @return
     * @throws NoSuchMethodException
     */
    private Method getMethod(ProceedingJoinPoint joinPoint) {
        //获取返回值类型
        Signature s = joinPoint.getSignature();
        MethodSignature ms = (MethodSignature) s;
        Method m = ms.getMethod();
        return m;
    }

    /**
     * 执行方法
     *
     * @param joinPoint 需要执行的方法
     * @return 返回结果
     * @throws Throwable
     */
    private Object executeMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        return joinPoint.proceed();
    }
}