package cn.ysk.cashier.config;

import cn.ysk.cashier.utils.FastJsonUtils;
import cn.ysk.cashier.utils.SpringContextHolder;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * 方法调用统一切面处理
 */
@Aspect
@Component
@Slf4j
public class AppApiMethodAspect {
    @Pointcut("execution(public * (" +
            "cn.ysk.cashier.controller.* " +
            "|| cn.ysk.cashier.controller.*.* " +
            "|| cn.ysk.cashier.mnt.rest.* " +
            "|| cn.ysk.cashier.system.rest.* " +
            "|| cn.ysk.cashier.config.security.rest.*" +
            ").*(..))")
    public void pkg() {
    }

    @Around("pkg()")
//    @SuppressWarnings("unchecked")
    public Object around(ProceedingJoinPoint pjp) {
        HttpServletRequest req = SpringContextHolder.getRequest();
        Signature sign = pjp.getSignature();
        MethodSignature ms = (MethodSignature) sign;

        Map<String, Object> params = new HashMap<>();
        Object result = null;
        String requestJson="";
        try {
            // 获取方法参数
            Object[] args = pjp.getArgs();
            String[] paramNames = ms.getParameterNames();
            for (int i = 0; i < args.length; i++) {
                params.put(paramNames[i], FastJsonUtils.toJSONString(args[i]));
            }
            requestJson=FastJsonUtils.toJSONString(params);
            // 执行被拦截的方法
            result = pjp.proceed();
            String resultJson = FastJsonUtils.toJSONString(result);
            if (resultJson.length() > 300) {
                resultJson = resultJson.substring(0, 300);
            }
            log.info("\n>>>>>>{} {}\n>>>>>>{}\n>>>>>>Request: {}\n>>>>>>Response: {}"
                    , req.getMethod(), req.getRequestURL(), req.getRemoteAddr(),
                    requestJson,
                    resultJson
            );
            return result;
        } catch (RuntimeException e) {
            if (StringUtils.isBlank(e.getMessage())) {
                log.error("\n>>>>>>{} {} {}\n>>>>>>Request: {}\n>>>>>>Exception: {}"
                        , req.getMethod(), req.getRequestURL(), req.getRemoteAddr(),
                        requestJson,
                        e);
            } else {
                log.error("\n>>>>>>{} {} {}\n>>>>>>Request: {}\n>>>>>>Exception: {}"
                        , req.getMethod(), req.getRequestURL(), req.getRemoteAddr(),
                        requestJson,
                        e.getMessage());
            }
            throw e;
        } catch (Error e) {
            log.error("\n>>>>>>{} {} {}\n>>>>>>Request: {}\n>>>>>>Exception: {}"
                    , req.getMethod(), req.getRequestURL(), req.getRemoteAddr(),
                    requestJson,
                    e);
            throw e;
        } catch (Throwable e) {
            log.error("\n>>>>>>{} {} {}\n>>>>>>Request: {}\n>>>>>>Exception: {}"
                    , req.getMethod(), req.getRequestURL(), req.getRemoteAddr(),
                    requestJson,
                    e);
            throw new RuntimeException(e);
        }
    }
}
