package com.jiayue.ipfcst.dataexchange.controllerutil;


import com.alibaba.fastjson.JSON;
import com.jiayue.ipfcst.common.core.exception.BusinessException;
import com.jiayue.ipfcst.common.core.web.vo.ResponseVO;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Arrays;


/**
 * 该类为aop切面类，主要是对所有返回值为ResponseVO的方法进行入参监控，以及异常处理
 *
 * @author 修唯
 */
@Aspect
@Component
@Slf4j
public class ControllerAOP {


  /**
   * 指定切点位置
   */
  @Pointcut("execution(public com.jiayue.ipfcst.common.core.web.vo.ResponseVO com.jiayue.ipfcst.dataexchange.controller.*.* (..))")
  public void webLog() {
  }

  @Around("webLog()")
  /**
   * 环绕
   * 对返回值为ResponseVO的方法进行切面，获取其入参
   * @param pjp  切入点方法
   * @return 统一返回格式对象
   */
  public Object handlerControllerMethod(ProceedingJoinPoint pjp) {
    long startTime = System.currentTimeMillis();
    ResponseVO<?> result;
    try {
      result = (ResponseVO<?>) pjp.proceed();
      log.info(pjp.getSignature() + "use time:" + (System.currentTimeMillis() - startTime));
      // 接收到请求，记录请求内容
      ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
        .getRequestAttributes();
      HttpServletRequest request = attributes.getRequest();
      // 记录下请求内容
      log.info("URL : " + request.getRequestURL().toString());
      log.info("HTTP_METHOD : " + request.getMethod());
      log.info("IP : " + request.getRemoteAddr());
      log.info("CLASS_METHOD : " + pjp.getSignature().getDeclaringTypeName() + "." + pjp.getSignature().getName());
      log.info("ARGS : " + Arrays.toString(pjp.getArgs()));
    } catch (Throwable e) {
      result = handlerException(pjp, e);
    }
    return result;

  }

  @AfterReturning(returning = "ret", pointcut = "webLog()")
  /**
   * 对切面方法进行返回值处理 后置
   * @param ret  处理结果
   */
  public void doAfterReturning(Object ret) {
    // 处理完请求，返回内容
   // log.info("RESPONSE : " + JSON.toJSONString(ret));
  }

  /**
   * 对切面方法进行异常捕获处理
   *
   * @param pjp 切点处理方法
   * @param e   切入方法运行中发生的一层
   * @return 统一格式的返回值
   */
  private ResponseVO<?> handlerException(ProceedingJoinPoint pjp, Throwable e) {

    ResponseVO<?> result = new ResponseVO();
    // 已知异常
    if (e instanceof BusinessException) {
      result.setMessage(e.getMessage());
      result.setCode(1);
    } else if (e instanceof IOException) {
      result.setMessage(e.getLocalizedMessage() + "找不到文件夹");
      result.setCode(1);
    } else {
      log.error(pjp.getSignature() + " 后台接口 exception ", e);
      result.setMessage(pjp.getSignature() + e.toString());
      result.setCode(1);
      // 未知异常是应该重点关注的，这里可以做其他操作，如通知邮件，单独写到某个文件等等。
    }
    return result;

  }

}
