package org.fuseri.modulecertificate.exceptions;

import jakarta.persistence.EntityNotFoundException;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.util.UrlPathHelper;

import java.util.List;

@ControllerAdvice
public class RestResponseEntityExceptionHandler {
    private static final UrlPathHelper URL_PATH_HELPER = new UrlPathHelper();

    /**
     * Handle ResourceNotFoundException exceptions
     *
     * @param ex      exception
     * @param request request
     * @return response entity
     */
    @ExceptionHandler(value = {EntityNotFoundException.class})
    public ResponseEntity<ApiError> handleNotFoundError(EntityNotFoundException ex, HttpServletRequest request) {
        ApiError error = new ApiError(
                HttpStatus.NOT_FOUND,
                ex,
                URL_PATH_HELPER.getRequestUri(request));
        return buildResponseEntity(error);
    }

    /**
     * Handle Validation exceptions
     *
     * @param ex      exception
     * @param request request
     * @return response entity
     */
    @ExceptionHandler(value = {MethodArgumentNotValidException.class})
    public ResponseEntity<ApiError> handleValidationErrors(MethodArgumentNotValidException ex, HttpServletRequest request) {
        List<ApiSubError> subErrors = ex.getBindingResult().getFieldErrors()
                .stream()
                .map(e -> (ApiSubError) new ApiValidationError(e.getObjectName(), e.getField(), e.getRejectedValue(), e.getDefaultMessage()))
                .toList();
        ApiError error = new ApiError(
                HttpStatus.BAD_REQUEST,
                subErrors,
                ex,
                URL_PATH_HELPER.getRequestUri(request));
        return buildResponseEntity(error);
    }

    /**
     * Handle MessageNotReadable exceptions
     *
     * @param ex      exception
     * @param request request
     * @return response entity
     */
    @ExceptionHandler(value = {HttpMessageNotReadableException.class})
    public ResponseEntity<ApiError> handleMessageNotReadableErrors(HttpMessageNotReadableException ex, HttpServletRequest request) {
        ApiError error = new ApiError(
                HttpStatus.BAD_REQUEST,
                ex,
                URL_PATH_HELPER.getRequestUri(request));
        return buildResponseEntity(error);
    }

    /**
     * Handle exceptions not matched by above handler methods
     *
     * @param ex      exception
     * @param request request
     * @return response entity
     */
    @ExceptionHandler({Exception.class})
    public ResponseEntity<ApiError> handleAll(final Exception ex, HttpServletRequest request) {
        final ApiError error = new ApiError(
                HttpStatus.INTERNAL_SERVER_ERROR,
                ExceptionUtils.getRootCause(ex),
                URL_PATH_HELPER.getRequestUri(request));
        return buildResponseEntity(error);
    }

    private ResponseEntity<ApiError> buildResponseEntity(ApiError apiError) {
        return new ResponseEntity<>(apiError, apiError.getStatus());
    }
}
