package com.storlead.framework.web.handler;

import com.storlead.framework.common.result.Result;
import com.storlead.framework.web.exception.DaoException;
import com.storlead.framework.web.exception.TopException;
import com.storlead.framework.web.message.MsgCode;
import com.storlead.framework.web.message.TopMsgCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.redis.connection.PoolException;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.sql.SQLException;
import java.util.*;

/**
 * @program: storlead-mail-platform
 * @description:
 * @author: chenkq
 * @create: 2025-12-23 10:57
 */
@Slf4j
@RestControllerAdvice
public class ExceptionHandler {

    private final boolean ONLINE = StringUtils
            .startsWithIgnoreCase(StringUtils.isNotBlank(System.getProperty("spring.profiles.active"))
                    ? System.getProperty("spring.profiles.active")
                    : System.getProperty("spring.profiles.default"), "prod");
    /**
     * 校验错误拦截处理
     *
     * @param exception 错误信息集合
     * @return 错误信息
     */
    @org.springframework.web.bind.annotation.ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<?> validationBodyException(MethodArgumentNotValidException exception) {
        BindingResult result = exception.getBindingResult();
        String message = "";
        if (result.hasErrors()) {
            List<ObjectError> errors = result.getAllErrors();
            if (errors != null) {
                errors.forEach(p -> {
                    FieldError fieldError = (FieldError) p;
                    log.error("Data check failure : object{" + fieldError.getObjectName() + "},field{" + fieldError.getField() +
                            "},errorMessage{" + fieldError.getDefaultMessage() + "}");

                });
                if (errors.size() > 0) {
                    FieldError fieldError = (FieldError) errors.get(0);
                    message = fieldError.getDefaultMessage();
                }
            }
        }
        return Result.error("".equals(message) ? "请填写正确信息" : message);
    }

    @org.springframework.web.bind.annotation.ExceptionHandler(NoHandlerFoundException.class)
    public Result<?> handlerNoFoundException(Exception e) {
        log.error(e.getMessage(), e);
        return Result.error(404, "路径不存在，请检查路径是否正确");
    }

    @org.springframework.web.bind.annotation.ExceptionHandler(DuplicateKeyException.class)
    public Result<?> handleDuplicateKeyException(DuplicateKeyException e){
        log.error(e.getMessage(), e);
        return Result.error("数据库中已存在该记录");
    }

//	@ExceptionHandler(Exception.class)
//	public Result<?> handleException(Exception e){
//		log.error(e.getMessage(), e);
//		return Result.error("操作失败，"+e.getMessage());
//	}

    @org.springframework.web.bind.annotation.ExceptionHandler(HttpMessageConversionException.class)
    public Result<?> invalidFormatException(HttpMessageConversionException e){
        log.error("invalidFormatException --- error --", e);
        return Result.error("操作失败----，"+e.getMessage());
    }

    @org.springframework.web.bind.annotation.ExceptionHandler(HttpMessageNotReadableException.class)
    public Result<?> httpMessageNotReadableException(HttpMessageNotReadableException e){
        log.error("httpMessageNotReadableException --- error --", e);
        return Result.error("操作失败，参数转换失败,请校验传入参数类型是否正确!");
    }

