package eu.dnetlib.data.search.solr;

import eu.dnetlib.domain.EPR;
import eu.dnetlib.functionality.index.cql.CqlTranslator;
import eu.dnetlib.functionality.index.cql.CqlTranslatorImpl;
import eu.dnetlib.functionality.index.cql.TranslatedQuery;
import gr.uoa.di.driver.enabling.resultset.ResultSet;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.log4j.Logger;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrServer;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.z3950.zing.cql.CQLParseException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Created by antleb on 2/4/14.
 */
public class SolrResultSet implements ResultSet<String> {

    private Logger logger = Logger.getLogger(getClass());

    private EPR epr = null;
    private CloudSolrServer solrClient = null;

    private NamedList<String> queryOpts = new NamedList<String>();
    int size = -1;


    public SolrResultSet(EPR epr, CloudSolrServer solrClient) throws IOException, CQLParseException {
        this.epr = epr;
        this.solrClient = solrClient;

        CqlTranslator translator = new CqlTranslatorImpl();
        String cqlQuery = epr.getParameter("query");
        //logger.debug("epr query param: " + cqlQuery);
        String[] queryParts = cqlQuery.split("&groupby=");

        //logger.debug("Got query " + cqlQuery);
        //for (int i = 0; i < queryParts.length; i++) {
        //    logger.debug("queryParts [" + i + "] = '" + queryParts[i] +"'");
        //}

        TranslatedQuery translatedQuery = translator.getTranslatedQuery(queryParts[0].replace("query=",""));

        if (epr.getParameter("action").equals("lookup")) {
            queryOpts.add("q", translatedQuery.asLucene());
            queryOpts.add("fl", "__result");

          if (translatedQuery.getOptions() != null && translatedQuery.getOptions().getSort()!= null  ) {
                queryOpts.add("sort", translatedQuery.getOptions().getSort().getField() + " " + translatedQuery.getOptions().getSort().getMode());
          }

        } else if (epr.getParameter("action").equals("browse")) {
            logger.debug("Browse query: " + translatedQuery.asLucene());

            queryOpts.add("q", translatedQuery.asLucene());
            queryOpts.add("facet", "true");
            queryOpts.add("facet.mincount", "1");

            if (queryParts.length > 1) {

                queryOpts.add("facet.threads", queryParts[1].split(",").length + "");

                for (String field:queryParts[1].split(","))
                    queryOpts.add("facet.field", field);
            }
        }


        queryOpts.add("shards.tolerant","true");

        String layout = epr.getParameter("layout");
        String mdformat = epr.getParameter("mdformat");
        String interpretation = epr.getParameter("interpretation");

        solrClient.setDefaultCollection(mdformat + "-" + layout + "-" + interpretation);
    }

    @Override
    public boolean isOpen() {
        return true;
    }

    @Override
    public boolean isAlive() {
        return true;
    }

    @Override
    public void close() {
        //solrClient.shutdown();
    }

    @Override
    public int size() {
        if (size == -1) {
            try {
                size = getSize();
            } catch (SolrServerException sse) {
               logger.error("Fail to get size", sse);
            }
        }

        return size;
    }

    private int getSize() throws SolrServerException {
        //logger.debug("Query opts" + queryOpts);
        QueryResponse rsp = null;

        synchronized (solrClient) {
            rsp = solrClient.query(SolrParams.toSolrParams(queryOpts));
        }

        //logger.debug(queryOpts);

        if (epr.getParameter("action").equals("lookup")) {
            return (int) rsp.getResults().getNumFound();
        } else if (epr.getParameter("action").equals("browse")) {
            int max = -12;

            for (FacetField field:rsp.getFacetFields()) {
                if (field.getValueCount() > max)
                    max = field.getValueCount();
            }

            return max;
        }

        return 0;
    }

    @Override
    public List<String> getElements(int from, int to) {
        return get(from, to);
    }

    @Override
    public List<String> get(int from, int to) {

        logger.debug("Getting records from " + from + "  to " + to);

        if ("lookup".equals(epr.getParameter("action")))

            return getDocumentResults(from, to);
        else if ("browse".equals(epr.getParameter("action"))) {

            return getBrowseResults(from, to);
        }

        return null;
    }

