/**
 * Copyright 2018-2020 stylefeng & fengshuonan (sn93@qq.com)
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package com.sunxung.factoring.component.exception;


import com.sunxung.factoring.component.util.CodeUtil;
import com.sunxung.factoring.entity.ResponseJson;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
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.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;


/**
 * 全局异常处理器
 *
 * @author 张超
 * @date 2021-10-27
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

  /**
   * 参数校验错误
   *
   * @author zc
   * @Date 2021-03-18
   */
  @ExceptionHandler(MissingServletRequestParameterException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public ResponseJson handleError(MissingServletRequestParameterException e) {
    String message = String.format("Missing Request Parameter: %s", e.getParameterName());
    return new ResponseJson(CodeUtil.PARAMETER_ERROR, message);
  }

  /**
   * 参数校验错误
   *
   * @author zc
   * @date 2021-10-27
   */
  @ExceptionHandler(MethodArgumentTypeMismatchException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public ResponseJson handleError(MethodArgumentTypeMismatchException e) {
    String message = String.format("Method Argument Type Mismatch: %s", e.getName());
    return new ResponseJson(CodeUtil.PARAMETER_ERROR, message);
  }

  /**
   * 参数校验错误
   *
   * @author zc
   * @date 2021-10-27
   */
  @ExceptionHandler(MethodArgumentNotValidException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public ResponseJson handleError(MethodArgumentNotValidException e) {
    BindingResult result = e.getBindingResult();
    FieldError error = result.getFieldError();
    String message = String.format("%s:%s", error.getField(), error.getDefaultMessage());
    return new ResponseJson(CodeUtil.PARAMETER_ERROR, message);
  }

  /**
   * 参数校验错误异常
   *
   * @author zc
   * @date 2021-10-27
   */
  @ExceptionHandler(BindException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public ResponseJson handleError(BindException e) {

    FieldError error = e.getFieldError();
    String message = String.format("%s:%s", error.getField(), error.getDefaultMessage());
    return new ResponseJson(CodeUtil.PARAMETER_ERROR, message);
  }

  /**
   * 参数校验错误异常
   *
   * @author zc
   * @date 2021-10-27
   */
  @ExceptionHandler(ConstraintViolationException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public ResponseJson handleError(ConstraintViolationException e) {
    Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
    ConstraintViolation<?> violation = violations.iterator().next();
    String path = violation.getLeafBean().toString();
    String message = String.format("%s:%s", path, violation.getMessage());
    return  new ResponseJson(CodeUtil.PARAMETER_ERROR, message);
  }

  /**
   * 消息不可读 异常
   *
   * @author zc
   * @date 2021-10-27
   */
  @ExceptionHandler(HttpMessageNotReadableException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public ResponseJson handleError(HttpMessageNotReadableException e) {
    //log.warn("HttpMessageNotReadableException ", e);
    String message = String.format("HttpMessageNotReadableException:%s", e.getMessage());
    return new ResponseJson(CodeUtil.PARAMETER_ERROR, message);
  }

  /**
   * 拦截业务异常，返回状态码500
   */
  @ExceptionHandler(ServiceException.class)
  public ResponseJson serviceError(ServiceException e, HttpServletResponse response) {
    if (e.getCode() == null) {
      response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
      e.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
    } else {
      response.setStatus(e.getCode());
    }
    return new ResponseJson(e.getCode().toString(), e.getErrorMessage());
  }

  /**
   * 拦截业务代码校验异常类
   */
  @ExceptionHandler(ValidatorException.class)
  public ResponseJson validatorError(ValidatorException e, HttpServletResponse response) {
    response.setStatus(400);
    ResponseJson responseJson = e.getResponseJson();
    responseJson.setCode("400");
    return responseJson;
  }


//  /**
//   * 拦截远程调用异常
//   */
//  @ExceptionHandler(RemoteException.class)
//  public ResponseJson remoteError(ServiceException e, HttpServletResponse response) {
//    log.error("远程调用异常:", e);
//    if (e.getCode() == null) {
//      response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
//      e.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
//    } else {
//      response.setStatus(e.getCode());
//    }
//    return ResponseData.error(e.getCode(), e.getServiceCode(), e.getErrorMessage());
//  }

  /**
   * 拦截未知的运行时异常，返回状态码503
   */
  @ExceptionHandler(Throwable.class)
  @ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE)
  public ResponseJson serverError(Throwable e) {
    String message = "服务器暂不可用，请联系客服在线咨询";
    String javaMessage = e.getMessage();
    if (e.getStackTrace().length > 0) {
      for (StackTraceElement stackTraceElement : e.getStackTrace()) {
        javaMessage += stackTraceElement.toString();
      }
    }
    return new ResponseJson("503",javaMessage);
  }
}
