package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.exception;

import lombok.extern.slf4j.Slf4j;
import org.mte.numecoeval.referentiel.domain.exception.NotFoundException;
import org.mte.numecoeval.referentiel.domain.exception.ReferentielException;
import org.mte.numecoeval.referentiel.domain.exception.ReferentielRuntimeException;
import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;

import java.time.LocalDateTime;

import static org.springframework.http.HttpStatus.*;

@Slf4j
@RestControllerAdvice
public class ReferentelExceptionHandler {

    /**
     * writer error message
     *
     * @param ex     excepetion
     * @param status le statut http
     * @return l'objet erreur
     */
    private static ErrorResponseDTO writeErrorResponse(Exception ex, HttpStatus status) {
        return ErrorResponseDTO.builder()
                .status(status)
                .code(status.value())
                .timestamp(LocalDateTime.now())
                .message(ex.getLocalizedMessage()).build();
    }

    @ExceptionHandler(value = {NotFoundException.class})
    public ErrorResponseDTO notFoundException(Exception ex, WebRequest request) {
        return writeErrorResponse(ex, NOT_FOUND);
    }

    @ExceptionHandler(value = {ReferentielException.class})
    @ResponseStatus(value = NOT_FOUND)
    public ErrorResponseDTO referentielException(Exception ex, WebRequest request) {
        return writeErrorResponse(ex, NOT_FOUND);
    }

    @ExceptionHandler(value = {ReferentielRuntimeException.class})
    @ResponseStatus(value = INTERNAL_SERVER_ERROR)
    public ErrorResponseDTO referentielPersistenceException(Exception ex, WebRequest request) {
        return writeErrorResponse(ex, INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler(value = {DataIntegrityViolationException.class})
    @ResponseStatus(BAD_REQUEST)
    public ErrorResponseDTO dataIntegrityViolationException(DataIntegrityViolationException ex, WebRequest request) {
        log.debug("DataIntegrityViolationException lors d'un traitement sur l'URI {}", request.getContextPath(), ex);
        return writeErrorResponse(new Exception("Erreur d'intégrité lors de la persistence des données."), BAD_REQUEST);
    }

    @ExceptionHandler(value = {RuntimeException.class})
    @ResponseStatus(value = INTERNAL_SERVER_ERROR)
    public ErrorResponseDTO runtimeException(Exception ex, WebRequest request) {
        log.error("RuntimeException lors d'un traitement sur l'URI {}", request.getContextPath(), ex);
        log.debug("RuntimeException lors d'un traitement sur l'URI {}", request.getContextPath(), ex);
        return writeErrorResponse(new Exception("Erreur interne de traitement lors du traitement de la requête"), INTERNAL_SERVER_ERROR);
    }

    @ExceptionHandler(value = {Exception.class})
    @ResponseStatus(value = INTERNAL_SERVER_ERROR)
    public ErrorResponseDTO exception(Exception ex, WebRequest request) {
        log.error("Exception lors d'un traitement sur l'URI {} : {}", request.getContextPath(), ex.getMessage());
        log.debug("Exception lors d'un traitement sur l'URI {}", request.getContextPath(), ex);
        return writeErrorResponse(new Exception("Erreur interne de traitement lors du traitement de la requête"), INTERNAL_SERVER_ERROR);
    }

}

