package com.codvision.webcore.config;

import com.codvision.commoncore.common.ResponseEntity;
import com.codvision.commoncore.exception.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.validation.BindException;
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.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;

import java.util.Arrays;
import java.util.Objects;

import static org.springframework.http.HttpStatus.*;

/**
 * @Author huxb
 * @description: 全局异常捕获
 * @create 2022/11/22 10:30
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @Autowired
    private Environment environment;

    /**
     * LimitException
     *
     * @param e the e
     * @return R
     */
    @ExceptionHandler(LimitException.class)
    @ResponseStatus(TOO_MANY_REQUESTS)
    public ResponseEntity<String> handleLimitException(LimitException e) {
        ResponseEntity<String> responseEntity = new ResponseEntity<>();
        log.error("接口限流，ex={}", e.getMessage());
        return responseEntity.error(429, e.getMessage());
    }


    /**
     * IdempotentException
     *
     * @param e the e
     * @return R
     */
    @ExceptionHandler(IdempotentException.class)
    @ResponseStatus(TOO_MANY_REQUESTS)
    public ResponseEntity<String> handleIdempotentException(IdempotentException e) {
        ResponseEntity<String> responseEntity = new ResponseEntity<>();
        log.error("请求频繁异常，ex={}", e.getMessage());
        return responseEntity.error(429, e.getMessage());
    }


    /**
     * Validation Exception
     *
     * @param ex
     * @return
     */
    @ResponseStatus(BAD_REQUEST)
    @ExceptionHandler(BindException.class)
    public ResponseEntity<Object> handleBodyValidException(BindException ex) {
        String errorMsg = Objects.requireNonNull(ex.getBindingResult().getFieldError()).getDefaultMessage();
        log.error(errorMsg);
        return new ResponseEntity<>().error(30002, errorMsg);
    }

    /**
     * Business Exception
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(INTERNAL_SERVER_ERROR)
    public ResponseEntity<Object> businessException(BusinessException ex) {
        log.error(ex.getMessage(), ex);
        if (null == ex.getCode() && null != ex.getMessage()) {
            return new ResponseEntity<>().error(10000, ex.getMessage());
        }
        if (null == ex.getMessage() && null != ex.getCode()) {
            return new ResponseEntity<>().error(ex.getCode());
        }
        return new ResponseEntity<>().error(ex.getCode(), ex.getMessage());
    }


    /**
     * File Upload Exception
     *
     * @param ex
     * @return
     */
    @ResponseStatus(INTERNAL_SERVER_ERROR)
    @ExceptionHandler(MultipartException.class)
    public ResponseEntity<Object> fileUploadException(Exception ex) {
        log.error(ex.getMessage(), ex);
        if (ex instanceof MaxUploadSizeExceededException) {
            return new ResponseEntity<>().error(50002);
        }

        return new ResponseEntity<>().error(50003);
    }

    /**
     * Shiro AuthorizationException
     *
     * @param ex
     * @return
     */
    @ResponseStatus(UNAUTHORIZED)
    @ExceptionHandler(AuthException.class)
    public ResponseEntity<Object> authorizationException(AuthException ex) {
        log.error(ex.getMessage(), ex);
        if (null != ex.getCode() && null != ex.getMessage()) {
            return new ResponseEntity<>().error(ex.getCode(), ex.getMessage());
        }
        if (null == ex.getCode() && null != ex.getMessage()) {
            return new ResponseEntity<>().error(10002, ex.getMessage());
        }
        if (null == ex.getMessage() && null != ex.getCode()) {
            return new ResponseEntity<>().error(ex.getCode());
        }
        return new ResponseEntity<>().error(10002);
    }

    @ResponseStatus(FORBIDDEN)
    @ExceptionHandler(PermissionException.class)
    public ResponseEntity<Object> permissionException(PermissionException ex) {
        log.error(ex.getMessage(), ex);
        if (null == ex.getCode()) {
            return new ResponseEntity<>().error(20001, ex.getMessage());
        }
        if (null == ex.getMessage()) {
            return new ResponseEntity<>().error(ex.getCode());
        }
        return new ResponseEntity<>().error(20001);
    }


    /**
     * Shiro AuthorizationException
     *
     * @param ex
     * @return
     */
    @ResponseStatus(BAD_REQUEST)
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<Object> illegalArgumentException(Exception ex) {
        log.error(ex.getMessage(), ex);
        return new ResponseEntity<>().error(30002, ex.getMessage());
    }

    /**
     * RuntimeException
     *
     * @param ex
     * @return
     */
    @ResponseStatus(INTERNAL_SERVER_ERROR)
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<Object> runtimeException(RuntimeException ex) {
        log.error(ex.getMessage(), ex);
        if (Arrays.stream(environment.getActiveProfiles()).filter(item -> item.equals("dev")).count() > 0) {
            return new ResponseEntity<>().error(990000).data(ex.getMessage());
        }
        return new ResponseEntity<>().error(990000);
    }
}
