package com.ytpm.handle;

import cn.hutool.core.util.StrUtil;
import com.ytpm.general.Result;
import com.ytpm.general.StatusCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.text.MessageFormat;
import java.util.List;
import java.util.Set;

/**
 * @author Marx
 * @date 2025/8/28 10:38
 */
@Slf4j(topic = "agent-exception")
@RestControllerAdvice(annotations = RestController.class)
public class CustomerExceptionHandler implements HandlerExceptionResolver {
    @ResponseBody
    @ExceptionHandler(Exception.class)
    public Result handleException(Exception ex) {
        //打印异常信息
        log.error("抛出异常信息，异常信息为：ex={}",ex);
        ex.printStackTrace();
        String msg = "查询超时，请稍后重试！";
        return new Result(StatusCode.ERROR,msg);
    }

    /**
     * 对象参数校验失败
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Result handleMissingServletRequestParameterException(Exception ex) {
        log.error("对象参数校验失败，异常信息为：e={}", ex);
        String msg = MessageFormat.format("缺少参数{0}", ((MissingServletRequestParameterException) ex).getParameterName());
        return new Result(StatusCode.MISSING_PARAMETER, msg);
    }

    /**
     * 单个参数校验失败
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(ConstraintViolationException.class)
    public Result handleConstraintViolationException(Exception ex) {
        log.error("单个参数校验失败，异常信息为：ex={}",ex);
        ex.printStackTrace();
        Set<ConstraintViolation<?>> sets = ((ConstraintViolationException) ex).getConstraintViolations();
        if (!CollectionUtils.isEmpty(sets)) {
            StringBuilder sb = new StringBuilder();
            sets.forEach(error -> {
//                if (error instanceof FieldError) {
//                    sb.append(((FieldError) error).getField()).append(":");
//                }
                sb.append(error.getMessage()).append(";");
            });
            String msg = sb.toString();
            msg = StrUtil.sub(msg, 0, msg.length() - 1);
            return new Result(StatusCode.PARAMETER_CHECK_ERR, msg);
        }
        return new Result(StatusCode.PARAMETER_CHECK_ERR, "参数校验失败");
    }

    /**
     * 自定义校验异常信息捕获
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(IllegalArgumentException.class)
    public Result handleSpringCheckException(Exception ex) {
        log.error("自定义校验异常信息捕获，异常信息为：ex={}",ex);
        ex.printStackTrace();
        String msg = ex.getMessage();
        return new Result(StatusCode.PARAMETER_CHECK_ERR, msg);
    }

    /**
     * POST 请求参数校验失败
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result handleMethodArgumentNotValidException(Exception ex) {
        log.error(" 请求参数校验失败，异常信息为：ex={}",ex);
        ex.printStackTrace();
        List<ObjectError> errors = ((MethodArgumentNotValidException) ex).getBindingResult().getAllErrors();
        String msg = getValidExceptionMsg(errors);
        return new Result(StatusCode.PARAMETER_CHECK_ERR, msg);
    }

    @ResponseBody
    @ExceptionHandler(ValidatedException.class)
    public Result handleValidatedException(Exception ex) {
        log.error(" 请求参数校验失败，异常信息为：ex={}",ex.getMessage());
        return new Result(StatusCode.BUSINESS_CERTIFICATE_TYPE_STATUS_ERROR, ex.getMessage());
    }

    /**
     * 获取属性校验异常信息
     * @param errors
     * @return
     */
    private String getValidExceptionMsg(List<ObjectError> errors) {
        if(!CollectionUtils.isEmpty(errors)){
            StringBuilder sb = new StringBuilder();
            errors.forEach(error -> {
//                if (error instanceof FieldError) {
//                    sb.append(((FieldError)error).getField()).append(":");
//                }
                sb.append(error.getDefaultMessage()).append(";");
            });
            String msg = sb.toString();
            msg = StrUtil.sub(msg,0, msg.length() -1);
            return msg;
        }
        return "绑定异常";
    }

    @ResponseBody
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public Result handlerFileUploadException(MaxUploadSizeExceededException ex){
        log.error("抛出异常信息，异常信息为：ex={}",ex);
        return new Result(StatusCode.ERROR,"文件超出限制(10MB)");
    }

    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
        log.error(" 系统异常，异常信息为：e={}", e.getMessage());
        ModelAndView mv = new ModelAndView(new MappingJackson2JsonView());
        if (e instanceof MultipartException) {
            mv.addObject("message", "系统异常");
            mv.addObject("code", "801");
            mv.setStatus(HttpStatus.OK);
        } else {
            mv.addObject("msg", e.getMessage());
        }
        return mv;
    }

    @ResponseBody
    @ExceptionHandler(CustomerException.class)
    public Result handleCustomerException(Exception ex){
        log.error("自定义校验异常信息捕获，异常信息为：ex={}", ex);
        ex.printStackTrace();
        String msg = ex.getMessage();
        return new Result(StatusCode.ACCESS_ERR, msg);
    }


}
