package eu.dnetlib.clients.dsManager;

import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import com.google.common.collect.ImmutableMap;

import eu.dnetlib.clients.BaseServiceClient;
import eu.dnetlib.conf.DnetGenericApplicationProperties;
import eu.dnetlib.enabling.annotations.DnetServiceClient;
import eu.dnetlib.enabling.annotations.DnetServiceType;

@Component
@Scope("prototype")
@DnetServiceClient(DnetServiceType.dsManager)
public class DsManagerClient extends BaseServiceClient {

	@Autowired
	private DnetGenericApplicationProperties props;

	public List<DatasourcePoint> getRepositoryMap() {
		return Arrays.asList((new RestTemplate()).getForObject(props.getDatasourceManagerUrl() + "/map", DatasourcePoint[].class));
	}

	public List<SimpleDatasourceDesc> simpleListDatasourcesByType(final String type) {
		return Arrays.asList((new RestTemplate()).getForObject(props.getDatasourceManagerUrl() + "/ds/" + type.trim(), SimpleDatasourceDesc[].class));
	}

	public String addDatasource(final DatasourceDesc ds) {
		return (new RestTemplate()).postForObject(props.getDatasourceManagerUrl() + "/ds", ds, String.class);
	}

	public void deleteDatasource(final String dsId) {
		(new RestTemplate()).delete(props.getDatasourceManagerUrl() + "/ds?dsId=" + dsId.trim());
	}

	public DatasourceDesc getDatasource(final String dsId) {
		return (new RestTemplate()).getForObject(props.getDatasourceManagerUrl() + "/ds?dsId=" + dsId.trim(), DatasourceDesc.class);
	}

	public List<DatasourceDesc> listDatasources(final String compliance, final String contentDescription, final String collectedFrom) {
		final String url = props.getDatasourceManagerUrl() + "search/ds";

		final Map<String, String> params = new HashMap<>();
		if (StringUtils.isNotBlank(compliance)) {
			params.put("compliance", compliance);
		}
		if (StringUtils.isNotBlank(contentDescription)) {
			params.put("contentDescription", contentDescription);
		}
		if (StringUtils.isNotBlank(collectedFrom)) {
			params.put("collectedFrom", collectedFrom);
		}

		return Arrays.asList((new RestTemplate()).getForObject(url, DatasourceDesc[].class, params));
	}

	public void updateLevelOfCompliance(final String dsId, final String ifaceId, final String level, final boolean override) {
		(new RestTemplate()).getForObject(props.getDatasourceManagerUrl() + "/api/compliance?dsId={dsId}&ifaceId={ifaceId}&level={level}&override={override}",
				Object.class,
				ImmutableMap.of("dsId", dsId, "ifaceId", ifaceId, "level", level, "override", override));
	}

	public void resetLevelOfCompliance(final String dsId, final String ifaceId) {
		(new RestTemplate()).getForObject(props.getDatasourceManagerUrl() + "/api/compliance?dsId={dsId}&ifaceId={ifaceId}&override=true",
				Object.class,
				ImmutableMap.of("dsId", dsId, "ifaceId", ifaceId));
	}

	public void updateBaseUrl(final String dsId, final String ifaceId, final String baseUrl) {
		(new RestTemplate()).getForObject(
				props.getDatasourceManagerUrl() + "/api/baseUrl?dsId={dsId}&ifaceId={ifaceId}&baseUrl={baseUrl}",
				Object.class,
				ImmutableMap.of("dsId", dsId, "ifaceId", ifaceId, "baseUrl", baseUrl));
	}

	public void updateActivationStatus(final String dsId, final String ifaceId, final boolean active) {
		(new RestTemplate()).getForObject(
				props.getDatasourceManagerUrl() + "/api/activation?dsId={dsId}&ifaceId={ifaceId}&active={active}",
				Object.class,
				ImmutableMap.of("dsId", dsId, "ifaceId", ifaceId, "active", active));
	}

	public void updateContentDescription(final String dsId, final String ifaceId, final String desc) {
		(new RestTemplate()).getForObject(
				props.getDatasourceManagerUrl() + "/api/contentDescr?dsId={dsId}&ifaceId={ifaceId}&desc={desc}",
				Object.class,
				ImmutableMap.of("dsId", dsId, "ifaceId", ifaceId, "desc", desc));
	}

