package jnpf.config;

import cn.dev33.satoken.exception.NotPermissionException;
import jnpf.base.ActionResult;
import jnpf.base.ActionResultCode;
import jnpf.exception.ApproveException;
import jnpf.exception.HandleException;
import jnpf.exception.QueryException;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.exceptions.PersistenceException;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.validation.ConstraintViolationException;
import java.util.HashSet;
import java.util.Set;

/**
 * 自定义全局异常
 *
 * @author yanwenfu
 * @create 2023-07-24
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public Object processDefaultException(Exception e) {
        log.error(e.getClass().getName());
        log.error(e.getMessage(), e);
        return ActionResult.fail("服务异常：" + e.getMessage());
    }

    @ExceptionHandler(HandleException.class)
    public Object processHandleException(HandleException e) {
        log.error(e.getClass().getName());
        log.error(e.getMessage(), e);
        return ActionResult.fail(e.getMessage());
    }

    @ExceptionHandler(RuntimeException.class)
    public Object processRuntimeException(RuntimeException e) {
        log.error(e.getClass().getName());
        log.error(e.getMessage(), e);
        return ActionResult.fail(e.getMessage());
    }

    @ExceptionHandler(value = MaxUploadSizeExceededException.class)
    public ActionResult<String> fileUploadExceptionHandler(MaxUploadSizeExceededException e) {
        log.error(e.getClass().getName());
        log.error(e.getMessage(), e);
        return ActionResult.fail("上传文件超过500MB限制");
    }

    @ExceptionHandler(QueryException.class)
    public Object processQueryException(QueryException e) {
        log.error(e.getClass().getName());
        log.error(e.getMessage(), e);
        return ActionResult.fail(e.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public Object handleBindException(MethodArgumentNotValidException e) {
        //打印校验住的所有的错误信息
        Set<String> set = new HashSet<>();
        e.getBindingResult().getAllErrors().forEach(item -> set.add(item.getDefaultMessage()));
        StringBuilder sb = getErrorMessage(set);
        log.error(e.getMessage(), e);
        return ActionResult.fail(sb.toString());
    }

    @ExceptionHandler(BindException.class)
    @ResponseBody
    public Object handleBindException(BindException e) {
        //打印校验住的所有的错误信息
        Set<String> set = new HashSet<>();
        log.error(e.getMessage(), e);
        e.getBindingResult().getAllErrors().forEach(item -> set.add(item.getDefaultMessage()));
        StringBuilder sb = getErrorMessage(set);
        return ActionResult.fail(sb.toString());
    }

    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public Object handleBindException(ConstraintViolationException e) {
        //打印校验住的所有的错误信息
        Set<String> set = new HashSet<>();
        e.getConstraintViolations().forEach(item -> set.add(item.getMessage()));
        StringBuilder sb = getErrorMessage(set);
        log.error(e.getMessage(), e);
        return ActionResult.fail(sb.toString());
    }

    @ExceptionHandler(ApproveException.class)
    public Object processApproveException(ApproveException e) throws ApproveException {
        log.error(e.getClass().getName());
        log.error(e.getMessage(), e);
        throw new ApproveException(e.getMessage());
    }

    /**
     * 权限码异常
     */
    @ResponseBody
    @ExceptionHandler(NotPermissionException.class)
    public ActionResult<Void> handleNotPermissionException(NotPermissionException e) {
        return ActionResult.fail(ActionResultCode.Fail.getCode(), "没有访问权限，请联系管理员授权");
    }

    @ExceptionHandler(MyBatisSystemException.class)
    public ActionResult<Void> handlePersistenceException(MyBatisSystemException e) {
        log.error(e.getMessage(), e);
        if (e.getCause() instanceof PersistenceException) {
            return ActionResult.fail(ActionResultCode.Fail.getCode(), e.getCause().getCause().getCause().getMessage());
        }
        return ActionResult.fail(ActionResultCode.Fail.getCode(), e.getMessage());
    }


    private StringBuilder getErrorMessage(Set<String> set) {

        StringBuilder sb = new StringBuilder("[");
        set.forEach(item -> sb.append(item).append(','));
        sb.deleteCharAt(sb.length() - 1);
        sb.append(']');
        return sb;
    }
}
