package eu.dnetlib.services.async;

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

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import eu.dnetlib.services.AsyncInvocation;

@Component
public class AsyncClientUtils {

	private static final Log log = LogFactory.getLog(AsyncClientUtils.class);

	private static final Map<String, AsyncClientCallback> activeRemoteCalls = new HashMap<>();

	public Map<String, String> invokeRemoteMethod(final String remoteBaseUrl,
			final String remoteMethod,
			final String localBaseUrl,
			final Object o,
			final AsyncClientCallback callback) {

		final String url = remoteBaseUrl + "/async/method/" + remoteMethod + ((StringUtils.isNotBlank(localBaseUrl)) ? "?caller=" + localBaseUrl : "");

		final AsyncInvocation async = (new RestTemplate()).postForObject(url, o, AsyncInvocation.class);
		if (callback != null) {
			activeRemoteCalls.put(async.getId(), callback);
		}

		log.info("async method invoked, url: " + url + ", id: " + async.getId());

		return async.getInfo();
	}

	public boolean processResponse(final String id, final AsyncResponse response) {

		log.info("Received async response, id: " + id);

		if (activeRemoteCalls.containsKey(id)) {
			final AsyncClientCallback callback = activeRemoteCalls.get(id);

			callback.updateLastInvocation();

			switch (response.getStatus()) {
			case ASSIGNED:
			case RUNNING:
				callback.onGoing(response);
				break;
			case SUCCESS:
				callback.onDone(response);
				activeRemoteCalls.remove(id);
				break;
			case FAILED:
				callback.onFailed(response);
				activeRemoteCalls.remove(id);
				break;
			default:
				log.warn("Status " + response.getStatus() + " not managed");
				break;
			}
			return true;
		} else {
			log.warn("Unexpected message: " + id);
			return false;
		}
	}

	public void clearRemoteCalls() {
		activeRemoteCalls.clear();
	}

	public void deleteRemoteCall(final String id) {
		activeRemoteCalls.remove(id);
	}

	public static Map<String, AsyncClientCallback> getActiveremotecalls() {
		return activeRemoteCalls;
	}

}