	public void updateExtraField(final String dsId, final String ifaceId, final String field, final String value, final boolean preserveOriginal) {
		(new RestTemplate()).getForObject(
				props.getDatasourceManagerUrl() + "/api/extraField/{field}?dsId={dsId}&ifaceId={ifaceId}&value={value}&preserveOriginal={preserveOriginal}",
				Object.class,
				ImmutableMap.of("field", field, "dsId", dsId, "ifaceId", ifaceId, "value", value, "preserveOriginal", preserveOriginal));
	}

	public void deleteExtraField(final String dsId, final String ifaceId, final String field) {
		(new RestTemplate()).delete(
				props.getDatasourceManagerUrl() + "/api/extraField/{field}?dsId={dsId}&ifaceId={ifaceId}",
				ImmutableMap.of("field", field, "dsId", dsId, "ifaceId", ifaceId));
	}

	public void updateAccessParam(final String dsId, final String ifaceId, final String field, final String value, final boolean preserveOriginal) {
		(new RestTemplate()).getForObject(
				props.getDatasourceManagerUrl() + "/api/accessParam/{field}?dsId={dsId}&ifaceId={ifaceId}&value={value}&preserveOriginal={preserveOriginal}",
				Object.class,
				ImmutableMap.of("field", field, "dsId", dsId, "ifaceId", ifaceId, "value", value, "preserveOriginal", preserveOriginal));
	}

	public void deleteAccessParam(final String dsId, final String ifaceId, final String field) {
		(new RestTemplate()).delete(
				props.getDatasourceManagerUrl() + "/api/accessParam/{field}?dsId={dsId}&ifaceId={ifaceId}",
				ImmutableMap.of("field", field, "dsId", dsId, "ifaceId", ifaceId));
	}

	public void addInterface(final String dsId, final IfaceDesc iface) {
		final String url = props.getDatasourceManagerUrl() + "/api?dsId=" + dsId.trim();
		(new RestTemplate()).postForObject(url, iface, Object.class);
	}

	public void deleteInterface(final String dsId, final String ifaceId) {
		(new RestTemplate()).delete(
				props.getDatasourceManagerUrl() + "/api?dsId={dsId}&ifaceId={ifaceId}",
				ImmutableMap.of("dsId", dsId, "ifaceId", ifaceId));
	}

	public Date findNextScheduledExecution(final String dsId, final String ifaceId) {
		return (new RestTemplate()).getForObject(
				props.getDatasourceManagerUrl() + "/api/nextScheduledExecution?dsId={dsId}&ifaceId={ifaceId}",
				Date.class,
				ImmutableMap.of("dsId", dsId, "ifaceId", ifaceId));
	}

	public void bulkUpdateApiExtraFields(final String dsId, final String ifaceId, final Map<String, String> fields) {
		(new RestTemplate()).postForObject(
				props.getDatasourceManagerUrl() + "/api/extraFields?dsId={dsId}&ifaceId={ifaceId}", fields,
				Object.class,
				ImmutableMap.of("dsId", dsId, "ifaceId", ifaceId));
	}

	public void bulkUpdateApiAccessParams(final String dsId, final String ifaceId, final Map<String, String> accessParams) {
		(new RestTemplate()).postForObject(
				props.getDatasourceManagerUrl() + "/api/accessParams?dsId={dsId}&ifaceId={ifaceId}", accessParams,
				Object.class,
				ImmutableMap.of("dsId", dsId, "ifaceId", ifaceId));
	}

	@Cacheable(cacheNames = "apis_browsable_fields", key = "#root.methodName")
	public List<BrowsableField> listBrowsableFields() {
		return Arrays.asList((new RestTemplate()).getForObject(props.getDatasourceManagerUrl() + "/browse/api/fields", BrowsableField[].class));
	}

	public List<BrowseTerm> browseField(final String field) {
		return Arrays.asList((new RestTemplate()).getForObject(props.getDatasourceManagerUrl() + "/browse/api/" + field.trim(), BrowseTerm[].class));
	}

	@Cacheable("apis_search")
	public List<SearchInterfacesEntry> searchInterface(final String field, final String value) {
		return Arrays.asList((new RestTemplate()).getForObject(
				props.getDatasourceManagerUrl() + "/search/api/{field}?value={value}",
				SearchInterfacesEntry[].class,
				ImmutableMap.of("field", field, "value", value)));
	}

	@CacheEvict(value = "apis_search", allEntries = true, beforeInvocation = true)
	public void emptyCache() {}

}
