package com.fdkankan.web.exception;

import cn.hutool.core.exceptions.ExceptionUtil;
import com.fdkankan.common.constant.ErrorCode;
import com.fdkankan.common.constant.ServerCode;
import com.fdkankan.common.exception.BusinessException;
import com.fdkankan.web.response.ResultData;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MultipartException;

/**
 * 全局异常处理器
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 处理未知异常
     */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public ResultData exceptionHandler(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Exception e) throws Exception {
            log.error("服务错误:", e);
            //增加sentinel异常次数
//            Tracer.trace(e);
            return ResultData.error(ServerCode.SYSTEM_ERROR.code(), ExceptionUtil.stacktraceToString(e, 3000));
    }

    /**
     * 限流熔断异常处理
     * 如果在这里捕获的话，就需要在接口中加入@SentinelResour注解
     */
//    @ResponseBody
//    @ExceptionHandler({FlowException.class, DegradeException.class})
//    public ResultData flowExceptionHandler(HttpServletRequest httpServletRequest, Exception e) {
//        String requestURI = httpServletRequest.getRequestURI();
//        String resource = null;
//        if(e instanceof FlowException){
//            resource = ((FlowException) e).getRule().getResource();
//        }
//        if(e instanceof DegradeException){
//            resource = ((DegradeException) e).getRule().getResource();
//        }
//
//        log.error("请求限流：requestURI{}，resource：{}", requestURI, resource);
//        return ResultData.error(ServerCode.SYSTEM_ERROR.code(), "系统繁忙，请稍后重试");
//    }

    /**
     * <p>
            form表达提交，缺少参数异常处理
     * </p>
     * @author dengsixing
     * @date 2022/4/14
     * @param e
     * @return com.fdkankan.common.response.ResultData
     **/
    @ResponseBody
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public ResultData missingServletRequestParameterException(
        MissingServletRequestParameterException e){
        return ResultData.error(
            ServerCode.PARAM_REQUIRED.code(),
            ServerCode.PARAM_REQUIRED.formatMessage(e.getParameterName()));
    }

    /**
     * <p>
     form表达提交，文件为空异常处理
     * </p>
     * @author dengsixing
     * @date 2022/4/14
     * @param e
     * @return com.fdkankan.common.response.ResultData
     **/
    @ResponseBody
    @ExceptionHandler(value = MultipartException.class)
    public ResultData multipartException(MultipartException e){
        return ResultData.error(
            ServerCode.PARAM_REQUIRED.code(),
            ServerCode.PARAM_REQUIRED.formatMessage("文件"));
    }

    @ResponseBody
    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    public ResultData httpMessageNotReadableException(HttpMessageNotReadableException e){
        return ResultData.error(ErrorCode.PARAM_ERROR.code(), ExceptionUtil.stacktraceToString(e, 3000));
    }


    /**
     * 参数校验异常拦截处理
     */
    @ResponseBody
    @ExceptionHandler({BindException.class,MethodArgumentNotValidException.class})
    public ResultData validationBodyException(Exception e) {
        BindingResult result = null;
        if(e instanceof MethodArgumentNotValidException){
            result = ((MethodArgumentNotValidException) e).getBindingResult();
        }
        if(e instanceof BindException){
            result = ((BindException) e).getBindingResult();
        }
        String message = "";
        if (result.hasErrors()) {
            List<ObjectError> errors = result.getAllErrors();
            if (errors != null) {
                errors.forEach(p -> {
                    FieldError fieldError = (FieldError) p;
                    log.error("参数校验错误：类:{},字段：{},错误信息：{}",fieldError.getObjectName(), fieldError.getField(), fieldError.getDefaultMessage());
                });
                if (errors.size() > 0) {
                    FieldError fieldError = (FieldError) errors.get(0);
                    message = fieldError.getDefaultMessage();
                }
            }
        }
        return ResultData.error(ErrorCode.PARAM_REQUIRED.code(), message);
    }

    /**
     * 处理业务异常
     */
    @ResponseBody
    @ExceptionHandler(value = BusinessException.class)
    public ResultData businessExceptionHandler(HttpServletRequest httpServletRequest, BusinessException e) {
        log.info("业务异常code:{},message:{}", e.getCode(), e.getMessage());
        return ResultData.error(e.getCode(), e.getMessage());
    }
}
