package cn.lihongjie.coal.spring.config;

import cn.lihongjie.coal.base.dto.R;
import cn.lihongjie.coal.exception.BizException;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;

import lombok.extern.slf4j.Slf4j;

import org.springframework.core.annotation.Order;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.HandlerMethod;

import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@RestControllerAdvice
@Slf4j
@Order(1)
public class GlobalExceptionHandler {


    @ExceptionHandler(InvalidDataAccessApiUsageException.class)
    public R handleException(
            InvalidDataAccessApiUsageException ex, HttpServletRequest request, HandlerMethod handlerMethod) {
        logEx(ex, request, handlerMethod);

        Pattern pattern = Pattern.compile("\\[(.+?)\\]");

        Matcher matcher = pattern.matcher(ex.getMessage());

        if (matcher.find()) {
            return R.fail("fieldNotExist", "字段不存在: " + matcher.group(1));
        }


        return R.fail("sysError", "系统异常: " + ex.getMessage());
    }
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R handleException(
            MethodArgumentNotValidException ex, HttpServletRequest request, HandlerMethod handlerMethod) {
        logEx(ex, request, handlerMethod);
        List<ConstraintViolation> allError =
                ex.getBindingResult().getAllErrors().stream()
                        .map(oe -> oe.unwrap(ConstraintViolation.class))
                        .collect(Collectors.toList());
        List<Map<String, ? extends Object>> errorData =
                allError.stream()
                        .map(
                                x ->
                                        Map.of(
                                                "field",
                                                x.getPropertyPath() == null? "null" : x.getPropertyPath().toString(),
                                                "msg",
                                                x.getMessage(),

                                                "annotation",
                                                x.getConstraintDescriptor()
                                                        .getAnnotation()  == null ? "null":x.getConstraintDescriptor()
                                                        .getAnnotation()
                                                        .annotationType()
                                                        .getName()))
                        .collect(Collectors.toList());

        return R.fail("validError",   errorData.stream().map(x -> x.get("msg") + "").collect(Collectors.joining(", ")), errorData);
    }

    @ExceptionHandler(BizException.class)
    public R handleException(
            BizException ex, HttpServletRequest request, HandlerMethod handlerMethod) {
        logEx(ex, request, handlerMethod);
        return R.fail(ex.getCode(), ex.getMessage());
    }

    private void logEx(Exception ex, HttpServletRequest request, HandlerMethod handlerMethod) {
        if (request.getAttribute("__logged") == null) {

            log.info(
                    "接口调用异常: {}\nurl:{} {}\nmethod: {}",
                    ex.getMessage() == null ? "no message" : ex.getMessage(),
                    request.getMethod(),
                    request.getRequestURL(),
                    handlerMethod.getMethod(),
                    ex);
        }
    }

    @ExceptionHandler(RuntimeException.class)
    public R handleException(
            RuntimeException ex, HttpServletRequest request, HandlerMethod handlerMethod) {
        logEx(ex, request, handlerMethod);
        return R.fail("sysError", "系统异常: " + ex.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public R handleException(
            Exception ex, HttpServletRequest request, HandlerMethod handlerMethod) {
        logEx(ex, request, handlerMethod);
        return R.fail("sysError", "系统异常: " + ex.getMessage());
    }
}
