package cn.reghao.bnt.web.config.web.exception;

import cn.reghao.bnt.web.admin.model.po.Menu;
import cn.reghao.bnt.web.admin.service.MenuService;
import cn.reghao.jutil.jdk.exception.ExceptionUtil;
import cn.reghao.jutil.jdk.web.result.ResultStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import jakarta.servlet.http.HttpServletRequest;
import java.util.stream.Collectors;

/**
 * 全局异常处理类，处理 controller 抛出的异常
 *
 * @author reghao
 * @date 2019/03/21 10:25:49
 */
@Slf4j
@ControllerAdvice
public class ControllerExceptionHandler {
    private final MenuService menuService;
    private final MappingJackson2JsonView mappingJackson2JsonView = new MappingJackson2JsonView();

    public ControllerExceptionHandler(MenuService menuService) {
        this.menuService = menuService;
    }

    /**
     * 处理所有 controller 上抛出的异常
     *
     * @date 2019-09-28 上午11:01
     */
    @ExceptionHandler({Exception.class})
    public ModelAndView error(Exception e, HttpServletRequest request) {
        String method = request.getMethod();
        String uri = request.getRequestURI();
        String msg = ExceptionUtil.errorMsg(e);
        log.error("{} 接口抛出异常: {}", uri, msg);

        String retMsg = msg;
        int status = HttpStatus.OK.value();
        if (e instanceof AuthenticationException) {
            status = HttpStatus.UNAUTHORIZED.value();
        } else if (e instanceof MethodArgumentNotValidException) {
            // 参数校验失败
            MethodArgumentNotValidException exception = (MethodArgumentNotValidException) e;
            String errMsg = exception.getBindingResult().getAllErrors().stream()
                    .map(objectError -> {
                        String message = objectError.getDefaultMessage();
                        return message + "\n";
                    }).collect(Collectors.joining());
            retMsg = errMsg;
            /*body = exception.getBindingResult().getAllErrors().stream()
                    .map(DefaultMessageSourceResolvable::getDefaultMessage)
                    .collect(Collectors.joining());*/
        } else if (e instanceof IllegalStateException) {
            IllegalStateException exception = (IllegalStateException) e;
            Throwable throwable = exception.getCause();
            retMsg = throwable.getMessage();
        } else if (e instanceof BindException) {
            BindException bindException = (BindException) e;
            StringBuilder sb = new StringBuilder();
            bindException.getAllErrors().forEach(objectError -> {
                sb.append(objectError.getDefaultMessage()).append(System.lineSeparator());
            });
            retMsg = sb.toString();
        }

        ModelAndView mav = new ModelAndView();
        mav.addObject("code", ResultStatus.FAIL.getCode());
        mav.addObject("msg", retMsg);
        Menu menu = menuService.getMenu(method, uri);
        if (menu != null && menu.getVisible()) {
            // text/html
            String viewPath = "/classic/error";
            if (uri.startsWith("/bg")) {
                viewPath = "/admin/error";
            }

            mav.setViewName(viewPath);
            return mav;
        } else {
            // application/json
            mav.setView(mappingJackson2JsonView);
            return mav;
        }
    }
}
