package com.elab.spring.exception;

import com.elab.core.bean.Info;
import com.elab.core.exception.BusinessException;
import com.elab.core.exception.CoreException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.WebRequest;

import java.util.List;

/**
 * 全局异常定义
 *
 * @author Liukx
 * @create 2017-04-10 15:28
 * @email liukx@elab-plus.com
 **/
@ControllerAdvice
public class CommonException {

    private Logger logger = LoggerFactory.getLogger(CommonException.class);
    private String defaultSystemError = "CORE.ERROR.001";
    private String defaultParamsError = "CORE.PARAMS.001";
    private String defaultNotFoundError = "CORE.NOT_FOUND";
    private String defaultMessage = "系统异常";

    @Autowired
    private Environment environment;

    @ExceptionHandler(Exception.class)
    @ResponseBody
    @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
    public Object exception(Exception ex, WebRequest request) {
        logger.error(ex.getMessage(), ex);
        Info info = getInfo(environment.getProperty("mvc.common.exception.code", defaultSystemError), environment.getProperty("mvc.common.exception.message", defaultMessage));
        return info;
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public Object methodArgumentNotValidException(Exception ex) {
        logger.debug(ex.getMessage(), ex);
        StringBuffer sb = new StringBuffer();
        if (ex instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException e = (MethodArgumentNotValidException) ex;
            List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
            for (int i = 0; i < allErrors.size(); i++) {
                FieldError objectError = (FieldError) allErrors.get(i);
                sb.append(objectError.getField() + " 字段值 " + objectError.getRejectedValue() + " - " + objectError.getDefaultMessage());
            }
        }
        Info info = getInfo(defaultParamsError, sb.toString());
        return info;
    }

    @ExceptionHandler(CoreException.class)
    @ResponseBody
    public Object coreException(CoreException ex) {
        logger.debug(ex.getMessage(), ex);
        Info info = getInfo(ex.getErrorCode(), ex.getMessage());
        return info;
    }

    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public Object businessException(BusinessException bx) {
        logger.debug(bx.getMessage(), bx);
        Info info = getInfo(bx.getErrorCode(), bx.getMessage());
        return info;
    }

    private Info getInfo(String errorCode, String message) {
        return Info.NO(errorCode, message);
    }

    @ExceptionHandler(value = {HttpRequestMethodNotSupportedException.class, HttpMediaTypeNotSupportedException.class})
    @ResponseBody
    @ResponseStatus(value = HttpStatus.METHOD_NOT_ALLOWED)
    public Object notFondMethod(Exception ex) {
        logger.debug(" 全局notFondMethod异常捕获 .." + ex.getMessage());
        // 将匹配不到方法的异常状态定位404。
        Info info = getInfo(defaultNotFoundError, "not fond");
        return info;
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseBody
    @ResponseStatus(value = HttpStatus.NOT_FOUND)
    public Object notReadable(Exception ex) {
        logger.debug(" 全局notFondMethod异常捕获 .." + ex.getMessage());
        // 将参数有异常的数据拦截返回
        Info info = getInfo(defaultNotFoundError, "请检查请求数据..");
        return info;
    }


    @ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
    @ResponseBody
    @ResponseStatus(value = HttpStatus.NOT_ACCEPTABLE)
    public Object notAcceptable(Exception ex) {
        logger.debug(" 全局notFondMethod异常捕获 .." + ex.getMessage());
        // 将参数有异常的数据拦截返回
        Info info = getInfo(defaultNotFoundError, "请检查请求数据..");
        return info;
    }


}