    /**
     * @Author 政辉
     * @param e
     * @return
     */
    @org.springframework.web.bind.annotation.ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Result<?> HttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e){
        StringBuffer sb = new StringBuffer();
        sb.append("不支持");
        sb.append(e.getMethod());
        sb.append("请求方法，");
        sb.append("支持以下");
        String [] methods = e.getSupportedMethods();
        if(methods!=null){
            for(String str:methods){
                sb.append(str);
                sb.append("、");
            }
        }
        log.error(sb.toString(), e);
        //return Result.error("没有权限，请联系管理员授权");
        log.error("HttpRequestMethodNotSupportedException --- error --", e);
        return Result.error(405,sb.toString());
    }

    /**
     * spring默认上传大小100MB 超出大小捕获异常MaxUploadSizeExceededException
     */
    @org.springframework.web.bind.annotation.ExceptionHandler(MaxUploadSizeExceededException.class)
    public Result<?> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
        log.error("handleMaxUploadSizeExceededException --- error --", e);
        return Result.error("文件大小超出最大限制, 请压缩或降低文件质量! ");
    }

    @org.springframework.web.bind.annotation.ExceptionHandler(DataIntegrityViolationException.class)
    public Result<?> handleDataIntegrityViolationException(DataIntegrityViolationException e) {
        log.error("handleDataIntegrityViolationException --- error --", e);
        return Result.error("数据完整性异常");
//        return Result.error("字段太长,超出数据库字段的长度");
    }

    @org.springframework.web.bind.annotation.ExceptionHandler(PoolException.class)
    public Result<?> handlePoolException(PoolException e) {
        log.error("handlePoolException --- error --", e);
        return Result.error("Redis 连接异常!");
    }


    @org.springframework.web.bind.annotation.ExceptionHandler({ ConstraintViolationException.class, ValidationException.class, BindException.class })
    public Result onValidationException(Exception e) {
        Map<String, String> errorMessage;
        if (e instanceof BindException) {
            errorMessage = getErrorMessage((BindException) e);
        } else if (e instanceof ConstraintViolationException) {
            errorMessage = getErrorMessage((ConstraintViolationException) e);
        } else {
            throw new IllegalArgumentException("接收到不合理异常,无法处理,请检查编程错误", e);
        }
        log.error("onValidationException --- error --", e);
        return createWebResult(TopMsgCode.FORM_VALIDATE_ERROR, errorMessage);
    }

    //getBindingResult
    private static Map<String, String> getErrorMessage(BindException e) {
        BindingResult result = e.getBindingResult();
        List<ObjectError> errors = result.getAllErrors();
        if (errors == null || errors.isEmpty()) {
            return Collections.emptyMap();
        }
        Map<String, String> builder = new HashMap();
        //Builder<String, String> builder = ImmutableMap.builder();
        for (ObjectError oe : errors) {
            if (oe instanceof FieldError) {
                FieldError fe = (FieldError) oe;
                builder.put(fe.getField(), fe.getDefaultMessage());
            }
        }
        return builder;
    }

    private static Map<String, String> getErrorMessage(ConstraintViolationException e) {
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        if (violations == null || violations.isEmpty()) {
            return Collections.emptyMap();
        } else {
            Map<String, String> builder = new HashMap();
            for (ConstraintViolation<?> v : violations) {
                builder.put(v.getPropertyPath().toString(), v.getMessage());
            }
            return builder;
        }
    }

    @org.springframework.web.bind.annotation.ExceptionHandler({ DaoException.class, DataAccessException.class, SQLException.class })
    public Result onDaoException(Exception e) {
        log.error("onDaoException --- error --", e);
        if (ONLINE) {
            return createWebResult(TopMsgCode.DAO_ERROR, "数据库访问错误");
        } else {
            return createWebResult(TopMsgCode.DAO_ERROR, e.getMessage());
        }
    }

    @org.springframework.web.bind.annotation.ExceptionHandler(TopException.class)
    public Result onTopException(TopException e) {
        log.error("onTopException --- error --", e);
        return createWebResult(e.getCode(), e.getMessage());
    }

    @org.springframework.web.bind.annotation.ExceptionHandler
    public Result onOtherException(Exception e) {
        log.error("onOtherException --- error --", e);
        if (ONLINE) {
            return createWebResult(TopMsgCode.OTHER_ERROR, "未知异常");
        } else {
            return createWebResult(TopMsgCode.OTHER_ERROR, e.getMessage());
        }
    }

    private static Result createWebResult(MsgCode msgCode, Object value) {
        Result resp = createWebResult(msgCode,null);
        resp.setResult(value);
        return resp;
    }

    private static Result createWebResult(MsgCode msgCode, String message) {
        return Result.error(msgCode.code(), StringUtils.isNotBlank(message) ? message : msgCode.message());
    }


}
