package eu.dnetlib.openaire.common;

import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpStatus;
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 com.fasterxml.jackson.annotation.JsonAutoDetect;

import eu.dnetlib.openaire.exporter.exceptions.DsmApiException;
import eu.dnetlib.openaire.exporter.model.dsm.Response;

/**
 * Created by claudio on 18/07/2017.
 */
public abstract class AbstractExporterController {

	private static final Log log = LogFactory.getLog(AbstractExporterController.class); // NOPMD by marko on 11/24/08 5:02 PM

	@ResponseBody
	@ExceptionHandler({
		DsmApiException.class
	})
	@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
	public ErrorMessage handleDSMException(final Exception e) {
		return _handleError(e);
	}

	@ResponseBody
	@ExceptionHandler(MethodArgumentNotValidException.class)
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	public List<ErrorMessage> processValidationError(final MethodArgumentNotValidException e) {
		return e.getBindingResult()
			.getFieldErrors()
			.stream()
			.map(fe -> new ErrorMessage(
				String.format("field '%s'", fe.getField()),
				String.format("rejected value '%s'", fe.getRejectedValue()),
				fe.getDefaultMessage()))
			.collect(Collectors.toList());
	}

	private ErrorMessage _handleError(final Exception e) {
		log.error(e);
		if (StringUtils.containsIgnoreCase(ExceptionUtils.getRootCauseMessage(e), "Broken pipe")) {
			return null;        // socket is closed, cannot return any response
		} else {
			return new ErrorMessage(e);
		}
	}

	// HELPERS
	protected <T extends Response> T prepareResponse(final int page, final int size, final StopWatch stopWatch, final T rsp) {
		rsp.getHeader()
			.setTime(stopWatch.getTime())
			.setPage(page)
			.setSize(size);
		return rsp;
	}

	@JsonAutoDetect
	public class ErrorMessage {

		private final String message;
		private final String details;
		private final String stacktrace;

		public ErrorMessage(final Exception e) {
			this(e.getMessage(), "", ExceptionUtils.getStackTrace(e));
		}

		public ErrorMessage(final String message, final String details, final String stacktrace) {
			this.message = message;
			this.details = details;
			this.stacktrace = stacktrace;
		}

		public String getMessage() {
			return this.message;
		}

		public String getStacktrace() {
			return this.stacktrace;
		}

		public String getDetails() {
			return details;
		}
	}

}
