package com.jeeplus.gateway.handler;

import com.alibaba.fastjson.JSON;
import io.netty.channel.ConnectTimeoutException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Objects;

/**
 * 网关统一异常处理
 *
 * @author 刘高峰
 */
//@Order(-1)
@ControllerAdvice
@Configuration("jpExceptionTranslator")
public class GatewayExceptionHandler implements ErrorWebExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger ( GatewayExceptionHandler.class );

    @Override
    public Mono <Void> handle(ServerWebExchange exchange, Throwable ex) {
        ServerHttpResponse response = exchange.getResponse ( );

        if ( exchange.getResponse ( ).isCommitted ( ) ) {
            return Mono.error ( ex );
        }

        String msg;

        if ( ex instanceof NotFoundException ) {
            msg = "服务未找到";
            response.setStatusCode ( HttpStatus.NOT_FOUND );
        } else if ( ex instanceof ConnectTimeoutException ) {
            msg = "请求服务超时";
            response.setStatusCode ( HttpStatus.GATEWAY_TIMEOUT );
        }
        /**
         * 登录过期，或者用户名密码错误
         */
        else if ( ex instanceof AccessDeniedException ) {
            msg = ex.getMessage ( );
            response.setStatusCode ( HttpStatus.UNAUTHORIZED );
        }
//        /**
//         * 没有访问资源的权限
//         */
//        else if (ex instanceof AuthException ) {
//            msg = "权限不足:" + ex.getMessage();
//            response.setStatusCode (  HttpStatus.FORBIDDEN );
//        }

        /**
         * 请求参数非法
         */
        else if ( ex instanceof MissingServletRequestPartException ||
                ex instanceof MissingServletRequestParameterException ) {
            msg = "您提交的参数，服务器无法处理";
            response.setStatusCode ( HttpStatus.BAD_REQUEST );
        }
        /**
         * 处理所有接口数据验证异常
         */
        else if ( ex instanceof MethodArgumentNotValidException ) {
            ObjectError error = ((MethodArgumentNotValidException) ex).getBindingResult ( ).getAllErrors ( ).get ( 0 );
            String[] str = Objects.requireNonNull ( error.getCodes ( ) )[1].split ( "\\." );
            msg = "参数" + str[1] + ", 数据验证失败:" + error.getDefaultMessage ( );
            response.setStatusCode ( HttpStatus.BAD_REQUEST );
        } else if ( ex instanceof BindException ) {
            ObjectError error = ((BindException) ex).getBindingResult ( ).getAllErrors ( ).get ( 0 );
            String[] str = Objects.requireNonNull ( error.getCodes ( ) )[1].split ( "\\." );
            msg = "参数" + str[1] + ", 数据验证失败:" + error.getDefaultMessage ( );
            response.setStatusCode ( HttpStatus.BAD_REQUEST );
        } else if ( ex instanceof ResponseStatusException ) {
            ResponseStatusException responseStatusException = (ResponseStatusException) ex;
            response.setStatusCode ( responseStatusException.getStatus ( ) );
            msg = responseStatusException.getMessage ( );
        }
        /**
         * 处理未知异常
         */
        else {
            msg = "内部错误: " + ex.getMessage ( );
            response.setStatusCode ( HttpStatus.INTERNAL_SERVER_ERROR );
        }

        log.error ( "[网关异常处理]请求路径:{},异常信息:{}", exchange.getRequest ( ).getPath ( ), ex.getMessage ( ) );

        response.getHeaders ( ).setContentType ( MediaType.APPLICATION_JSON );


        return response.writeWith ( Mono.fromSupplier ( () -> {
            DataBufferFactory bufferFactory = response.bufferFactory ( );
            return bufferFactory.wrap ( JSON.toJSONBytes ( msg ) );
        } ) );
    }


    /**
     * 处理所有接口数据验证异常
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        // 打印堆栈信息
        ObjectError error = e.getBindingResult ( ).getAllErrors ( ).get ( 0 );
        String[] str = Objects.requireNonNull ( error.getCodes ( ) )[1].split ( "\\." );
        String errMsg = "参数" + str[1] + ", 数据验证失败:" + error.getDefaultMessage ( );
        log.error ( "{}", e );
        return new ResponseEntity ( errMsg, HttpStatus.BAD_REQUEST );
    }

    @ExceptionHandler({BindException.class})
    public ResponseEntity handleBindException(BindException e) {
        // 打印堆栈信息
        ObjectError error = e.getBindingResult ( ).getAllErrors ( ).get ( 0 );
        String[] str = Objects.requireNonNull ( error.getCodes ( ) )[1].split ( "\\." );
        String errMsg = "参数" + str[1] + ", 数据验证失败:" + error.getDefaultMessage ( );
        log.error ( "{}", e );
        return new ResponseEntity ( errMsg, HttpStatus.BAD_REQUEST );
    }

}
