package com.sikey.wa04.common.interceptor;

import com.sikey.wa04.common.exception.BusinessException;
import com.sikey.wa04.common.exception.ErrorResponse;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.bind.support.WebExchangeBindException;
import org.springframework.web.servlet.resource.NoResourceFoundException;

import java.util.Map;
import java.util.Objects;
import java.util.Optional;

@Slf4j
@RestControllerAdvice
public class ApplicationMvcExceptionAdvice {


    /**
     * 处理参数校验异常
     * <br />
     * 如果是 webflux 使用 {@link  WebExchangeBindException}
     *
     * @param ex      MethodArgumentNotValidException
     * @param request HttpServletRequest
     * @return ResponseEntity<Object>
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Object> handleValidationException(MethodArgumentNotValidException ex, HttpServletRequest request) {
        Optional<FieldError> firstFieldError = ex.getFieldErrors().stream().findFirst();
        if (firstFieldError.isPresent()) {
            FieldError fieldError = firstFieldError.get();

            String path = request.getRequestURI();
            String message = fieldError.getDefaultMessage();
            String reason = Objects.requireNonNull(ex.getBody().getDetail()).toUpperCase();

            ErrorResponse errorResponse = new ErrorResponse(HttpStatus.UNAUTHORIZED.value(), path, message, MDC.get("requestId"), fieldError.toString());
            return ResponseEntity.badRequest().body(errorResponse);
        } else {
            return ResponseEntity.badRequest().body(Map.of("message", "请求参数错误"));
        }
    }

    @ExceptionHandler(NoResourceFoundException.class)
    public ResponseEntity<Object> handleNoResourceFoundException(NoResourceFoundException ex, HttpServletRequest request) {
        String path = request.getRequestId();
        String message = ex.getMessage();
        ErrorResponse errorResponse = new ErrorResponse(HttpStatus.NOT_FOUND.value(), path, message, MDC.get("requestId"), ex.toString());
        log.error("NoResourceFoundException: ", ex);
        return ResponseEntity.badRequest().body(errorResponse);
    }

    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<Object> handleBusinessException(BusinessException ex, HttpServletRequest request) {
        ErrorResponse errorResponse = new ErrorResponse(ex.getCode(), request.getRequestURI(), ex.getMessage(), MDC.get("requestId"), ex.toString());
        log.error("Intercept an exception: {}", ex.toString());
        return ResponseEntity.badRequest().body(errorResponse);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<Object> handleOtherException(Exception ex, HttpServletRequest request) {
        ResponseEntity<Object> errorResponse = getResponseEntityMono(ex, request);
        log.error("Exception: ", ex);
        return errorResponse;
    }

    private ResponseEntity<Object> getResponseEntityMono(Exception ex, HttpServletRequest request) {
        String path = request.getRequestURI();
        String message = ex.getMessage();
        String reason = HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase();
        ErrorResponse errorResponse = new ErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), path, message, MDC.get("requestId"), ex.toString());
        return ResponseEntity.badRequest().body(errorResponse);
    }

}
