package com.iqser.red.service.persistence.v1.internal.api.controller;

import com.iqser.red.commons.spring.ErrorMessage;
import com.iqser.red.service.persistence.management.v1.processor.exception.*;
import io.swagger.v3.oas.annotations.Hidden;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.sql.SQLException;
import java.time.OffsetDateTime;
import java.util.stream.Collectors;

@Slf4j
@RestControllerAdvice
public class InternalControllerAdvice {

    public final String VIOLATES_UNIQUE_CONSTRAINT = "violates unique constraint";
    /* error handling */


    @Hidden
    @ResponseBody
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = NullPointerException.class)
    public ErrorMessage handleContentNotFoundException(NullPointerException e) {

        log.error(e.getMessage(), e);
        return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
    }


    @Hidden
    @ResponseBody
    @ResponseStatus(value = HttpStatus.NOT_FOUND)
    @ExceptionHandler(value = NotFoundException.class)
    public ErrorMessage handleFileNotFoundException(NotFoundException e) {

        return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
    }


    @Hidden
    @ResponseBody
    @ResponseStatus(value = HttpStatus.NOT_FOUND)
    @ExceptionHandler(value = DossierNotFoundException.class)
    public ErrorMessage handleDossierNotFoundException(DossierNotFoundException e) {

        return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
    }


    @Hidden
    @ResponseBody
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = InvalidRulesException.class)
    public ErrorMessage handleInvalidRulesException(InvalidRulesException e) {

        return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
    }


    @Hidden
    @ResponseBody
    @ResponseStatus(value = HttpStatus.CONFLICT)
    @ExceptionHandler(value = ConflictException.class)
    public ErrorMessage handleIConflictException(ConflictException e) {

        return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
    }

    @Hidden
    @ResponseBody
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = BadRequestException.class)
    public ErrorMessage handleIBadRequestException(BadRequestException e) {

        return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
    }


    @Hidden
    @ResponseBody
    @ExceptionHandler(value = SQLException.class)
    public ResponseEntity<ErrorMessage> handleSQLException(SQLException e) {

        if (e.getMessage().contains(VIOLATES_UNIQUE_CONSTRAINT)) {
            int indexFrom = e.getMessage().indexOf(VIOLATES_UNIQUE_CONSTRAINT) + VIOLATES_UNIQUE_CONSTRAINT.length();
            int indexTo = e.getMessage().indexOf("Detail");
            String violation_key = e.getMessage().substring(indexFrom, indexTo);
            return new ResponseEntity<>(new ErrorMessage(OffsetDateTime.now(), "Unique constraint violation: " + violation_key), HttpStatus.CONFLICT);
        } else if (e.getMessage().contains("No suitable driver found")) {
            return new ResponseEntity<>(new ErrorMessage(OffsetDateTime.now(), "JDBC URL is incorrect"), HttpStatus.BAD_REQUEST);
        } else {
            log.error("PLSQL Exception occurred: {}", e.getMessage(), e);
            return new ResponseEntity<>(new ErrorMessage(OffsetDateTime.now(), "SQL Exception" + e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }


    @Hidden
    @ResponseBody
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public ErrorMessage handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {


        var errorList = e.getFieldErrors();
        String errorListAsString = errorList.stream().map(fieldError -> fieldError.getField() + ": " + fieldError.getDefaultMessage()).collect(Collectors.joining(", "));
        return new ErrorMessage(OffsetDateTime.now(), String.format("You have empty/wrong formatted parameters: %s", errorListAsString));
    }

    @Hidden
    @ResponseBody
    @ResponseStatus(value = HttpStatus.UNPROCESSABLE_ENTITY)
    @ExceptionHandler(value = RulesTimeoutDetectedException.class)
    public ErrorMessage handleRulesTimeoutDetectedException(RulesTimeoutDetectedException e) {

        return new ErrorMessage(OffsetDateTime.now(), e.getMessage());
    }

}
