import com.sdtool.common.api.ESDataInfoExecutor
import com.sdtool.common.api.QueryBuilderExecutor
import com.sdtool.common.api.SortBuilderExecutor
import com.dySweetFishPlugin.elasticsearch.ESClient
import com.sweetfish.convert.json.JsonConvert
import com.sweetfish.source.PageFlipper
import org.elasticsearch.action.search.SearchRequestBuilder
import org.elasticsearch.action.search.SearchResponse
import org.elasticsearch.common.unit.TimeValue
import org.elasticsearch.index.query.QueryBuilder
import org.elasticsearch.search.SearchHits

/**
 * Created by jlutt on 2022-04-20
 *
 * @author jlutt
 */

class ESList<T> {

    private ESClient esClient

    private JsonConvert jsonConvert

    private Class<T> clazz

    private QueryBuilderExecutor qbe

    private String index

    private ESDataInfoExecutor<T> de

    private List<SortBuilderExecutor> sbeList = new ArrayList<>()

    static <T> ESList<T> getESList() {
        return new ESList<>()
    }

    ESList<T> esClient(ESClient value) {
        this.esClient = value
        return this
    }

    ESList<T> jsonConvert(JsonConvert value) {
        this.jsonConvert = value
        return this
    }

    ESList<T> clazz(Class<T> value) {
        this.clazz = value
        return this
    }

    ESList<T> queryBuilder(QueryBuilderExecutor value) {
        this.qbe = value
        return this
    }

    ESList<T> sortBuilder(SortBuilderExecutor value) {
        this.sbeList.add(value)
        return this
    }

    ESList<T> index(String value) {
        this.index = value
        return this
    }

    ESList<T> dataExecutor(ESDataInfoExecutor<T> value) {
        this.de = value
        return this
    }

    List<T> executeNonePage() {
        QueryBuilder qb = qbe.execute(null)

        SearchRequestBuilder requestBuilder = esClient.getClient().prepareSearch(index).setQuery(qb)

        if ((sbeList != null) && (!sbeList.isEmpty())) {
            for (SortBuilderExecutor sortBuilderExecutor : sbeList) {
                if (sortBuilderExecutor != null) {
                    requestBuilder = requestBuilder.addSort(sortBuilderExecutor.execute())
                }
            }
        }

        SearchResponse scrollResp = requestBuilder.setSize(100)
                .setScroll(new TimeValue(60000))
                .execute()
                .actionGet()

        List<T> resultList = new ArrayList<>()

        while (scrollResp.getHits().getHits().length != 0) {
            scrollResp.getHits().getHits().each { x ->
                String json = x.getSourceAsString()
                T result = jsonConvert.convertFrom(clazz, json)
                if (de != null) {
                    de.execute(result)
                }
                resultList.add(result)
            }

            scrollResp = esClient.getClient().prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(60000)).execute().actionGet()
        }

        return resultList
    }

    List<T> executePage(PageFlipper pageFlipper) {
        if (pageFlipper == null) {
            //加这个判断的目的是为了调用方统一代码，避免写了半天，调用方还要判断是否需要分页获取
            return executeNonePage()
        }

        //需要修改pageFlipper的值，所以pageFlipper作参数传入
        QueryBuilder qb = qbe.execute(null)

        SearchRequestBuilder requestBuilder = esClient.getClient().prepareSearch(index).setQuery(qb)

        if ((sbeList != null) && (!sbeList.isEmpty())) {
            for (SortBuilderExecutor sortBuilderExecutor : sbeList) {
                if (sortBuilderExecutor != null) {
                    requestBuilder = requestBuilder.addSort(sortBuilderExecutor.execute())
                }
            }
        }

        requestBuilder = requestBuilder.setSize(pageFlipper.getPageSize())
                .setFrom(pageFlipper.getPageSize() * (pageFlipper.getPageIndex() - 1))


        SearchHits searchHits = requestBuilder.execute().actionGet().getHits()

        List<T> resultList = new ArrayList<>()
        searchHits.each { x ->
            String json = x.getSourceAsString()
            T result = jsonConvert.convertFrom(clazz, json)
            if (de != null) {
                de.execute(result)
            }
            resultList.add(result)
        }

        pageFlipper.setTotal(searchHits.getTotalHits())

        return resultList
    }

}
