package com.yunfeiyun.agmp.common.framework.web.exception;

import com.yunfeiyun.agmp.common.constant.ErrorCode;
import com.yunfeiyun.agmp.common.exception.BizException;
import com.yunfeiyun.agmp.common.framework.manager.RbacDictManager;
import com.yunfeiyun.agmp.common.framework.security.context.PermissionContextHolder;
import com.yunfeiyun.agmp.common.utils.StringUtils;
import com.yunfeiyun.agmp.common.core.domain.AjaxResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
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.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 全局异常处理器
 * 
 * @author 杨晓辉
 */
@Order(0)
@ControllerAdvice
@RestControllerAdvice
public class GlobalExceptionHandler
{
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 权限校验异常
     */
    @ExceptionHandler(AccessDeniedException.class)
    public AjaxResult handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        String permission = StringUtils.defaultIfEmpty(PermissionContextHolder.getContext(), "无权限");
        log.error("请求地址'{}',权限校验失败'{}'  需要配置权限='{}'", requestURI, e.getMessage(),permission);
        String  ancestorLabel =  RbacDictManager.getMenuAncestorRemark(permission);
        log.error("请求地址'{}',权限校验失败'{}'  需要配置权限='{}'  权限位置='{}'", requestURI, e.getMessage(),permission ,ancestorLabel );
        String errMsg  = String.format(" 请求地址=[%s] 需要配置权限=[%s]  权限位置=%s", requestURI,permission,ancestorLabel);
        return AjaxResult.error(ErrorCode.ACCESS_FORBIDDEN.getCode(), ErrorCode.ACCESS_FORBIDDEN.getMessage() + errMsg);
    }

    /**
     * 请求方式不支持
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        String errMsg  = String.format("请求地址%s 不支持%s请求", requestURI,e.getMethod());
        log.error("请求地址'{}',服务发生BizException异常={}", requestURI, e);
        return AjaxResult.error( ErrorCode.BIZ_ERROR.getCode(), ErrorCode.BIZ_ERROR.getMessage());
    }

    /**
     * 业务异常
     */
    @ExceptionHandler(BizException.class)
    public AjaxResult handleBizException(BizException e, HttpServletRequest request)
    {
        log.error(e.getMessage(), e);
        String requestURI = request.getRequestURI();
        String code = e.getCode();
        log.error("请求地址'{}',服务发生BizException异常={}", requestURI, e);
        return AjaxResult.error( e.getCode(), e.getMessage());
    }

    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        String errMsg  = String.format("请求地址%s 发生未知运行时异常:%s", requestURI,e);
        log.error("请求地址'{}',发生未知运行时异常={}", requestURI, e);
        return AjaxResult.error( ErrorCode.UNKNONW_RUNTIME_ERROR.getCode(), ErrorCode.UNKNONW_RUNTIME_ERROR.getMessage());
    }


    /**
     * 系统异常
     */
    @ExceptionHandler(Exception.class)
    public AjaxResult handleException(Exception e, HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        String errMsg  = String.format("请求地址%s 服务发生系统异常:%s", requestURI,e);
        log.error("请求地址'{}',发生未知异常={}", requestURI, e);
        return AjaxResult.error(ErrorCode.SYSTEM_ERROR.getCode(),ErrorCode.SYSTEM_ERROR.getMessage());
    }


    /**
     * 自定义验证异常
     */
    @ExceptionHandler(BindException.class)
    public AjaxResult handleBindException(BindException e,HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        log.error(e.getMessage(), e);
        String message = e.getAllErrors() == null ? "服务发生绑定验证异常:" + requestURI :  e.getAllErrors().get(0).getDefaultMessage();
        log.error("请求地址'{}',服务发生绑定验证异常={}", requestURI, e);
        return AjaxResult.error(ErrorCode.CUSTOM_BIND_ERROR.getCode(),ErrorCode.CUSTOM_BIND_ERROR.getMessage());
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e,HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        log.error(e.getMessage(), e);
        String msgError = e.getBindingResult() == null ? "服务发生自定义验证Valid异常" : e.getBindingResult().getFieldError() == null ? "服务发生自定义验证异2": e.getBindingResult().getFieldError().getDefaultMessage();
        log.error("请求地址'{}',服务发生自定义验证异常={}",requestURI,e);
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
        String message = allErrors.stream().map(s -> s.getDefaultMessage()).collect(Collectors.joining(";"));
        return AjaxResult.error(ErrorCode.CUSTOM_BIND_ERROR.getCode(),message == null ? ErrorCode.CUSTOM_BIND_ERROR.getMessage() : message);
    }


//    /**
//     * 基础异常验证异常
//     */
//    @ExceptionHandler(BaseException.class)
//    public Object handleBaseException(BaseException e,HttpServletRequest request)
//    {
//        String requestURI = request.getRequestURI();
//        log.error("请求地址'{}',服务发生BaseException验证异常={}",requestURI,e);
//        return AjaxResult.error( e.getCode(), e.getMessage());
//    }

}