    List<FacetField> facetFields = null;

    private List<String> getBrowseResults(int from, int to) {
        List<String> res = new ArrayList<String>();


        if (facetFields == null) {
            try {
                QueryResponse rsp = null;

                synchronized (solrClient) {
                    rsp = solrClient.query(SolrParams.toSolrParams(queryOpts));
                }

                facetFields = rsp.getFacetFields();
            } catch (SolrServerException e) {
                e.printStackTrace();
            }


            for (int i = from - 1; i < to; i++) {
                StringBuilder sb = new StringBuilder();

                sb.append("<row>");

                for (FacetField field:facetFields) {
                    if (field.getValueCount() > i) {
                        sb.append("<groupresult field=\"").append(field.getName()).append("\">");
                        sb.append("<count>").append(field.getValues().get(i).getCount()).append("</count>");
                        sb.append("<value>").append(StringEscapeUtils.escapeXml(field.getValues().get(i).getName())).append("</value>");
                        sb.append("</groupresult>");
                    }
                }

                sb.append("</row>");

            //    logger.debug("row: " + sb.toString());

                res.add(sb.toString());
            }
        }

        return res;
    }

    private List<String> getDocumentResults(int from, int to) {
        try {
            QueryResponse rsp = null;
            NamedList<String> extraOpts = new NamedList<String>();

            extraOpts.add("start", (from - 1) + "");
            extraOpts.add("rows", (to - from) + 1 + "");
            extraOpts.addAll(queryOpts);

            synchronized (solrClient) {
                rsp = solrClient.query(SolrParams.toSolrParams(extraOpts));
            }

            SolrDocumentList docs = rsp.getResults();

            logger.debug("time: " + rsp.getElapsedTime());
            logger.debug("found: " + docs.getNumFound());

            List<String> res = new ArrayList<String>();

            for (int i = 0; i < (to - from) + 1; i++) {
                String result = ((ArrayList<String>) docs.get(i).get("__result")).get(0);

                res.add(result);
            }

            return res;
        } catch (SolrServerException e) {
            e.printStackTrace();
        }

        return Collections.EMPTY_LIST;
    }

    public static void main(String[] args) throws IOException, CQLParseException, SolrServerException {
        CloudSolrServer solrClient = new CloudSolrServer("beta.solr.openaire.eu:9983");
        NamedList<String> queryOpts = new NamedList<String>();

        //queryOpts.put("q", new CqlTranslatorImpl().getTranslatedQuery("oaftype exact result").asLucene());
       // queryOpts.add("facet", "true");
        TranslatedQuery translatedQuery = new CqlTranslatorImpl().getTranslatedQuery("oaftype=result sortBy resultdateofacceptance/sort.descending");

        queryOpts.add("q", translatedQuery.asLucene());
//        queryOpts.put("fq", new CqlTranslatorImpl().getTranslatedQuery("").asLucene());
       // queryOpts.add("facet.field", "contextid");
       //  queryOpts.add("facet.field", "contextname");
       //  queryOpts.add("facet.mincount", "1");
       //  queryOpts.add("facet.threads", "10");
        System.out.println(translatedQuery.getOptions().getSort().getMode());
        System.out.println(translatedQuery.getOptions().getSort().getField());

        queryOpts.add("sort", translatedQuery.getOptions().getSort().getField() + " " + translatedQuery.getOptions().getSort().getMode() );

        solrClient.setDefaultCollection("DMF-index-openaire");

        QueryResponse resp = null;
        synchronized (solrClient) {
            resp = solrClient.query(SolrParams.toSolrParams(queryOpts));
        }
        System.out.println("time: " + resp.getElapsedTime());
        System.out.println("time: " + resp.getResults());

        System.out.println(resp.getFacetField("contextname").getValueCount());

        for (FacetField.Count count:resp.getFacetField("contextname").getValues())
            System.out.println(count.getName() + " : " +  count.getCount());


        int max = -12;

        for (FacetField field:resp.getFacetFields()) {
            if (field.getValueCount() > max)
                max = field.getValueCount();

        }

        System.out.println("max: " + max);

    }

    @Override
    public EPR getEpr() {
        return epr;
    }
}