package com.jeeplus.common;

import com.jeeplus.aop.demo.exception.DemoException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
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 java.util.Objects;

@Slf4j
@ControllerAdvice
@Configuration("jpExceptionTranslator")
public class ExceptionTranslator {
    /**
     * 处理未知异常
     */
    @ExceptionHandler({Throwable.class, java.sql.SQLException.class, RuntimeException.class})
    public ResponseEntity handleException(Throwable e) {

        String errMsg = "错误: " + e.getMessage ( );
        log.error ( "{}", e );
        return new ResponseEntity ( errMsg, HttpStatus.INTERNAL_SERVER_ERROR );
    }

    /**
     * 演示模式，禁止操作
     */
    @ExceptionHandler({DemoException.class})
    public ResponseEntity handleDemoException(Throwable e) {

        String errMsg = e.getMessage ( );
        log.error ( "{}", e );
        return new ResponseEntity ( errMsg, HttpStatus.FORBIDDEN );
    }


    /**
     * 没有访问资源的权限
     */
    @ExceptionHandler(AccessDeniedException.class)
    public ResponseEntity handleUnauthorizedException(Throwable e) {

        String errMsg = "权限不足:" + e.getMessage ( );
        log.error ( "{}", e );
        return new ResponseEntity ( errMsg, HttpStatus.FORBIDDEN );
    }

    /**
     * 登录过期，或者用户名密码错误
     *
     * @param e
     * @return
     */
    @ExceptionHandler(AuthenticationException.class)
    public ResponseEntity handleAuthenticationException(Throwable e) {

        String errMsg = e.getMessage ( );
        log.error ( "{}", e );
        return new ResponseEntity ( errMsg, HttpStatus.UNAUTHORIZED );
    }

    /**
     * 请求参数非法
     */
    @ExceptionHandler({
            MissingServletRequestPartException.class,
            MissingServletRequestParameterException.class})
    public ResponseEntity handleBadRequestException(Throwable e) {

        String errMsg = "您提交的参数，服务器无法处理";
        log.error ( "{}", e );
        return new ResponseEntity ( errMsg, HttpStatus.BAD_REQUEST );
    }

    /**
     * 处理所有接口数据验证异常
     */
    @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 );
    }


    /**
     * Post-process the Problem payload to add the message key for the front-end if needed.
     */
