package com.hepl.tunefortwo.config.exceptions;

import java.util.HashMap;
import java.util.Map;

import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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.server.ResponseStatusException;

import com.hepl.tunefortwo.config.i18n.Translator;
import com.hepl.tunefortwo.dto.GenericResponse;

import lombok.extern.slf4j.Slf4j;

@ControllerAdvice
@Slf4j
public class ErrorHandler {

	private final Translator translator;

	public ErrorHandler(Translator translator) {
		this.translator = translator;
	}

	@ExceptionHandler
	public ResponseEntity<GenericResponse> handleException(ResponseStatusException exc) {
		GenericResponse error = new GenericResponse(false);
		error.setMessage(translator.toLocale(exc.getReason()));
		error.setErrorType("OPERATIONAL");
		log.error("Operational Exception occured - {}", error.getTimestamp(), exc);

		return new ResponseEntity<>(error, exc.getStatusCode());
	}

	@ExceptionHandler
	public ResponseEntity<GenericResponse> handleException(Exception exc) {
		GenericResponse error = new GenericResponse(false);
		error.setMessage(exc.getLocalizedMessage());
		error.setErrorType("FATAL");
		log.error("Fatal Exception occured - {}", error.getTimestamp(), exc);

		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}

	@ExceptionHandler
	public ResponseEntity<GenericResponse> handleValidationExceptions(MethodArgumentNotValidException exc) {
		Map<String, String> errors = new HashMap<>();
		exc.getBindingResult().getAllErrors().forEach(error -> {
			String fieldName = ((FieldError) error).getField();
			String errorMessage = error.getDefaultMessage();
			errors.put(fieldName, errorMessage);
		});
		GenericResponse error = new GenericResponse(false);
		error.setMessage(translator.toLocale("error.validationError"));
		error.setErrorType("OPERATIONAL");
		error.setErrors(errors);
		log.error("Validation error - {}", error.getTimestamp(), exc);

		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}

	@ExceptionHandler
	public ResponseEntity<GenericResponse> handleException(DuplicateKeyException exc) {
		GenericResponse error = new GenericResponse(false);
		error.setMessage(translator.toLocale("error.valueExists"));
		error.setErrorType("OPERATIONAL");
		log.error("Operational Exception occured - {}", error.getTimestamp(), exc);

		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}

	@ExceptionHandler
	public ResponseEntity<GenericResponse> handleFieldErrorExceptions(FieldException exc) {
		Map<String, String> errors = new HashMap<>();

		exc.getErrors().forEach((k, v) -> {
			errors.put(k, translator.toLocale(v));
		});

		GenericResponse error = new GenericResponse(false);
		error.setMessage(translator.toLocale("error.valueExists"));
		error.setErrorType("OPERATIONAL");
		error.setErrors(errors);
		log.error("Validation error - {}", error.getTimestamp(), exc);

		return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
	}
}
