package it.micegroup.gestioneferie.libs.exception;

import it.micegroup.gestioneferie.libs.response.BaseResponse;
import it.micegroup.gestioneferie.libs.utilities.MessageSourceSettings;
import it.micegroup.gestioneferie.libs.utilities.MessageUtil;

import it.micegroup.voila2runtime.exception.*;
import it.micegroup.voila2runtime.response.Messages;
import it.micegroup.voila2runtime.response.Message.MessageLevelType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import java.util.ArrayList;


public abstract class BaseExceptionHandler extends ResponseEntityExceptionHandler {

    private static final Logger LOGGER = LoggerFactory.getLogger(BaseExceptionHandler.class);

    @Autowired
    private MessageSource messageSource;
    
    @ExceptionHandler({NotFoundException.class})
    public ResponseEntity<BaseResponse<ErrorDetails>> exceptionHandler(RuntimeException exception, WebRequest request) {
        return notFoundExceptionHandler((NotFoundException) exception, request);
    }

    @ExceptionHandler({BusinessException.class})
    public ResponseEntity<Object> businessExceptionHandler(BusinessException exception, WebRequest request) {
        logException(exception);
        ErrorDetails errorDetails = new ErrorDetails(exception, request);
        return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
    }

    protected ResponseEntity<BaseResponse<ErrorDetails>> notFoundExceptionHandler(NotFoundException exception, WebRequest request) {
        exception.setMessage( messageSource.getMessage("not.found", new Object[] {exception.getClassType().getSimpleName()}, exception.getLocale()));
        //ErrorDetails errorDetails = ;
        
        BaseResponse<ErrorDetails> baseError = new BaseResponse<>();
        baseError.setErrorDetails(new ErrorDetails(exception, request));
        
        Messages msgs = new Messages();
        msgs.addMessage(MessageLevelType.ERROR, exception.getMessage());

        baseError.setMessages(msgs);
        return new ResponseEntity<BaseResponse<ErrorDetails>>(baseError, HttpStatus.NOT_FOUND);
    }

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        MessageUtil.setMessageSource(messageSource);
        MessageUtil.setMessages(new ArrayList<>());
        ErrorDetails errorDetails = new ErrorDetails(ex, request);
        for (ObjectError oe : ex.getAllErrors()) {
            MessageUtil.addErrorMessage(oe.getCode(), oe.getArguments());
        }
//        errorDetails.getMessages().addAll(MessageUtil.getMessages());
        return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
    }

    @Override
    protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        logException(ex);
        ErrorDetails errorDetails = new ErrorDetails(ex, request);
        return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorDetails> globalExceptionHandler(Exception ex, WebRequest request) {
        logException(ex);
        ErrorDetails errorDetails = new ErrorDetails(ex, request);
        return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    protected void logException(Exception e) {
        LOGGER.error("Generic error", e);
    }


}
