package ru.ulstu.core.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;
import ru.ulstu.core.error.EntityIdIsNullException;
import ru.ulstu.core.model.ErrorConstants;
import ru.ulstu.core.model.response.Response;
import ru.ulstu.core.model.response.ResponseExtended;
import ru.ulstu.user.error.*;
import ru.ulstu.user.error.*;

import java.util.Set;
import java.util.stream.Collectors;

@RestController
@ControllerAdvice
public class AdviceController {
    private final Logger log = LoggerFactory.getLogger(AdviceController.class);

    private Response<Void> handleException(ErrorConstants error) {
        log.warn(error.toString());
        return new Response<>(error);
    }

    private <E> ResponseExtended<E> handleException(ErrorConstants error, E errorData) {
        log.warn(error.toString());
        return new ResponseExtended<>(error, errorData);
    }

    @ExceptionHandler(EntityIdIsNullException.class)
    public Response<Void> handleEntityIdIsNullException(Throwable e) {
        return handleException(ErrorConstants.ID_IS_NULL);
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseExtended<Set<String>> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        final Set<String> errors = e.getBindingResult().getAllErrors().stream()
                .filter(error -> error instanceof FieldError)
                .map(error -> ((FieldError) error).getField())
                .collect(Collectors.toSet());
        return handleException(ErrorConstants.VALIDATION_ERROR, errors);
    }

    @ExceptionHandler(UserIdExistsException.class)
    public Response<Void> handleUserIdExistsException(Throwable e) {
        return handleException(ErrorConstants.USER_ID_EXISTS);
    }

    @ExceptionHandler(UserActivationError.class)
    public ResponseExtended<String> handleUserActivationError(Throwable e) {
        return handleException(ErrorConstants.USER_ACTIVATION_ERROR, e.getMessage());
    }

    @ExceptionHandler(UserLoginExistsException.class)
    public ResponseExtended<String> handleUserLoginExistsException(Throwable e) {
        return handleException(ErrorConstants.USER_LOGIN_EXISTS, e.getMessage());
    }

    @ExceptionHandler(UserEmailExistsException.class)
    public ResponseExtended<String> handleUserEmailExistsException(Throwable e) {
        return handleException(ErrorConstants.USER_EMAIL_EXISTS, e.getMessage());
    }

    @ExceptionHandler(UserPasswordsNotValidOrNotMatchException.class)
    public Response<Void> handleUserPasswordsNotValidOrNotMatchException(Throwable e) {
        return handleException(ErrorConstants.USER_PASSWORDS_NOT_VALID_OR_NOT_MATCH);
    }

    @ExceptionHandler(UserNotFoundException.class)
    public ResponseExtended<String> handleUserNotFoundException(Throwable e) {
        return handleException(ErrorConstants.USER_NOT_FOUND, e.getMessage());
    }

    @ExceptionHandler(UserNotActivatedException.class)
    public Response<Void> handleUserNotActivatedException(Throwable e) {
        return handleException(ErrorConstants.USER_NOT_ACTIVATED);
    }

    @ExceptionHandler(UserResetKeyError.class)
    public ResponseExtended<String> handleUserResetKeyError(Throwable e) {
        return handleException(ErrorConstants.USER_RESET_ERROR, e.getMessage());
    }

    @ExceptionHandler(UserIsUndeadException.class)
    public ResponseExtended<String> handleUserIsUndeadException(Throwable e) {
        return handleException(ErrorConstants.USER_UNDEAD_ERROR, e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public ResponseExtended<String> handleUnknownException(Throwable e) {
        e.printStackTrace();
        return handleException(ErrorConstants.UNKNOWN, e.getMessage());
    }
}
