package cn.com.ty.lift.system.framework.aspect;

import cn.com.ty.lift.common.constants.ApiConstants;
import cn.com.ty.lift.common.utils.ValuePool;
import cn.com.ty.lift.common.verify.ValidateException;
import cn.com.xwy.boot.web.dto.RestResponse;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author wcz
 * @date 2019/12/10
 * @description 全局异常捕获处理
 */
@Slf4j
@RestControllerAdvice
public class GlobalDefaultExceptionHandler {

    private static final String classPrefix = "cn.com.ty.lift.system";

    //处理verify抛出的异常
    @ExceptionHandler(value = ValidateException.class)
    public Object verifyHandler(final ValidateException e) {
        // 捕获错误message
        String message = e.getMessage();
        return StrUtil.isEmpty(message) ? RestResponse.failParam() : RestResponse.fail(message);
    }

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Object jsonErrorHandler(final MethodArgumentNotValidException e) {
        // 获取验证框架的错误详情
        final FieldError error = e.getBindingResult().getFieldError();
        // 捕获错误message
        String message = error.getDefaultMessage();
        return StrUtil.isEmpty(message) ? RestResponse.failParam() : RestResponse.fail(message);
    }

    @ExceptionHandler(value = ExceptionInInitializerError.class)
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public Object badRequest() {
        return RestResponse.exception("Bad Request");
    }

    @ExceptionHandler(value = Exception.class)
    public Object defaultErrorHandler(final HttpServletRequest req, final HttpServletResponse resp, final Exception error) {
        // 原始错误集合数据偏多，包含native错误
        final StackTraceElement[] stackTrace = error.getStackTrace();
        // 过滤错误信息
        final List<StackTraceElement> elements = Stream.of(stackTrace)
                .filter(st -> (st.getClassName().contains(classPrefix) && st.getFileName().contains(ValuePool.DOT_JAVA)))
                .collect(Collectors.toCollection(LinkedList::new));

        final StackTraceElement[] dwStackTrace = new StackTraceElement[elements.size()];
        elements.toArray(dwStackTrace);

        // 填充StackTrace
        error.setStackTrace(dwStackTrace);
        log.error(ValuePool.LOG_GLOBAL_EXCEPTION_LINE);
        log.error("{}{} {}",ValuePool.LOG_URL, req.getMethod(), req.getRequestURI());
        log.error(ValuePool.LOG_STATUS + resp.getStatus());
        log.error(ValuePool.LOG_EXCEPTION, error);

        if (error instanceof Exception) {
            return RestResponse.fail(ApiConstants.RESULT_EXCEPTION, "操作异常，请重试");
        }
        return RestResponse.exception();
    }
}
