package uk.ac.ebi.quickgo.geneproduct.model;

import uk.ac.ebi.quickgo.geneproduct.common.document.GeneProductFields;
import uk.ac.ebi.quickgo.rest.controller.request.ArrayPattern;
import uk.ac.ebi.quickgo.rest.search.query.QuickGOQuery;
import uk.ac.ebi.quickgo.rest.search.request.FilterRequest;

import io.swagger.annotations.ApiModelProperty;
import java.util.*;
import java.util.stream.Stream;
import javax.validation.constraints.*;

import static javax.validation.constraints.Pattern.Flag.CASE_INSENSITIVE;
import static uk.ac.ebi.quickgo.rest.search.DefaultSearchQueryTemplate.DEFAULT_PAGE_NUMBER;

/**
 * A data structure used to store the input parameters a client can submit to the Ontology search enpoint
 *
 * Once the comma separated values have been set, then turn then into an object (SimpleFilter) that
 * encapsulates the list and solr field name to use for that argument.
 */
public class GeneProductRequest {
    static final int MIN_PAGE_NUMBER = 1;

    static final int DEFAULT_ENTRIES_PER_PAGE = 25;
    static final int MIN_ENTRIES_PER_PAGE = 0;
    static final int MAX_ENTRIES_PER_PAGE = 100;

    private static final String[] TARGET_FIELDS = new String[]{GeneProductFields.Searchable.TYPE,
            GeneProductFields.Searchable.TAXON_ID};

    @ApiModelProperty(value = "Indicates whether the result set should be highlighted")
    private boolean highlighting = false;

    @ApiModelProperty(value = "Page number of the result set to display.",
            allowableValues = "range[" + MIN_PAGE_NUMBER + ",  max_result_page_size]",
            required = true)
    private int page = DEFAULT_PAGE_NUMBER;

    @ApiModelProperty(value = "Number of results per page.",
            allowableValues = "range[" + MIN_ENTRIES_PER_PAGE + "," + MAX_ENTRIES_PER_PAGE + "]",
            required = true)
    private int limit = DEFAULT_ENTRIES_PER_PAGE;

    @ApiModelProperty(value = "Fields to generate facet from", example = "taxonId, type")
    private String[] facet;

    @ApiModelProperty(value = "The query used to filter the gene products", example = "kinase", required = true)
    private String query;

    /*
        The filter fields are only declared here, because there is a bug in springfox that doesn't read annotations on
        setters
     */
    @ApiModelProperty(value = "Further filters the results of the main query based on values chosen from " +
            "the taxonomy identifier field", example = "9606")
    private String[] taxonId;

    @ApiModelProperty(value = "Further filters the results of the main query based on a value chosen from " +
            "the type field", allowableValues = "protein,miRNA,complexes", example = "protein")
    private String type;

    private Map<String, String[]> filterMap = new HashMap<>();

    @Min(value = MIN_PAGE_NUMBER, message = "Page number cannot be less than 1")
    public int getPage() {
        return page;
    }

    public void setPage(int page) {
        this.page = page;
    }

    @Min(value = MIN_ENTRIES_PER_PAGE, message = "Number of results per page cannot be less than 0")
    @Max(value = MAX_ENTRIES_PER_PAGE,
            message = "Number of results per page cannot be greater than " + MAX_ENTRIES_PER_PAGE)
    public int getLimit() {
        return limit;
    }

    public void setLimit(int limit) {
        this.limit = limit;
    }

    @NotNull(message = "Query cannot be null")
    @Size(min = 1, message = "Query cannot be empty")
    public String getQuery() {
        return query;
    }

    public void setQuery(String query) {
        this.query = query;
    }

    public boolean isHighlighting() {
        return highlighting;
    }

    public void setHighlighting(boolean useHighlighting) {
        this.highlighting = useHighlighting;
    }

    public String[] getFacet() {
        return facet;
    }

    public void setFacet(String[] facets) {
        this.facet = facets;
    }

    @ArrayPattern(regexp = "[0-9]+", paramName = "taxonId")
    public String[] getTaxonId() {
        return filterMap.get(GeneProductFields.TAXON_ID);
    }

    public void setTaxonId(String... taxonIds) {
        if (taxonIds != null) {
            filterMap.put(GeneProductFields.TAXON_ID, taxonIds);
        }
    }

    @Pattern(regexp = "protein|miRNA|complexes", flags = CASE_INSENSITIVE,
            message = "Provided type is invalid: ${validatedValue}")
    public String getType() {
        return filterMap.get(GeneProductFields.Searchable.TYPE) == null ? null :
                filterMap.get(GeneProductFields.Searchable.TYPE)[0];
    }

    public void setType(String filterByType) {
        if (filterByType != null) {
            filterMap.put(GeneProductFields.Searchable.TYPE, new String[]{filterByType});
        }
    }

    public QuickGOQuery createQuery() {
        return QuickGOQuery.createQuery(query);
    }

    public List<FilterRequest> createFilterRequests() {
        List<FilterRequest> filterRequests = new ArrayList<>();

        Stream.of(TARGET_FIELDS)
                .map(this::createFilter)
                .filter(Optional::isPresent)
                .map(Optional::get)
                .forEach(filterRequests::add);

        return filterRequests;
    }

    private Optional<FilterRequest> createFilter(String key) {
        Optional<FilterRequest> request;

        if (filterMap.containsKey(key)) {
            FilterRequest.Builder requestBuilder = FilterRequest.newBuilder();
            requestBuilder.addProperty(key, filterMap.get(key));
            request = Optional.of(requestBuilder.build());
        } else {
            request = Optional.empty();
        }

        return request;
    }
}

@@ -1559,37 +1559,8 @@
 ze%5D%22
-,%0A            required = true
 )%0A  
@@ -1763,37 +1763,8 @@
  %22%5D%22
-,%0A            required = true
 )%0A  

Make page and limit non mandatory.