package com.ym.im.config;

import com.ym.im.entity.MsgBody;
import com.ym.im.exception.IMessageException;
import com.ym.im.util.MessageUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 全局异常处理
 *
 * @author 陈俊雄
 * @date 2019/5/31
 **/
@Slf4j
@Configuration
public class ExceptionConfig {

    /**
     * REST异常处理类
     */
    @RestControllerAdvice
    public class RestResponseEntityExceptionHandler {

        /**
         * 系统级异常处理
         *
         * @param e e
         * @return ResponseEntity
         */
        @ExceptionHandler(value = Exception.class)
        protected ResponseEntity<MsgBody> exceptionHandle(Exception e, HttpServletRequest request) {
            // 错误信息编号：Error number，用于日志定位
            final String errornum = UUID.randomUUID().toString();
            log.error("Error number: " + errornum, e);
            final MsgBody msgBody = new MsgBody<>()
                    .setCode(HttpStatus.INTERNAL_SERVER_ERROR.value())
                    .setMessage(MessageUtils.getMsg("error.system", request.getLocale(), errornum));
            return new ResponseEntity<>(msgBody, HttpStatus.INTERNAL_SERVER_ERROR);
        }

        /**
         * Request参数异常处理
         *
         * @return ResponseEntity
         */
        @ExceptionHandler(value = HttpMessageNotReadableException.class)
        protected ResponseEntity<MsgBody> httpMessageNotReadableExceptionHandle(HttpServletRequest request) {
            final MsgBody msgBody = new MsgBody<>()
                    .setCode(HttpStatus.BAD_REQUEST.value())
                    .setMessage(MessageUtils.getMsg("error.missing_body", request.getLocale()));
            return new ResponseEntity<>(msgBody, HttpStatus.BAD_REQUEST);
        }

        /**
         * 聊天服务自定义异常处理
         *
         * @param e e
         * @return ResponseEntity
         */
        @ExceptionHandler(value = IMessageException.class)
        protected ResponseEntity<MsgBody> iMessageExceptionHandle(IMessageException e) {
            final MsgBody msgBody = new MsgBody<>().setCode(HttpStatus.INTERNAL_SERVER_ERROR.value()).setMessage("error.top_level_error");
            return new ResponseEntity<>(msgBody, HttpStatus.INTERNAL_SERVER_ERROR);
        }

        /**
         * JsonBean参数校验异常处理
         * {@link javax.validation}
         *
         * @param e e
         * @return ResponseEntity
         */
        @ExceptionHandler(value = {MethodArgumentNotValidException.class, BindException.class})
        protected ResponseEntity<MsgBody<List<String>>> methodArgumentNotValidExceptionHandle(Exception e, HttpServletRequest request) {
            final ArrayList<String> errorMsg = new ArrayList<>();
            if (e instanceof MethodArgumentNotValidException) {
                final List<ObjectError> allErrors = ((MethodArgumentNotValidException)e).getBindingResult().getAllErrors();
                for (ObjectError oe : allErrors) {
                    errorMsg.add(oe.getDefaultMessage() + "[" + ((FieldError) oe).getField() + " = " + ((FieldError) oe).getRejectedValue() + "]");
                }
            }
            if (e instanceof BindException){
                final List<FieldError> allErrors = ((BindException)e).getFieldErrors();
                for (FieldError fe : allErrors) {
                    errorMsg.add(fe.getDefaultMessage() + "[" + fe.getField() + " = " + fe.getRejectedValue() + "]");
                }
            }
            final MsgBody<List<String>> msgBody = new MsgBody<>();
            msgBody.setCode(HttpStatus.BAD_REQUEST.value());
            msgBody.setMessage(MessageUtils.getMsg("error.bad_parameter", request.getLocale()) + errorMsg.toString());
            return new ResponseEntity<>(msgBody, HttpStatus.BAD_REQUEST);
        }
    }
}
