package com.codefork.refine.orcid;

import com.codefork.refine.Config;
import com.codefork.refine.SearchQuery;
import com.codefork.refine.SearchQueryFactory;
import com.codefork.refine.ThreadPoolFactory;
import com.codefork.refine.datasource.ConnectionFactory;
import com.codefork.refine.resources.NameType;
import com.codefork.refine.resources.Result;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriUtils;

import java.util.Collections;
import java.util.List;

@Component("orcidsmartnames")
public class OrcidSmartNames extends OrcidBase {

    SmartNamesModeSearchQueryFactory smartNamesModeSearchQueryFactory =
            new SmartNamesModeSearchQueryFactory();

    @Autowired
    public OrcidSmartNames(Config config, CacheManager cacheManager, ThreadPoolFactory threadPoolFactory, ConnectionFactory connectionFactory) {
        super(config, cacheManager, threadPoolFactory, connectionFactory);
    }

    @Override
    public SearchQueryFactory getSearchQueryFactory() {
        return smartNamesModeSearchQueryFactory;
    }

    @Override
    public List<Result> search(SearchQuery query) throws Exception {
        List<Result> results = Collections.emptyList();

        if(query.isOrcidSmartNamesMode()) {
            String name = query.getQuery();
            String[] namePieces = parseName(name);
            if(namePieces != null) {
                results = searchSmartNames(query, namePieces[0], namePieces[1]);
            }
        }
        if(results.isEmpty()) {
            results = searchKeyword(query);
        }
        return results;
    }

    private List<Result> searchSmartNames(SearchQuery query, String givenName, String familyName) throws Exception {
        String q = String.format("given-names:%s AND family-name:%s", givenName, familyName);
        String fields = createSearchFieldsQueryString(query);
        if(fields.length() > 0) {
            q += " " + fields;
        }
        String url = String.format("https://pub.orcid.org/v2.1/search/?rows=%d&q=", query.getLimit()) +
                UriUtils.encodeQueryParam(q, "UTF-8");
        return doSearch(query, url);
    }

    /**
     * Parse name into given name, family name parts. returns null if name is too complicated to be
     * parsed.
     * @param name
     * @return
     */
    public static String[] parseName(String name) {
        int numCommas = name.length() - name.replace(",", "").length();
        if(numCommas == 1) {
            String[] namePieces = name.split(",");
            if(namePieces.length == 2) {
                return new String[]{
                        namePieces[1].trim(),
                        namePieces[0].trim()
                };
            }
        } else {
            String[] namePieces = name.split("\\s+");
            if(namePieces.length == 2) {
                return namePieces;
            }
        }
        return null;
    }

    private static class SmartNamesModeSearchQueryFactory implements SearchQueryFactory {

        @Override
        public SearchQuery createSearchQuery(JsonNode queryStruct) {
            SearchQuery searchQuery = new SearchQuery(queryStruct);
            searchQuery.setOrcidSmartNamesMode(true);
            return searchQuery;
        }

        @Override
        public SearchQuery createSearchQuery(String query, int limit, NameType nameType, String typeStrict) {
            SearchQuery searchQuery = new SearchQuery(query, limit, nameType, typeStrict);
            searchQuery.setOrcidSmartNamesMode(true);
            return searchQuery;
        }
    }

}