package eu.dnetlib.dli.resolver;

import com.google.common.collect.Lists;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import eu.dnetlib.dli.resolver.model.CompletionStatus;
import eu.dnetlib.dli.resolver.model.DLIObjectProvenance;
import eu.dnetlib.dli.resolver.model.DLIResolvedObject;
import eu.dnetlib.enabling.tools.DnetStreamSupport;
import eu.dnetlib.pid.resolver.AbstractPIDResolver;
import eu.dnetlib.pid.resolver.model.ObjectType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

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

/**
 * The Class DataciteDOIResolver.
 */

public class DataciteResolver extends AbstractPIDResolver {

    public static final String DATACITE_NS_PREFIX = "datacite____";

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

    /**
     * The Constant baseURL.
     */
    private final static String baseURL = "https://api.datacite.org/works/";

    private static String getStringValue(final JsonObject root, final String key, final String defaultValue) {

        if (root.has(key) && !root.get(key).isJsonNull()) {
            return root.get(key).getAsString();
        }
        return defaultValue;
    }

    public static DLIResolvedObject parseResponse(final String response) {
        if (response == null) return null;
        final JsonElement jElement = new JsonParser().parse(response);

        final JsonObject jobject = jElement.getAsJsonObject();
        if (jobject.has("data")) {
            DLIResolvedObject responseObj = new DLIResolvedObject();
            final JsonObject root = jobject.getAsJsonObject("data").getAsJsonObject("attributes");


            final String doi = root.get("doi").getAsString();
            responseObj.setPid(doi);
            responseObj.setPidType("doi");
            responseObj.setType(ObjectType.dataset);

            final List<String> authors = Lists.newArrayList();

            // ADDING TITLES

            if (root.has("title") && root.get("title").isJsonArray()) {
                responseObj.setTitles(DnetStreamSupport.generateStreamFromIterator(root.get("title").getAsJsonArray().iterator())
                        .map(JsonElement::toString)
                        .collect(Collectors.toList()));
            } else if (root.has("title") && !root.get("title").isJsonNull()) {
                responseObj.setTitles(Collections.singletonList(root.get("title").getAsString()));
            }

            //ADDING DESCRIPTION
            if (root.has("description") && !root.get("description").isJsonNull())
                responseObj.setDescription(root.get("description").getAsString());

            // ADDING AUTHORS
            if (root.has("author") && root.get("author").isJsonArray()) {

                DnetStreamSupport.generateStreamFromIterator(root.getAsJsonArray("author").iterator())
                        .map(JsonElement::getAsJsonObject)
                        .forEach(it -> {
                            if (it.has("literal")) {
                                authors.add(it.get("literal").getAsString());
                            } else {
                                authors.add(getStringValue(it, "given", " ") + " " + getStringValue(it, "family", " "));
                            }
                        });
            }
            responseObj.setAuthors(authors);

            final String date = getStringValue(root, "registered", "");
            responseObj.setDate(date);

            final DLIObjectProvenance provenance = new DLIObjectProvenance();
            DLIPIDResolver.setDatasourceProvenance(provenance, DATACITE_NS_PREFIX);


            responseObj.setDatasourceProvenance(Lists.newArrayList(provenance));
            responseObj.setCompletionStatus(CompletionStatus.complete.toString());
            return responseObj;
        }
        return null;


    }


    @Override
    protected boolean canResolvePid(final String pidType) {
        return (pidType != null) && ("doi".equals(pidType.toLowerCase().trim()) || "handle".equals(pidType.toLowerCase().trim()));

    }

    @Override
    public DLIResolvedObject resolve(final String pid, final String pidType) {
        try {
            final String response = requestURL(baseURL + pid.replace(" ", "%20"));
            return parseResponse(response);
        } catch (Throwable e) {
            log.error("Error on getting item from url " + baseURL + pid.replace(" ", "%20"));
        }
        return null;
    }
}