//    @Override
//    public Mono <ResponseEntity<Problem>> process(@Nullable ResponseEntity<Problem> entity, ServerWebExchange request) {
//        if (entity == null) {
//            return Mono.empty();
//        }
//        Problem problem = entity.getBody();
//        if (!(problem instanceof ConstraintViolationProblem || problem instanceof DefaultProblem)) {
//            return Mono.just(entity);
//        }
//
//        ProblemBuilder builder = Problem
//                .builder()
//                .withType(Problem.DEFAULT_TYPE.equals(problem.getType()) ? ErrorConstants.DEFAULT_TYPE : problem.getType())
//                .withStatus(problem.getStatus())
//                .withTitle(problem.getTitle())
//                .with(PATH_KEY, request.getRequest().getPath().value());
//
//        if (problem instanceof ConstraintViolationProblem) {
//            builder
//                    .with(VIOLATIONS_KEY, ((ConstraintViolationProblem) problem).getViolations())
//                    .with(MESSAGE_KEY, ErrorConstants.ERR_VALIDATION);
//        } else {
//            builder.withCause(((DefaultProblem) problem).getCause()).withDetail(problem.getDetail()).withInstance(problem.getInstance());
//            problem.getParameters().forEach(builder::with);
//            if (!problem.getParameters().containsKey(MESSAGE_KEY) && problem.getStatus() != null) {
//                builder.with(MESSAGE_KEY, "error.http." + problem.getStatus().getStatusCode());
//            }
//        }
//        return Mono.just(new ResponseEntity<>(builder.build(), entity.getHeaders(), entity.getStatusCode()));
//    }
//
//    @Override
//    public Mono<ResponseEntity<Problem>> handleBindingResult(WebExchangeBindException ex, @Nonnull ServerWebExchange request) {
//        BindingResult result = ex.getBindingResult();
//        List <FieldErrorVM> fieldErrors = result
//                .getFieldErrors()
//                .stream()
//                .map(
//                        f ->
//                                new FieldErrorVM(
//                                        f.getObjectName().replaceFirst("DTO$", ""),
//                                        f.getField(),
//                                        StringUtils.isNotBlank(f.getDefaultMessage()) ? f.getDefaultMessage() : f.getCode()
//                                )
//                )
//                .collect( Collectors.toList());
//
//        Problem problem = Problem
//                .builder()
//                .withType(ErrorConstants.CONSTRAINT_VIOLATION_TYPE)
//                .withTitle("Data binding and validation failure")
//                .withStatus( Status.BAD_REQUEST)
//                .with(MESSAGE_KEY, ErrorConstants.ERR_VALIDATION)
//                .with(FIELD_ERRORS_KEY, fieldErrors)
//                .build();
//        return create(ex, problem, request);
//    }
//
//    @ExceptionHandler
//    public Mono<ResponseEntity<Problem>> handleBadRequestAlertException(BadRequestAlertException ex, ServerWebExchange request) {
//        return create(
//                ex,
//                request,
//                HeaderUtil.createFailureAlert("jeeplus", true, ex.getEntityName(), ex.getErrorKey(), ex.getMessage())
//        );
//    }
//
//    @ExceptionHandler
//    public Mono<ResponseEntity<Problem>> handleConcurrencyFailure(ConcurrencyFailureException ex, ServerWebExchange request) {
//        Problem problem = Problem.builder().withStatus(Status.CONFLICT).with(MESSAGE_KEY, ErrorConstants.ERR_CONCURRENCY_FAILURE).build();
//        return create(ex, problem, request);
//    }
//
//    @Override
//    public ProblemBuilder prepare(final Throwable throwable, final StatusType status, final URI type) {
//            if (throwable instanceof HttpMessageConversionException ) {
//                return Problem
//                        .builder()
//                        .withType(type)
//                        .withTitle(status.getReasonPhrase())
//                        .withStatus(status)
//                        .withDetail("Unable to convert http message")
//                        .withCause(
//                                Optional.ofNullable(throwable.getCause()).filter( cause -> isCausalChainsEnabled()).map(this::toProblem).orElse(null)
//                        );
//            }
//            if (throwable instanceof DataAccessException ) {
//                return Problem
//                        .builder()
//                        .withType(type)
//                        .withTitle(status.getReasonPhrase())
//                        .withStatus(status)
//                        .withDetail("Failure during data access")
//                        .withCause(
//                                Optional.ofNullable(throwable.getCause()).filter(cause -> isCausalChainsEnabled()).map(this::toProblem).orElse(null)
//                        );
//            }
//            if (containsPackageName(throwable.getMessage())) {
//                return Problem
//                        .builder()
//                        .withType(type)
//                        .withTitle(status.getReasonPhrase())
//                        .withStatus(status)
//                        .withDetail("Unexpected runtime exception")
//                        .withCause(
//                                Optional.ofNullable(throwable.getCause()).filter(cause -> isCausalChainsEnabled()).map(this::toProblem).orElse(null)
//                        );
//            }
//
//        return Problem
//                .builder()
//                .withType(type)
//                .withTitle(status.getReasonPhrase())
//                .withStatus(status)
//                .withDetail(throwable.getMessage())
//                .withCause(
//                        Optional.ofNullable(throwable.getCause()).filter(cause -> isCausalChainsEnabled()).map(this::toProblem).orElse(null)
//                );
//    }
//
//    private boolean containsPackageName(String message) {
//        // This list is for sure not complete
//        return StringUtils.containsAny(message, "org.", "java.", "net.", "javax.", "com.", "io.", "de.", "com.jeeplus");
//    }


}
