package uk.ac.ebi.quickgo.client.controller;

import uk.ac.ebi.quickgo.client.model.ontology.OntologyRequest;
import uk.ac.ebi.quickgo.client.model.ontology.OntologyTerm;
import uk.ac.ebi.quickgo.client.service.search.SearchServiceConfig;
import uk.ac.ebi.quickgo.rest.ParameterBindingException;
import uk.ac.ebi.quickgo.rest.search.DefaultSearchQueryTemplate;
import uk.ac.ebi.quickgo.rest.search.SearchService;
import uk.ac.ebi.quickgo.rest.search.SearchableField;
import uk.ac.ebi.quickgo.rest.search.request.converter.ConvertedFilter;
import uk.ac.ebi.quickgo.rest.search.request.converter.FilterConverterFactory;
import uk.ac.ebi.quickgo.rest.search.results.QueryResult;

import com.google.common.base.Preconditions;
import io.swagger.annotations.ApiOperation;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import static uk.ac.ebi.quickgo.rest.search.SearchDispatcher.search;

/**
 * Search controller responsible for providing consistent search functionality over selected services.
 *
 * Created 13/01/16
 * @author Edd
 */
@RestController
@RequestMapping(value = "/internal/search")
public class SearchController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final SearchService<OntologyTerm> ontologySearchService;
    private final DefaultSearchQueryTemplate requestTemplate;
    private final FilterConverterFactory converterFactory;

    @Autowired
    public SearchController(
            SearchService<OntologyTerm> ontologySearchService,
            SearchableField ontologySearchableField,
            SearchServiceConfig.OntologyCompositeRetrievalConfig ontologyRetrievalConfig,
            FilterConverterFactory converterFactory) {

        Preconditions.checkArgument(ontologySearchService != null, "Ontology search service cannot be null");
        Preconditions.checkArgument(ontologySearchableField != null, "Ontology searchable field cannot be null");
        Preconditions.checkArgument(ontologyRetrievalConfig != null, "Ontology retrieval configuration cannot be null");
        Preconditions.checkArgument(converterFactory != null, "Ontology converter factory cannot be null");

        this.ontologySearchService = ontologySearchService;
        this.converterFactory = converterFactory;

        this.requestTemplate = new DefaultSearchQueryTemplate(ontologySearchableField);
        this.requestTemplate.setReturnedFields(ontologyRetrievalConfig.getSearchReturnedFields());
        this.requestTemplate.setHighlighting(ontologyRetrievalConfig.repo2DomainFieldMap().keySet(),
                ontologyRetrievalConfig.getHighlightStartDelim(),
                ontologyRetrievalConfig.getHighlightEndDelim());
    }

    /**
     * Perform a custom client search
     *
     * @param request an object that wraps all possible configurations for this endpoint
     * @return the search results
     */
    @ApiOperation(value = "Searches a user defined query, e.g., query=apopto",
            notes = "Response fields include: id and name (and aspect for GO terms)")
    @RequestMapping(value = "/ontology", method = {RequestMethod.GET}, produces = {MediaType.APPLICATION_JSON_VALUE})
    public ResponseEntity<QueryResult<OntologyTerm>> ontologySearch(@Valid @ModelAttribute OntologyRequest request,
            BindingResult bindingResult) {

        if (bindingResult.hasErrors()) {
            throw new ParameterBindingException(bindingResult);
        }

        DefaultSearchQueryTemplate.Builder requestBuilder = requestTemplate.newBuilder()
                .setQuery(request.createQuery())
                .addFacets(request.getFacet() == null ? null : Arrays.asList(request.getFacet()))
                .addFilters(request.createFilterRequests().stream()
                        .map(converterFactory::convert)
                        .filter(Objects::nonNull)
                        .map(ConvertedFilter::getConvertedValue)
                        .collect(Collectors.toList()))
                .useHighlighting(request.isHighlighting())
                .setPage(request.getPage())
                .setPageSize(request.getLimit());

        return search(requestBuilder.build(), ontologySearchService);
    }
}
@@ -460,16 +460,133 @@
 eField;%0A
+import uk.ac.ebi.quickgo.rest.search.query.QuickGOQuery;%0Aimport uk.ac.ebi.quickgo.rest.search.request.FilterRequest;%0A
 import u
@@ -901,16 +901,45 @@
 Arrays;%0A
+import java.util.Collection;%0A
 import j
@@ -4426,269 +4426,67 @@
 ers(
-request.createFilterRequests().stream()%0A                        .map(converterFactory::convert)%0A                        .filter(Objects::nonNull)%0A                        .map(Conver
+convertFilterRequestsToQueries(request.crea
 te
-d
 Filter
-::getConvertedValue)%0A                        .collect(Collectors.toList
+Requests
 ()))
@@ -4715,10 +4715,362 @@
 );%0A    %7D
+%0A%0A    private Collection%3CQuickGOQuery%3E convertFilterRequestsToQueries(Collection%3CFilterRequest%3E filterRequests) %7B%0A        return filterRequests.stream()%0A                .map(converterFactory::convert)%0A                .filter(Objects::nonNull)%0A                .map(ConvertedFilter::getConvertedValue)%0A                .collect(Collectors.toList());%0A    %7D
 %0A%7D

Move code to convert filter into QuickGOQuery into a separate method to improve readability.