package eu.dnetlib.dli;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;

import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import eu.dnetlib.data.transform.Ontologies;
import eu.dnetlib.data.transform.OntologyLoader;
import eu.dnetlib.enabling.locators.UniqueServiceLocator;
import eu.dnetlib.miscutils.functional.xml.DnetXsltFunctions;
import eu.dnetlib.rmi.enabling.ISLookUpException;
import eu.dnetlib.rmi.enabling.ISLookUpService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;

public class DLIUtils {

	public final static Map<String, Pair<String, String>> datasources = new HashMap<>();
	public static final Map<String, String> resolvedTypes = new HashMap<String, String>() {
		{
			put("pdb", "http://www.rcsb.org/pdb/explore/explore.do?structureId=%s");
			put("ncbi-n", "http://www.ncbi.nlm.nih.gov/gquery/?term=%s");
			put("pmid", "http://www.ncbi.nlm.nih.gov/pubmed/%s");
			put("pmcid", "http://www.ncbi.nlm.nih.gov/pmc/articles/%s");
			put("pubmedid", "http://www.ncbi.nlm.nih.gov/pubmed/%s");
			put("doi", "http://dx.doi.org/%s");
			put("genbank", "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank");
			put("nuccore", "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank");
			put("swiss-prot", "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank");
			put("arrayexpress", "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank");
			put("biomodels", "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank");
			put("bmrb", "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank");
			put("ena", "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank");
			put("genbank", "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank");
			put("geo", "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank");
			put("ensembl", "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank");
			put("mgi", "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank");
			put("bind", "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank");
			put("pride", "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank");
			put("ddbj", "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank");
			put("bioproject", "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank");
			put("embl", "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank");
			put("sra", "http://www.ncbi.nlm.nih.gov/nucest/%s?report=genbank");
		}

	};
    public static Ontologies ontologies;
    private static DLIUtils instance;
	private static BiMap<String, String> relations;
    @Autowired
	private UniqueServiceLocator serviceLocator;

	private static BiMap<String, String> getRelationMap() {

		if (relations == null) {
			relations = HashBiMap.create();
			relations.put("IsCitedBy", "Cites");
			relations.put("IsSupplementTo", "IsSupplementedBy");
			relations.put("IsReferencedBy", "References");
		}
		return relations;
	}

	public static String getNameFromDataSourcePrefix(final String datasourcePrefix) throws ISLookUpException {
		if (datasources.keySet() == null || datasources.keySet().size() == 0) {
			generateDSMap();
		}
		if (!datasources.containsKey(datasourcePrefix))
			return "";
		return datasources.get(datasourcePrefix).getRight();
	}

	public static String getIdFromDataSourcePrefix(final String datasourcePrefix) throws ISLookUpException {
		if (datasources.keySet() == null || datasources.keySet().size() == 0) {
			generateDSMap();
		}
		if (!datasources.containsKey(datasourcePrefix))
			return "";
		return datasources.get(datasourcePrefix).getLeft();
	}

	public static void generateDSMap() throws ISLookUpException {
		if (datasources.keySet() != null && datasources.keySet().size() > 0)
			return;

		final String query = "for $x in collection('/db/DRIVER/RepositoryServiceResources/RepositoryServiceResourceType') "
				+ "return concat($x//FIELD[./key='NamespacePrefix']/value/text(),'@--@',$x//FIELD[./key='DataSourceId']/value/text(),'@--@',$x//ENGLISH_NAME )";
        final ISLookUpService lookupService = instance.getServiceLocator().getService(ISLookUpService.class);
        final List<String> results = lookupService.quickSearchProfile(query);
        datasources.clear();
		if (results != null)
			results.forEach(it -> {
				final String[] splitted = it.split("@--@");
				if (splitted != null && splitted.length == 3) {
					datasources.put(splitted[0], new ImmutablePair<>(splitted[1], splitted[2]));
				}
			});
	}

	public static String fixPID(String input) {
		if (input != null) {
			return input.replace("http://dx.doi.org/", "").replace("http://doi.org/", "");
		}
		return input;
	}

    public static String normalizeRelation(final String relation) {
        if (relation == null || StringUtils.isEmpty(relation)) {
            return null;
        }
        return Character.toLowerCase(relation.charAt(0)) + relation.substring(1);

    }

    public static String getInverse(final String relation) throws Exception {
        if (ontologies == null) {
            ontologies = OntologyLoader.loadOntologiesFromIS();
        }
        final String normalizedRelation = normalizeRelation(relation);


        try {
        	return ontologies.getTerms(normalizedRelation).stream().findFirst().get().getInverseCode();
        } catch (Throwable e) {
            System.out.println("Relation not found = " + normalizedRelation);
            return "related";
        }
    }


	public static String generateIdentifier(final String pid, final String pidtype) {
		if (StringUtils.isBlank(pid) || StringUtils.isBlank(pidtype))
			throw new RuntimeException("Error pid or pidtype cannot be null");
		return DnetXsltFunctions.md5(String.format("%s::%s", pid.trim(), pidtype.toLowerCase().trim()));
	}

    /**
     * This method is used only for test Scope
     *
     * @param mockInstance
     */
    public static void setInstance(final DLIUtils mockInstance) {
        instance = mockInstance;
    }

	@PostConstruct
	public void registerInstance() throws ISLookUpException {
		instance = this;
		//DLIUtils.generateDSMap();
	}

	public UniqueServiceLocator getServiceLocator() {
		return serviceLocator;
	}



	public void setServiceLocator(final UniqueServiceLocator serviceLocator) {
		this.serviceLocator = serviceLocator;
	}
}
