package cn.qinys.platform.base.exceptions;



import cn.qinys.platform.base.response.Result;
import cn.qinys.platform.base.response.ResultCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
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.client.HttpClientErrorException;

import java.net.ConnectException;
import java.nio.file.AccessDeniedException;
import java.sql.SQLException;

/**
 * code is far away from bug with the animal protecting
 *
 * @author v-lishiquan.gx@chinatelecom.cn
 * @description 全局异常处理
 * @date Create in 2019-1-21
 */
@RestControllerAdvice
@Slf4j
public class GlobalDefaultExceptionHandler {

    /**
     * 全局异常 300
     *
     * @param ex 异常
     * @return 返回值
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> defaultErrorHandler(Exception ex) {
        log.error("全局异常: [{}]", ex.getMessage(), ex);
        return new Result<String>(ResultCodeEnum.INTERNAL_SERVER_ERROR).setData(ex.getMessage());
        // 网络安全中心要求发生异常时不能泄漏代码和数据库的信息,直接返回ex.getMessage()可能会泄露.
        //return new Result<String>(ResultCodeEnum.INTERNAL_SERVER_ERROR).setData("");
    }


    @ExceptionHandler(value = AccessDeniedException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public Result<String> accessDeniedHandler(Exception ex) {
        log.error("401:该账号无权限: [{}]", ex.getMessage());
        return new Result<>(ResultCodeEnum.UNAUTHORIZED);
    }


    /**
     * 校验不通过
     *
     * @param ex 异常
     * @return 返回值
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> validationErrorHandler(MethodArgumentNotValidException ex) {
        StringBuilder sb = new StringBuilder();
        ex.getBindingResult().getAllErrors().forEach(error -> sb.append(error.getDefaultMessage()).append(","));
        log.error("验证未通过 ==> [{}], 字段 ==> [{}]", ex.getMessage(), sb.toString());
        //return new Result<String>(ResultCodeEnum.VALIDATE_NOT_ACCESS).setMsg(sb.toString());
        return new Result<>(400, sb.toString());
    }

    /**
     * 缺少请求参数
     *
     * @param ex 异常
     * @return 返回值
     */
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> missingServletRequestParameterErrorHandler(MissingServletRequestParameterException ex) {
        log.error("缺少请求参数:[{}]", ex.getMessage());
        return new Result<String>(ResultCodeEnum.MISSING_REQUEST_PARAMETER).setData(ex.getMessage());
    }

    /**
     * 请求参数类型错误
     *
     * @param ex 异常
     * @return 返回值
     */
    @ExceptionHandler(value = BindException.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> badRequestErrorHandler(BindException ex) {
        log.error("请求参数类型错误:[{}]", ex.getMessage());
        return new Result<String>(ResultCodeEnum.BAD_REQUEST).setData(ex.getMessage());
    }

    /**
     * 数据库操作错误
     *
     * @param ex 异常
     * @return 返回值
     */
    @ExceptionHandler(value = SQLException.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> databaseErrorHandler(SQLException ex) {
        log.error("数据库操作错误:[{}]", ex.getMessage());
        return new Result<String>(ResultCodeEnum.DATABASE_ERROR).setData(ex.getMessage());
    }

    /**
     * 网络连接失败
     *
     * @param ex 异常
     * @return 返回值
     */
    @ExceptionHandler(value = ConnectException.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public Result<String> connect(ConnectException ex) {
        log.error("网络连接失败:[{}]", ex.getMessage());
        return new Result<String>(ResultCodeEnum.CONNECTION_ERROR).setData(ex.getMessage());
    }

    /**
     * 业务异常
     *
     * @param ex 异常
     * @return 返回值
     */
    @ExceptionHandler(value = BizException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public Result<String> bizException(BizException ex) {
        log.info("业务异常:[{}]=={}", ex.getMsg(), ex.getData());
        return new Result<>(400, ex.getMsg(), ex.getMsg());
    }



    /**
     * 无权限
     *
     * @param ex 异常
     * @return 返回值
     */
    @ExceptionHandler(value = HttpClientErrorException.class)
    @ResponseStatus(value = HttpStatus.FORBIDDEN)
    public Result<String> badRequestException(HttpClientErrorException ex) {
        return new Result<>(403, ex.getMessage());
    }

}
