package com.zcxk.core.common.exception;

import com.alibaba.fastjson.JSON;
import com.zcxk.core.common.enums.RespCodeEnum;
import com.zcxk.core.common.pojo.AjaxMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
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.method.annotation.MethodArgumentConversionNotSupportedException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.UnexpectedTypeException;
import java.util.List;
import java.util.Map;
/**
 * @author Andy
 * @description: 全局异常捕获提示
 * @date 2021/7/16
 * @version V1.0
 **/
@Slf4j
@RestControllerAdvice
public class SystemExceptionHandler implements InitializingBean {

    @ResponseBody
    @ExceptionHandler(BusinessException.class)
    public AjaxMessage<Void> handleBusinessException(HttpServletRequest req, BusinessException exception) {
        String message = !StringUtils.isEmpty(exception.getMsg()) ? exception.getMsg()
                : exception.getMessage();
        log.info("【全局异常捕获提示】：uri: {} param:[{}] msg：{}", getReqUrl(req), getRequestParam(req),
            message);
        return AjaxMessage.fail(exception.getCode(), message);
    }

    @ResponseBody
    @ExceptionHandler(BindException.class)
    public AjaxMessage<Void> handleBindException(HttpServletRequest req, BindException bindException) {
        String errorMsg = getBindingResult(bindException.getBindingResult());
        log.info("【全局异常捕获提示】：uri: {} param:[{}] msg：{}", getReqUrl(req), getRequestParam(req),
            errorMsg);
        return AjaxMessage.fail(RespCodeEnum.ERROR_500.getStatus(), errorMsg);
    }

    @ResponseBody
    @ExceptionHandler(UnexpectedTypeException.class)
    public AjaxMessage<Void> handleUnexpectedTypeException(
            HttpServletRequest req, UnexpectedTypeException exception) {
        String message = exception.getMessage();
        log.info("【全局异常捕获提示】：uri: {} param:[{}] msg：{}", getReqUrl(req), getRequestParam(req),
            message);
        return AjaxMessage
            .fail(RespCodeEnum.ERROR_500.getStatus(), message);
    }

    @ResponseBody
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public AjaxMessage<Void> handleMethodArgumentNotValidException(HttpServletRequest req,
        MethodArgumentNotValidException exception) {
        String errorMsg = getBindingResult(exception.getBindingResult());
        log.info("【全局异常捕获提示】：uri: {} param:[{}] msg：{}", getReqUrl(req), getRequestParam(req),
            errorMsg);
        return AjaxMessage.fail(RespCodeEnum.ERROR_500.getStatus(), errorMsg);
    }

    @ResponseBody
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public AjaxMessage<Void> handleHttpRequestMethodNotSupportedException(HttpServletRequest req,
        HttpRequestMethodNotSupportedException exception) {
        log.error("全局HttpRequestMethodNotSupportedException异常处理。非法请求 uri: {} param: [{}] msg: {}",
            getReqUrl(req), getRequestParam(req), exception.getMessage());
        return AjaxMessage.fail(RespCodeEnum.ERROR_500);
    }


    @ResponseBody
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public AjaxMessage<Void> handleHttpMessageNotReadableException(HttpServletRequest req,
        HttpMessageNotReadableException exception) {
        log.error("全局HttpMessageNotReadableException异常处理。非法请求 uri: {} param: [{}] msg: {}",
            getReqUrl(req), getRequestParam(req), exception.getMessage());
        return AjaxMessage.fail(RespCodeEnum.ERROR_500);
    }

    @ResponseBody
    @ExceptionHandler(MethodArgumentConversionNotSupportedException.class)
    public AjaxMessage<Void> handleMethodArgumentConversionNotSupportedException(
        HttpServletRequest req, MethodArgumentConversionNotSupportedException exception) {
        log.error("全局HttpMessageNotReadableException异常处理。非法请求 uri: {} param: [{}] msg: {}",
            getReqUrl(req), getRequestParam(req), exception.getMessage());
        return AjaxMessage.fail(RespCodeEnum.ERROR_500);
    }

    @ResponseBody
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public AjaxMessage<Void> handleMissingServletRequestParameterException(HttpServletRequest req,
        MissingServletRequestParameterException exception) {
        log.error("全局HttpMessageNotReadableException异常处理。非法请求 uri: {} param: [{}] msg: {}",
            getReqUrl(req), getRequestParam(req), exception.getMessage());
        return AjaxMessage.fail(RespCodeEnum.ERROR_500);
    }

    @ResponseBody
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public AjaxMessage<Void> handleHttpMediaTypeNotSupportedException(HttpServletRequest req,
        MissingServletRequestParameterException exception) {
        log.error("全局HttpMediaTypeNotSupportedException异常处理。非法请求 uri: {} param: [{}] msg: {}",
            getReqUrl(req), getRequestParam(req), exception.getMessage());
        return AjaxMessage.fail(RespCodeEnum.ERROR_500);
    }

    @ResponseBody
    @ExceptionHandler(Exception.class)
    public AjaxMessage<Void> handleException(HttpServletRequest req, Exception exception) {
        log.error("全局Exception异常处理。uri: {} param: [{}]", getReqUrl(req), getRequestParam(req),
            exception);
        return AjaxMessage.fail(RespCodeEnum.ERROR_500);
    }

    /**
     * 获取请求URL
     *
     * @param req
     * @return
     */
    private String getReqUrl(HttpServletRequest req) {
        String url = "uri";
        if (req != null && req.getRequestURL() != null) {
            url = req.getRequestURL().toString();
        }
        return url;
    }

    /**
     * 统一绑定错误信息处理
     *
     * @return java.lang.String
     * @author Richard
     **/
    private String getBindingResult(BindingResult bindingResult) {
        List<ObjectError> errors = bindingResult.getAllErrors();
        StringBuilder errorMsg = new StringBuilder();
        for (ObjectError error : errors) {
            errorMsg.append(error.getDefaultMessage()).append(";");
        }
        return errorMsg.toString();
    }

    private String getRequestParam(HttpServletRequest request) {
        final Map<String, String[]> parameterMap = request.getParameterMap();
        return JSON.toJSONString(parameterMap);
    }

    @Override
    public void afterPropertiesSet() {
    }
}
