package com.qmth.boot.api.exception;

import com.qmth.boot.core.exception.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.Nullable;
import org.springframework.validation.BindException;
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.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    protected static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @ExceptionHandler(ApiException.class)
    public ResponseEntity<Object> handleApiException(ApiException e) {
        return new ResponseEntity<>(e.responseEntity(), new HttpHeaders(), e.getStatus());
    }

    @ExceptionHandler(ParameterException.class)
    public ResponseEntity<Object> handleParameterException(ParameterException e) {
        //log.error(e.getMessage(), e);
        return handleApiException(DefaultExceptionEnum.REQUEST_PARAMETER_INVALID.exception(e));
    }

    @ExceptionHandler(UnauthorizedException.class)
    public ResponseEntity<Object> handleUnauthorizedException(UnauthorizedException e) {
        //log.error(e.getMessage(), e);
        return handleApiException(DefaultExceptionEnum.AUTHORIZATION_ERROR.exception(e));
    }

    @ExceptionHandler(ReentrantException.class)
    public ResponseEntity<Object> handleReentrantException(ReentrantException e) {
        //log.error(e.getMessage(), e);
        return handleApiException(DefaultExceptionEnum.REENTRANT_EXCEPTION.exception(e.getMessage()));
    }

    @ExceptionHandler(StatusException.class)
    public ResponseEntity<Object> handleStatusException(StatusException e) {
        //log.error(e.getMessage(), e);
        return handleApiException(DefaultExceptionEnum.COMMON_EXCEPTION.exception(e));
    }

    @ExceptionHandler(NotFoundException.class)
    public ResponseEntity<Object> handleNotFoundException(NotFoundException e) {
        //log.error(e.getMessage(), e);
        return handleApiException(DefaultExceptionEnum.RESOURCE_NOT_FOUND.exception(e));
    }

    @ExceptionHandler(ForbiddenException.class)
    public ResponseEntity<Object> handleForbiddenException(ForbiddenException e) {
        //log.error(e.getMessage(), e);
        return handleApiException(DefaultExceptionEnum.ACCESS_FORBIDDEN.exception(e));
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<Object> handleOtherException(Exception e) {
        log.error(e.getMessage(), e);
        return handleApiException(DefaultExceptionEnum.COMMON_EXCEPTION.exception(e.getMessage()));
    }

    @Override
    protected ResponseEntity<Object> handleExceptionInternal(Exception ex, @Nullable Object body, HttpHeaders headers,
            HttpStatus status, WebRequest request) {
        //log.error(ex.getMessage(), ex);
        return new ResponseEntity<>(
                new ExceptionResponseEntity(status.value(), status.name().toLowerCase(), ex.getMessage()), headers,
                status);
    }

    @Override
    protected ResponseEntity<Object> handleBindException(BindException ex, HttpHeaders headers, HttpStatus status,
            WebRequest request) {
        //log.warn(ex.getMessage(), ex);
        FieldError fieldError = ex.getBindingResult().getFieldError();
        String description = fieldError != null ? fieldError.getDefaultMessage() : null;
        return handleApiException(
                DefaultExceptionEnum.REQUEST_PARAMETER_INVALID.exception(ex.getMessage(), description));
    }

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
            HttpHeaders headers, HttpStatus status, WebRequest request) {
        //log.warn(ex.getMessage(), ex);
        FieldError fieldError = ex.getBindingResult().getFieldError();
        String description = fieldError != null ? fieldError.getDefaultMessage() : null;
        return handleApiException(
                DefaultExceptionEnum.REQUEST_PARAMETER_INVALID.exception(ex.getMessage(), description));
    }

}
