package com.arms.egovframework.javaservice.esframework.esquery;

import com.arms.egovframework.javaservice.esframework.esquery.bool.EsBoolQuery;
import com.arms.egovframework.javaservice.esframework.esquery.filter.*;
import com.arms.egovframework.javaservice.esframework.esquery.highlight.EsHighlightQuery;
import com.arms.egovframework.javaservice.esframework.esquery.must.MatchAllQueryMust;
import com.arms.egovframework.javaservice.esframework.esquery.must.MoreLikeThisMust;
import com.arms.egovframework.javaservice.esframework.esquery.must.QueryStringMust;
import com.arms.egovframework.javaservice.esframework.esquery.mustnot.ExistsQueryMustNot;
import com.arms.egovframework.javaservice.esframework.esquery.must.TermQueryMust;
import com.arms.egovframework.javaservice.esframework.esquery.mustnot.TermQueryMustNot;
import com.arms.egovframework.javaservice.esframework.esquery.mustnot.TermsQueryMustNot;
import com.arms.egovframework.javaservice.esframework.esquery.sort.EsSortQuery;
import com.arms.egovframework.javaservice.esframework.model.dto.esquery.*;
import com.arms.egovframework.javaservice.esframework.model.dto.esquery.CompositeGroupDTO;
import com.arms.egovframework.javaservice.esframework.model.dto.request.AggregationCardinalityRequestDTO;
import com.arms.egovframework.javaservice.esframework.model.dto.request.AggregationRequestDTO;
import com.arms.egovframework.javaservice.esframework.model.dto.request.CompositeRequestDTO;
import com.arms.egovframework.javaservice.esframework.model.dto.request.SearchRequestDTO;
import org.opensearch.index.query.BoolQueryBuilder;
import org.opensearch.index.query.QueryBuilders;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class SimpleQuery<T extends SearchDocDTO> extends EsQuery {

    private final List<EsBoolQuery> esBoolQueries = new ArrayList<>();

    private final T t;

    private SimpleQuery(EsBoolQuery esBoolQuery,T t) {
        this.esBoolQueries.add(esBoolQuery);
        this.t = t;
    }

    private SimpleQuery(T t) {
        this.t = t;
    }

    public static SimpleQuery<SearchDocDTO> search(SearchRequestDTO searchRequestDTO) {
        SearchDocDTO searchDocDTO = new SearchDocDTO();
        searchDocDTO.setFieldIncludes(searchRequestDTO.getIncludeFields());
        searchDocDTO.setSearchAfter(searchRequestDTO.getSearchAfter() == null ? new ArrayList<>() : searchRequestDTO.getSearchAfter());
        searchDocDTO.setPage(searchRequestDTO.getPage());
        searchDocDTO.setSize(searchRequestDTO.getSize());
        searchDocDTO.setPaging(searchRequestDTO.isPaging());
        return new SimpleQuery<>(searchDocDTO);
    }

    public static SimpleQuery<MainGroupDTO> aggregation(AggregationRequestDTO aggregationRequestDTO) {
        MainGroupDTO mainGroupDTO = new MainGroupDTO();
        mainGroupDTO.setMainField(aggregationRequestDTO.getMainField());
        mainGroupDTO.setMainFieldAlias(aggregationRequestDTO.getMainFieldAlias());
        mainGroupDTO.setContentView(aggregationRequestDTO.isContentView());
        mainGroupDTO.setAscending(aggregationRequestDTO.isAscending());
        mainGroupDTO.setSize(aggregationRequestDTO.getSize());
        mainGroupDTO.setSubGroupFieldDTOS(aggregationRequestDTO.getSubGroupFieldDTOS());
        return new SimpleQuery<>(mainGroupDTO);
    }

    public static SimpleQuery<SingleValueGroupDTO> aggregation(AggregationCardinalityRequestDTO aggregationCardinalityRequestDTO) {
        SingleValueGroupDTO singleValueGroupDTO = new SingleValueGroupDTO();
        singleValueGroupDTO.setMainField(aggregationCardinalityRequestDTO.getMainField());
        singleValueGroupDTO.setMainFieldAlias(aggregationCardinalityRequestDTO.getMainFieldAlias());
        singleValueGroupDTO.setContentView(aggregationCardinalityRequestDTO.isContentView());
        singleValueGroupDTO.setAscending(aggregationCardinalityRequestDTO.isAscending());
        singleValueGroupDTO.setSize(aggregationCardinalityRequestDTO.getSize());
        singleValueGroupDTO.setSubGroupFieldDTO(aggregationCardinalityRequestDTO.getSubGroupFieldDTO());
        return new SimpleQuery<>(singleValueGroupDTO);
    }

    public static SimpleQuery<CompositeGroupDTO> composite(CompositeRequestDTO compositeRequestDTO) {
        CompositeGroupDTO compositeQueryDTO = new CompositeGroupDTO();
        compositeQueryDTO.setSources(compositeRequestDTO.getSources());
        compositeQueryDTO.setAfterKey(compositeRequestDTO.getAfterKey());
        compositeQueryDTO.setHitSize(compositeRequestDTO.getHitSize());
        compositeQueryDTO.setSortField(compositeRequestDTO.getSortField());
        compositeQueryDTO.setSortAscending(compositeRequestDTO.isSortAscending());
        compositeQueryDTO.setIncludeFields(compositeRequestDTO.getIncludeFields());
        compositeQueryDTO.setSize(compositeRequestDTO.getSize());
        compositeQueryDTO.setContentView(compositeRequestDTO.isContentView());
        return new SimpleQuery<>(compositeQueryDTO);
    }

    public static SimpleQuery<SearchDocDTO> matchAllQueryMust(){
        return new SimpleQuery<>(new MatchAllQueryMust(),new SearchDocDTO());
    }

    public static SimpleQuery<SearchDocDTO> rangeQueryFilter(RangeQueryFilter rangeQueryFilter){
        return new SimpleQuery<>(rangeQueryFilter,new SearchDocDTO());
    }

    public static SimpleQuery<SearchDocDTO> queryStringMust(QueryStringMust queryStringMust){
        return new SimpleQuery<>(queryStringMust,new SearchDocDTO());
    }

    public static SimpleQuery<SearchDocDTO> existsQueryFilter(String key){
        return new SimpleQuery<>(new ExistsQueryFilter(key),new SearchDocDTO());
    }

    public static SimpleQuery<SearchDocDTO> existsQueryMustNot(String value){
        return new SimpleQuery<>(new ExistsQueryMustNot(value),new SearchDocDTO());
    }

    public static <T extends Serializable> SimpleQuery<SearchDocDTO> termQueryMust(String key, T value){
        return new SimpleQuery<>(new TermQueryMust(key,value),new SearchDocDTO());
    }

    public static <T extends Serializable> SimpleQuery<SearchDocDTO> termQueryMustNot(String key, T value){
        return new SimpleQuery<>(new TermQueryMustNot(key,value),new SearchDocDTO());
    }

    public static <T> SimpleQuery<SearchDocDTO> termsQueryMustNot(String key, List<T> value){
        return new SimpleQuery<>(new TermsQueryMustNot(key,value),new SearchDocDTO());
    }

    public static SimpleQuery<SearchDocDTO> wildQueryQueryFilter(String key, String value){
        return new SimpleQuery<>(new WildCardQueryFilter(key,value,true),new SearchDocDTO());
    }

    public static SimpleQuery<SearchDocDTO> wildQueryQueryFilter(String key, String value, Boolean caseInsensitive){
        return new SimpleQuery<>(new WildCardQueryFilter(key,value,caseInsensitive),new SearchDocDTO());
    }

    public static <T extends Serializable> SimpleQuery<SearchDocDTO> matchQueryFilter(String key, T t){
        return new SimpleQuery<>(new MatchQueryFilter(key,t),new SearchDocDTO());
    }

    public static <T extends Serializable> SimpleQuery<SearchDocDTO> matchQueryFilter(String key, List<T> t){
        return new SimpleQuery<>(new MatchQueryFilter(key,t),new SearchDocDTO());
    }

    public static <T extends Serializable> SimpleQuery<SearchDocDTO> termQueryFilter(String key, T value){
        return new SimpleQuery<>(new TermQueryFilter(key,value),new SearchDocDTO());
    }

    public static SimpleQuery<SearchDocDTO> queryStringFilter(String key){
        return new SimpleQuery<>(QueryStringFilter.of(key),new SearchDocDTO());
    }

    public static <T extends Serializable> SimpleQuery<SearchDocDTO> termsQueryFilter(String key, List<T> value){
        return new SimpleQuery<>(new TermsQueryFilter(key,value),new SearchDocDTO());
    }

    public SimpleQuery<SearchDocDTO> moreLikeThisMust(String[] texts, String[] fields){
        return new SimpleQuery<>(new MoreLikeThisMust(texts,fields),new SearchDocDTO());
    }

    public SimpleQuery<T> orderBy(SortDTO... sortDTOs){
        this.sort(new EsSortQuery(Arrays.stream(sortDTOs).toList()));
        return this;
    }

    public SimpleQuery<T> highlight(EsHighlightQuery esHighlightQuery){
        setHighlightBuilder(esHighlightQuery.highlight());
        return this;
    }

    public <S extends Serializable> SimpleQuery<T> andTermQueryFilter(String key, S value){
        esBoolQueries.add(new TermQueryFilter(key,value));
        return this;
    }

    public <S extends Serializable> SimpleQuery<T> andTermQueryMust(String key, S value){
        esBoolQueries.add(new TermQueryMust(key,value));
        return this;
    }

    public SimpleQuery<T> andExistQueryMustNot(String value){
        esBoolQueries.add(new ExistsQueryMustNot(value));
        return this;
    }

    public <S extends Serializable> SimpleQuery<T> andTermQueryMustNot(String key, S value){
        esBoolQueries.add(new TermQueryMustNot(key,value));
        return this;
    }

    public <S extends Serializable> SimpleQuery<T> andTermsQueryMustNot(String key, List<S> value){
        esBoolQueries.add(new TermsQueryMustNot(key,value));
        return this;
    }

    public SimpleQuery<T> andRangeQueryFilter(RangeQueryFilter rangeQueryFilter){
        esBoolQueries.add(rangeQueryFilter);
        return this;
    }

    public SimpleQuery<T> andQueryStringMust(QueryStringMust queryStringMust){
        esBoolQueries.add(queryStringMust);
        return this;
    }

    public <S extends Serializable> SimpleQuery<T> andTermsQueryFilter(String key, List<S> value){
        esBoolQueries.add(new TermsQueryFilter(key,value));
        return this;
    }

    public SimpleQuery<T> andExistsQueryFilter(String key){
        esBoolQueries.add(new ExistsQueryFilter(key));
        return this;
    }

    public SimpleQuery<T> andWildCardQueryFilter(String key, String value){
        esBoolQueries.add(new WildCardQueryFilter(key,value,true));
        return this;
    }

    public SimpleQuery<T> andWildCardQueryFilter(String key, String value,Boolean caseInsensitive){
        esBoolQueries.add(new WildCardQueryFilter(key,value,caseInsensitive));
        return this;
    }

    public <S extends Serializable> SimpleQuery<T> andMatchQueryFilter(String key, List<S> value){
        esBoolQueries.add(new MatchQueryFilter(key,value));
        return this;
    }

    public <S extends Serializable> SimpleQuery<T> andMatchQueryFilter(String key, S value){
        esBoolQueries.add(new MatchQueryFilter(key,value));
        return this;
    }

    public SimpleQuery<T> andQueryStringFilter(String key){
        esBoolQueries.add(QueryStringFilter.of(key));
        return this;
    }

    public SimpleQuery<T> andMoreLikeThisMust(String[] texts, String[] fields){
        esBoolQueries.add(new MoreLikeThisMust(texts,fields));
        return this;
    }

    public T toSearchDoc(){
        this.bool(this.esBoolQueries.toArray(EsBoolQuery[]::new));
        this.t.setEsQuery(this);
        return t;
    }

    private void bool(EsBoolQuery... esBoolQuery){
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        for (EsBoolQuery esQuery : esBoolQuery) {
            esQuery.boolQueryBuilder(boolQueryBuilder);
        }
        setBoolQueryBuilder(boolQueryBuilder);
    }

    private void sort(EsSortQuery esSortQuery){
        setSortBuilders(esSortQuery.sortBy());
    }


}
