
package com.tmerclub.cloud.search.builder;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Maps;
import com.tmerclub.cloud.api.dto.EsPageDTO;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.constant.StatusEnum;
import com.tmerclub.cloud.common.i18n.I18nMessage;
import com.tmerclub.cloud.common.i18n.LanguageEnum;
import com.tmerclub.cloud.common.product.constant.*;
import com.tmerclub.cloud.common.product.dto.ProductSearchDTO;
import com.tmerclub.cloud.common.product.dto.ProductSearchLimitDTO;
import com.tmerclub.cloud.common.util.BooleanUtil;
import com.tmerclub.cloud.search.constant.*;
import com.tmerclub.cloud.search.util.EsSearchUtil;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.lucene.search.function.CombineFunction;
import org.elasticsearch.common.lucene.search.function.FieldValueFactorFunction;
import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FieldValueFactorFunctionBuilder;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.TopHitsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.NestedSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.*;


/**
 * @author tmerclub
 * @date 2020/11/16
 */
@Component
public class ProductSearchRequestBuilder {

    private static final Logger log = LoggerFactory.getLogger(ProductSearchRequestBuilder.class);


    /**
     * 通过搜索信息分页搜索es数据的信息
     *
     * @param pageDTO          分页数据
     * @param productSearchDTO 商品搜索条件
     * @param isAgg            true:聚合搜索  false:非聚合搜索  null:非聚合搜索
     * @return 搜索结果
     */
    public SearchResponse pageSearchResult(EsPageDTO pageDTO, ProductSearchDTO productSearchDTO, Boolean isAgg) {
        //1、准备检索请求
        SearchRequest searchRequest = buildSearchRequest(pageDTO, productSearchDTO, isAgg);
        return EsSearchUtil.search(searchRequest);
    }

    /**
     * 准备检索请求
     *
     * @param pageDTO 分页参数
     * @param param   搜索参数
     * @param isAgg   true:聚合搜索  false:非聚合搜索  null:非聚合搜索
     * @return
     */
    private SearchRequest buildSearchRequest(EsPageDTO pageDTO, ProductSearchDTO param, Boolean isAgg) {
        if (Objects.isNull(param.getAppDisplay())) {
            param.setAppDisplay(Boolean.FALSE);
        }

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        Integer lang = I18nMessage.getLang();

        // 指定返回数组中的字段
        if (ArrayUtil.isNotEmpty(param.getFetchSource())) {
            searchSourceBuilder.fetchSource(param.getFetchSource(), null);
        } else {
            searchSourceBuilder.fetchSource(EsConstant.APP_FETCH_SOURCE, null);
        }

        // 构建bool-query
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();

        // 过滤
        filterQueryIfNecessary(param, boolQueryBuilder, lang);

        // 关键字搜索
        keywordSearch(param, boolQueryBuilder, lang);

        // 排序
        sort(param, searchSourceBuilder, boolQueryBuilder, lang);

        //分页
        if (Objects.nonNull(pageDTO)) {
            searchSourceBuilder.from((pageDTO.getPageNum() - 1) * pageDTO.getPageSize());
            searchSourceBuilder.size(pageDTO.getPageSize());
        }

        // 进行聚合分析
        agg(param, searchSourceBuilder, isAgg);

        log.info("构建的DSL语句 {}", searchSourceBuilder);

        return new SearchRequest(new String[]{EsIndexEnum.PRODUCT.value()}, searchSourceBuilder);
    }

    public SearchRequest buildScrollSearchRequest(ProductSearchDTO param, Scroll scroll) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 构建bool-query
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        Integer lang = Objects.nonNull(param.getLang()) ? param.getLang() : I18nMessage.getLang();
        // 指定返回数组中的字段
        if (ArrayUtil.isNotEmpty(param.getFetchSource())) {
            searchSourceBuilder.fetchSource(param.getFetchSource(), null);
        }
        // 过滤
        filterQueryIfNecessary(param, boolQueryBuilder, lang);

        // 关键字搜索
        keywordSearch(param, boolQueryBuilder, lang);

        // 排序
        sort(param, searchSourceBuilder, boolQueryBuilder, lang);

        searchSourceBuilder.query(boolQueryBuilder);
        //设置最多一次能够取出100笔数据，从第101笔数据开始，将开启滚动查询
        //PS:滚动查询也属于这一次查询，只不过因为一次查不完，分多次查
        searchSourceBuilder.size(EsConstant.MAX_PAGE_SIZE);

        log.info("构建滚动查询的DSL语句 {}", searchSourceBuilder);

        return new SearchRequest(new String[]{EsIndexEnum.PRODUCT.value()}, searchSourceBuilder).scroll(scroll);
    }

    /**
     * 聚合分析
     */
    private void agg(ProductSearchDTO param, SearchSourceBuilder searchSourceBuilder, Boolean isAgg) {
        // 店铺进行聚合
        if (param.getKeyword() != null && param.getKeyword().length() > 0) {
            searchSourceBuilder.aggregation(AggregationBuilders.terms(EsConstant.SHOP).field(EsConstant.SHOP_ID).size(1));
        }
        if (Objects.isNull(isAgg) || !isAgg) {
            return;
        }
        // 品牌聚合
        searchSourceBuilder.aggregation(EsSearchUtil.nestedAggregation(EsConstant.BRAND, EsConstant.BRAND_UNION_ID, EsConstant.BRAND_ID, EsConstant.BRAND_INCLUDE));

        // 搜索平台商品，按照平台分类信息进行聚合
        if (Objects.isNull(param.getShopId()) && Objects.isNull(param.getCategoryId())) {
            searchSourceBuilder.aggregation(EsSearchUtil.nestedAggregation(EsConstant.CATEGORY, EsConstant.CATEGORY_UNION_ID, EsConstant.CATEGORY_ID, EsConstant.CATEGORY_INCLUDE));
        }
        // 搜索店铺中的商品，按照店铺分类信息进行聚合
        else if (Objects.nonNull(param.getShopId()) && Objects.isNull(param.getShopSecondaryCategoryId())) {
            searchSourceBuilder.aggregation(EsSearchUtil.nestedAggregation(EsConstant.SHOP_CATEGORY, EsConstant.SHOP_CATEGORY_UNION_ID, EsConstant.SHOP_CATEGORY_ID, EsConstant.CATEGORY_INCLUDE));
        }

        // 按照属性信息进行聚合
        NestedAggregationBuilder attrs = AggregationBuilders.nested(EsConstant.ATTRS, EsConstant.ATTRS);

        // 按照属性ID进行聚合
        TermsAggregationBuilder attrIds = AggregationBuilders.terms(EsConstant.ATTR_IDS).field(EsConstant.ATTR_UNION_ID).size(10);
        attrs.subAggregation(attrIds);
        TermsAggregationBuilder attrValueIds = AggregationBuilders.terms(EsConstant.ATTR_VALUE_IDS).field(EsConstant.ATTR_ATTR_VALUE_ID).size(10);
        attrIds.subAggregation(attrValueIds);

        attrValueIds.subAggregation(AggregationBuilders
                .topHits(EsConstant.TOP_HITS_DATA)
                .fetchSource(EsConstant.ATTR_INCLUDE, null)
                .sort(EsConstant.ATTR_UNION_VALUE_ZH, SortOrder.ASC)
                .size(1));

        searchSourceBuilder.aggregation(attrs);
    }

    /**
     * 关键字搜索
     */
    private void keywordSearch(ProductSearchDTO param, BoolQueryBuilder boolQueryBuilder, Integer lang) {
        if (StrUtil.isBlank(param.getKeyword())) {
            return;
        }
        // 创建查询语句 ES中must和should不能同时使用 同时使用should失效 嵌套多个must 将should条件拼接在一个must中即可
        BoolQueryBuilder keywordShouldQuery = QueryBuilders.boolQuery();
        // 商家、平台端商品名称模糊搜索
        if (Objects.isNull(param.getAppDisplay()) || !param.getAppDisplay()) {
            if (Objects.equals(lang, LanguageEnum.LANGUAGE_ZH_CN.getLang())) {
                keywordShouldQuery.should(QueryBuilders.wildcardQuery(EsConstant.SPU_NAME_LIKE_ZH, "*" + param.getKeyword() + "*"));
            } else {
                keywordShouldQuery.should(QueryBuilders.wildcardQuery(EsConstant.SPU_NAME_LIKE_EN, "*" + param.getKeyword() + "*"));
            }
        }
        // 用户端商品名称分词搜索
        else {
            // 提升商品名称搜索的权重
            if (Objects.equals(lang, LanguageEnum.LANGUAGE_ZH_CN.getLang())) {
                keywordShouldQuery.should(QueryBuilders.matchQuery(EsConstant.SPU_NAME_ZH, param.getKeyword()).boost(10));
            } else {
                keywordShouldQuery.should(QueryBuilders.matchQuery(EsConstant.SPU_NAME_EN, param.getKeyword()).boost(10));
            }

            if (param.getKeyword().length() > 1) {
                // 卖点，不分词
                if (Objects.equals(lang, LanguageEnum.LANGUAGE_ZH_CN.getLang())) {
                    keywordShouldQuery.should(QueryBuilders.matchPhraseQuery(EsConstant.SELLING_POINT_ZH, param.getKeyword()).boost(2));
                } else {
                    keywordShouldQuery.should(QueryBuilders.matchPhraseQuery(EsConstant.SELLING_POINT_EN, param.getKeyword()).boost(2));
                }
            }
        }
        boolQueryBuilder.must(keywordShouldQuery);
    }

    /**
     * 进行排序
     */
    private void sort(ProductSearchDTO param, SearchSourceBuilder searchSourceBuilder, BoolQueryBuilder boolQueryBuilder, Integer lang) {
        // 如果是分组搜索，默认排序方式为分组序号倒序(用户端)
        if (Objects.nonNull(param.getTagId()) && Objects.isNull(param.getSort())) {
            searchSourceBuilder.sort(SortBuilders.fieldSort(EsProductSortEnum.SPU_TAG_DESC.param())
                    .order(EsProductSortEnum.SPU_TAG_DESC.order())
                    .setNestedSort(new NestedSortBuilder(EsConstant.TAGS)));
            searchSourceBuilder.sort(EsProductSortEnum.SALE_NUM_DESC.param(), EsProductSortEnum.SALE_NUM_DESC.order());
            searchSourceBuilder.query(boolQueryBuilder);
            return;
        }

        // 用户端、商家端、平台端自定义排序
        if (Objects.nonNull(param.getSort())) {
            if (Objects.equals(param.getSort(), EsProductSortEnum.NON_SORT.value())) {
                // 不进行任何排序
                searchSourceBuilder.query(boolQueryBuilder);
                return;
            }
            for (EsProductSortEnum enumValue : EsProductSortEnum.values()) {
                if (!Objects.equals(enumValue.value(), param.getSort())) {
                    continue;
                }
                searchSourceBuilder.sort(enumValue.param(), enumValue.order());
            }
            //封装所有的查询条件(没有function score)
            searchSourceBuilder.query(boolQueryBuilder);
            return;
        }

        // 用户端关键字排序 -- 没有指定排序规则，且是关键字搜索的查询，统一按关键字优先排序（防止关键字搜素时，关键字的商品没有优先显示）
        if (StrUtil.isNotBlank(param.getKeyword()) && param.getAppDisplay()) {
            this.keywordSort(param, searchSourceBuilder, boolQueryBuilder, lang);
            return;
        }

        // 平台、商家端的店铺名称、商品名称搜索排序
        if (StrUtil.isNotBlank(param.getKeyword()) || StrUtil.isNotBlank(param.getShopName())) {
            if (StrUtil.isNotBlank(param.getKeyword())) {
                this.keywordLikeSort(param, searchSourceBuilder, boolQueryBuilder, lang);
                return;
            }
            // 平台、商家端的店铺名称、商品名称搜索
            this.shopNameSort(param, searchSourceBuilder, boolQueryBuilder);
            return;
        }


        // 商家、平台默认排序--商品序号 倒序， 创建时间 倒序
        if (Objects.nonNull(param.getShopId())) {
            if (Objects.isNull(param.getShopQuerySupplierSpu()) || Objects.equals(param.getShopQuerySupplierSpu(), false)) {
                // 商家端优先显示序号大的商品, 再到实际销量倒序
                searchSourceBuilder.sort(EsProductSortEnum.SEQ_DESC.param(), EsProductSortEnum.SEQ_DESC.order());
            }
        } else {
            boolean isTop = Objects.isNull(param.getSupplierId()) && (Objects.isNull(param.getShopQuerySupplierSpu()) || Objects.equals(param.getShopQuerySupplierSpu(), false));
            if (isTop) {
                // 平台端优先置顶的商品, 再到销量（实际销量+注水销量）
                searchSourceBuilder.sort(EsProductSortEnum.IS_TOP_DESC.param(), EsProductSortEnum.IS_TOP_DESC.order());
                searchSourceBuilder.sort(EsProductSortEnum.SALE_NUM_DESC.param(), EsProductSortEnum.SALE_NUM_DESC.order());
            }
        }
        searchSourceBuilder.sort(EsProductSortEnum.CREATE_TIME_DESC.param(), EsProductSortEnum.CREATE_TIME_DESC.order());
        searchSourceBuilder.query(boolQueryBuilder);


    }

    private void keywordLikeSort(ProductSearchDTO param, SearchSourceBuilder searchSourceBuilder, BoolQueryBuilder boolQueryBuilder, Integer lang) {
        List<FunctionScoreQueryBuilder.FilterFunctionBuilder> filterFunctionBuilders = new ArrayList<>();
        String name;
        if (Objects.equals(lang, LanguageEnum.LANGUAGE_ZH_CN.getLang())) {
            name = EsConstant.SPU_NAME_LIKE_ZH;
        } else {
            name = EsConstant.SPU_NAME_LIKE_EN;
        }
        // 商品名称完全匹配
        filterFunctionBuilders.add(
                new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.wildcardQuery(name, param.getKeyword()), ScoreFunctionBuilders.weightFactorFunction(1000))
        );
        // 商品名称前缀匹配
        filterFunctionBuilders.add(
                new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.wildcardQuery(name, param.getKeyword() + "*"), ScoreFunctionBuilders.weightFactorFunction(500))
        );
        // 商品名称优先前缀匹配
        filterFunctionBuilders.add(
                new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.wildcardQuery(name, "?" + param.getKeyword() + "*"), ScoreFunctionBuilders.weightFactorFunction(200))
        );
        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(boolQueryBuilder, ArrayUtil.toArray(filterFunctionBuilders, FunctionScoreQueryBuilder.FilterFunctionBuilder.class))
                .scoreMode(FunctionScoreQuery.ScoreMode.SUM).boostMode(CombineFunction.SUM);
        // 封装所有的查询条件(带有function score)
        searchSourceBuilder.query(functionScoreQueryBuilder);
    }
    /**
     * 关键字搜索排序
     * @param param
     * @param searchSourceBuilder
     * @param boolQueryBuilder
     */
    private void shopNameSort(ProductSearchDTO param, SearchSourceBuilder searchSourceBuilder, BoolQueryBuilder boolQueryBuilder) {
        List<FunctionScoreQueryBuilder.FilterFunctionBuilder> filterFunctionBuilders = new ArrayList<>();
        // 关键字搜索，优先匹配
        filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                QueryBuilders.multiMatchQuery(EsConstant.SHOP_NAME, param.getShopName()).minimumShouldMatch("100%"),
                ScoreFunctionBuilders.weightFactorFunction(100)
        ));

        filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                QueryBuilders.multiMatchQuery(EsConstant.SHOP_NAME, param.getShopName()).minimumShouldMatch("70%"),
                ScoreFunctionBuilders.weightFactorFunction(100)
        ));
        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(boolQueryBuilder, ArrayUtil.toArray(filterFunctionBuilders, FunctionScoreQueryBuilder.FilterFunctionBuilder.class))
                .scoreMode(FunctionScoreQuery.ScoreMode.SUM).boostMode(CombineFunction.SUM);
        // 封装所有的查询条件(带有function score)
        searchSourceBuilder.query(functionScoreQueryBuilder);
    }

    private void keywordSort(ProductSearchDTO param, SearchSourceBuilder searchSourceBuilder, BoolQueryBuilder boolQueryBuilder, Integer lang) {
        List<FunctionScoreQueryBuilder.FilterFunctionBuilder> filterFunctionBuilders = new ArrayList<>(Constant.INITIAL_CAPACITY);
        // 关键字搜索，优先匹配
        if (StrUtil.isNotBlank(param.getKeyword())) {
            FunctionScoreQueryBuilder.FilterFunctionBuilder spuName;
            if (Objects.equals(lang, LanguageEnum.LANGUAGE_ZH_CN.getLang())) {
                spuName = new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery(EsConstant.SPU_NAME_ZH, param.getKeyword()), ScoreFunctionBuilders.weightFactorFunction(1000));
            } else {
                spuName = new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery(EsConstant.SPU_NAME_EN, param.getKeyword()), ScoreFunctionBuilders.weightFactorFunction(1000));
            }
            filterFunctionBuilders.add(spuName);
        }


        // 用户端默认排序优先使用是否置顶参数
        FunctionScoreQueryBuilder.FilterFunctionBuilder isTop = new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery(EsConstant.IS_TOP, 10), ScoreFunctionBuilders.weightFactorFunction(100));
        filterFunctionBuilders.add(isTop);

        // 评论数 log1p
        ScoreFunctionBuilder<FieldValueFactorFunctionBuilder> commentNumScoreFunction = new FieldValueFactorFunctionBuilder(EsConstant.COMMENT_NUM).modifier(FieldValueFactorFunction.Modifier.LOG1P).factor(0.5f);
        filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(commentNumScoreFunction));
        // 销量数 square(出现负数销量，导致评分负数，使用平方解决负数评分)
        ScoreFunctionBuilder<FieldValueFactorFunctionBuilder> saleNumScoreFunction = new FieldValueFactorFunctionBuilder(EsConstant.SALE_NUM).modifier(FieldValueFactorFunction.Modifier.SQUARE).factor(0.5f);
        filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(saleNumScoreFunction));

        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(boolQueryBuilder, ArrayUtil.toArray(filterFunctionBuilders, FunctionScoreQueryBuilder.FilterFunctionBuilder.class))
                .scoreMode(FunctionScoreQuery.ScoreMode.SUM).boostMode(CombineFunction.SUM);

        // 封装所有的查询条件(带有function score)
        searchSourceBuilder.query(functionScoreQueryBuilder)
                .sort(EsConstant.SCORE, SortOrder.DESC);
    }

    /**
     * 过滤查询条件，如果有必要的话
     *
     * @param param            查询条件
     * @param boolQueryBuilder 组合进boolQueryBuilder
     * @param lang             当前语言
     */
    private void filterQueryIfNecessary(ProductSearchDTO param, BoolQueryBuilder boolQueryBuilder, Integer lang) {

        // 用户端搜索
        if (param.getAppDisplay()) {
            boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.APP_DISPLAY, param.getAppDisplay()));
            List<Long> supplierSpuType = new ArrayList<>(Constant.INITIAL_CAPACITY);
            //过滤掉供应商商品,
            supplierSpuType.add(0L);
            supplierSpuType.add(2L);
            boolQueryBuilder.filter(QueryBuilders.termsQuery(EsConstant.SUPPLIER_SPU_TYPE, supplierSpuType));
            //用户端过滤活动商品
            boolQueryBuilder.mustNot(QueryBuilders.termQuery(EsConstant.SPU_TYPE, SpuType.ACTIVE.value()));
        }

        //供应商商品类型
        supplierSpuTypeFilterQuery(param, boolQueryBuilder);

        //供应商id过滤
        supplierIdFilterQuery(param, boolQueryBuilder);

        // 名称（店铺名称）
        nameSearch(param, boolQueryBuilder, lang);

        // 商品（状态、库存、商品类型、商品id、商品id列表、商品编码、商品条形码、配送自提）
        spuFilterQuery(param, boolQueryBuilder);

        // 分类（商家一二级分类，平台一二三级分类）
        categoryFilterQuery(param, boolQueryBuilder);

        // 活动 （活动商品id、 活动时间、 秒杀活动商品、 分销商品）
        activityFilterQuery(param, boolQueryBuilder);

        // 商品扩展信息筛选（店铺id、店铺类型、供应商id、spu分组、品牌、规格属性）
        extensionFilterQuery(param, boolQueryBuilder);

        // 范围筛选（价格、销量）
        rangeFilterQuery(param, boolQueryBuilder);

        //代销商品状态
        commissionSpuStatusFilterQuery(param, boolQueryBuilder);

        //供应商名称
        supplierNameFilterQuery(param, boolQueryBuilder);

        //skuCode
        skuCodeFilterQuery(param, boolQueryBuilder);

        //过滤虚拟商品和活动商品和供应商商品、是否过滤定金预售商品
        spuMoldFilterQuery(param, boolQueryBuilder);

        //供应商品状态(商家端不显示平台下架、等待审核状态的供应商商品)
        supplierStatusFilterQuery(param, boolQueryBuilder);

    }

    /**
     * 范围过滤
     *
     * @param param            查询条件
     * @param boolQueryBuilder
     */
    private void rangeFilterQuery(ProductSearchDTO param, BoolQueryBuilder boolQueryBuilder) {
        // 价格区间
        if (param.getMinPrice() != null || param.getMaxPrice() != null) {
            boolQueryBuilder.filter(EsSearchUtil.rangeQuery(EsConstant.PRICE_FEE, param.getMinPrice(), param.getMaxPrice()));
        }
        // 销量区间
        if (param.getMinSaleNum() != null || param.getMaxSaleNum() != null) {
            boolQueryBuilder.filter(EsSearchUtil.rangeQuery(param.getAppDisplay() ? EsConstant.SALE_NUM : EsConstant.ACTUAL_SOLD_NUM,
                    param.getMinSaleNum(), param.getMaxSaleNum()));
        }
        if (Objects.nonNull(param.getStockWarning()) && param.getStockWarning().equals(1)) {
            Map<String, Object> params = Maps.newHashMap();
            params.put("datesub", 0);
            boolQueryBuilder.must(QueryBuilders.scriptQuery(
                    new Script(Script.DEFAULT_SCRIPT_TYPE,
                            Script.DEFAULT_SCRIPT_LANG,
                            "doc['stockWarning'].size()>0 && (doc['stock'].value - doc['stockWarning'].value <= params.datesub)", params)));
        }
    }

    /**
     * 商品扩展信息过滤
     *
     * @param param            查询条件
     * @param boolQueryBuilder
     */
    private void extensionFilterQuery(ProductSearchDTO param, BoolQueryBuilder boolQueryBuilder) {
        // 店铺id
        if (Objects.nonNull(param.getShopId())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.SHOP_ID, param.getShopId()));
        }

        // 店铺类型
        if (Objects.nonNull(param.getSelfShop())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.SHOP_TYPE, param.getSelfShop()));
        }

        // 供应商id
        if (Objects.nonNull(param.getSupplierId())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.SUPPLIER_ID, param.getSupplierId()));
        }

        // spu分组
        if (Objects.nonNull(param.getTagId())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.TAG_IDS, param.getTagId()));
        }


        // 品牌
        if (StrUtil.isNotBlank(param.getBrandIds())) {
            boolQueryBuilder.filter(EsSearchUtil.nestedQueryByArray(EsConstant.BRAND, EsConstant.BRAND_UNION_ID, param.getBrandIds()));
        }

        // 规格属性值
        if (MapUtil.isNotEmpty(param.getAttrMap())) {
            for (String attrId : param.getAttrMap().keySet()) {
                boolQueryBuilder.filter(EsSearchUtil.nestedQuery(EsConstant.ATTRS, EsConstant.ATTR_ATTR_VALUE_ID, param.getAttrMap().get(attrId)));
            }
        }
    }

    /**
     * 商品活动信息过滤
     *
     * @param param            查询条件
     * @param boolQueryBuilder
     */
    private void activityFilterQuery(ProductSearchDTO param, BoolQueryBuilder boolQueryBuilder) {
        // 商品活动Id
        if (Objects.nonNull(param.getActivityId())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.ACTIVITY_ID, param.getActivityId()));
        }

        // 活动商品（过滤活动时间）
        if (Objects.equals(param.getSpuType(), SpuType.GROUP.value()) && param.getAppDisplay()) {
            boolQueryBuilder.filter(EsSearchUtil.rangeQuery(EsConstant.ACTIVITY_START_TIME, null, System.currentTimeMillis()));
        }

        // 秒杀活动商品（过滤活动时间及批次及秒杀分类）
        if (Objects.equals(param.getSpuType(), SpuType.SECKILL.value())) {
            if (Objects.nonNull(param.getActivityTime())) {
                Calendar calendar = DateUtil.calendar(param.getActivityTime());
                if (Objects.isNull(param.getSelectedLot())) {
                    return;
                }
                long activityStartTime = DateUtil.offsetHour(calendar.getTime(), param.getSelectedLot()).getTime();
                // 根据时间搜索，此处为时间戳
                boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.ACTIVITY_START_TIME, activityStartTime));
            }
            if (Objects.nonNull(param.getSeckillCategoryId())) {
                boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.SECKILL_CATEGORY_ID, param.getSeckillCategoryId()));
            }
            if (Objects.nonNull(param.getSelectedLot())) {
                boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.SELECTED_LOT, param.getSelectedLot()));
            }
        }

        // 分销商品
        if (Objects.nonNull(param.getDistributionSpu())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.DISTRIBUTION_SPU, param.getDistributionSpu()));
            if (Objects.equals(param.getDistributionSpu(), Boolean.TRUE)) {
                // 分销信息
                if (Objects.nonNull(param.getDistributionState())) {
                    boolQueryBuilder.filter(EsSearchUtil.nestedQuery(EsConstant.DISTRIBUTION_INFO, EsConstant.STATE_UNION_NAME, param.getDistributionState().longValue()));
                }
                if (Objects.nonNull(param.getAwardMode())) {
                    boolQueryBuilder.filter(EsSearchUtil.nestedQuery(EsConstant.DISTRIBUTION_INFO, EsConstant.AWARD_MODE_UNION_NAME, param.getAwardMode().longValue()));
                }
            }
        }
    }

    /**
     * 名称过滤
     *
     * @param param            查询条件
     * @param boolQueryBuilder
     * @param lang
     */
    private void nameSearch(ProductSearchDTO param, BoolQueryBuilder boolQueryBuilder, Integer lang) {
        // 店铺名称
        if (StrUtil.isNotBlank(param.getShopName())) {
            BoolQueryBuilder nameShoudongQuery = new BoolQueryBuilder();
            nameShoudongQuery.should(QueryBuilders.matchQuery(EsConstant.SHOP_NAME, param.getShopName()));
            BoolQueryBuilder supplierQueryBuilder = new BoolQueryBuilder();
            supplierQueryBuilder.must(QueryBuilders.matchQuery(EsConstant.SUPPLIER_NAME, param.getShopName()));
            supplierQueryBuilder.mustNot(QueryBuilders.existsQuery(EsConstant.SHOP_NAME));
            nameShoudongQuery.should(supplierQueryBuilder);
            boolQueryBuilder.must(nameShoudongQuery);
        }
    }

    /**
     * 商品信息过滤
     *
     * @param param            查询条件
     * @param boolQueryBuilder
     */
    private void spuFilterQuery(ProductSearchDTO param, BoolQueryBuilder boolQueryBuilder) {
        // 过滤商品状态、库存、类型和类别
        List<Integer> statusList = filterStatusStockAndType(param, boolQueryBuilder);

        boolean spuStatusCheck = Objects.isNull(param.getDataType()) || Objects.equals(param.getDataType(), DataType.ALL.value());
        // 装修以及定时任务获取删除商品
        if (!BooleanUtil.isTrue(param.getGetDelete()) && Objects.isNull(param.getSpuStatus())
                && spuStatusCheck) {
            statusList.add(StatusEnum.ENABLE.value());
            statusList.add(StatusEnum.DISABLE.value());
            statusList.add(StatusEnum.OFFLINE.value());
            statusList.add(StatusEnum.WAIT_AUDIT.value());
            statusList.add(SpuStatus.PUBLISH_WAIT_AUDIT.value());
        }
        if (CollUtil.isNotEmpty(statusList)) {
            boolQueryBuilder.filter(QueryBuilders.termsQuery(EsConstant.SPU_STATUS, statusList));
        }

        // 是否展示定金预售商品 1.是 0.否
        if (Objects.nonNull(param.getCanDeposit()) && Objects.equals(param.getCanDeposit(), 0)) {
            boolQueryBuilder.mustNot(QueryBuilders.termQuery(EsConstant.PRE_SALE_TYPE, PreSaleType.DEPOSIT.value()));
        }
        if (Objects.nonNull(param.getCanDeposit()) && Objects.equals(param.getIsGiveaway(), 1)) {
            boolQueryBuilder.filter(QueryBuilders.termsQuery(EsConstant.PRE_SALE_TYPE, PreSaleType.DISABLE.value().toString()));
        }
        // spuId
        if (Objects.nonNull(param.getSpuId())) {
            boolQueryBuilder.filter(QueryBuilders.termsQuery(EsConstant.SPU_ID, param.getSpuId().toString()));
        }
        // spuId列表
        else if (CollectionUtil.isNotEmpty(param.getSpuIds())) {
            boolQueryBuilder.filter(QueryBuilders.termsQuery(EsConstant.SPU_ID, param.getSpuIds()));
        }
        // 查询不在该集合中的商品
        if (Objects.nonNull(param.getSpuIdsExclude())) {
            boolQueryBuilder.mustNot(QueryBuilders.termsQuery(EsConstant.SPU_ID, param.getSpuIdsExclude()));
        }
        // 商品编码
        if (StrUtil.isNotBlank(param.getPartyCodes())) {
            BoolQueryBuilder partyCodesShouldQuery = QueryBuilders.boolQuery()
                    .should(QueryBuilders.matchPhraseQuery("partyCodes", param.getPartyCodes()));
            boolQueryBuilder.must(partyCodesShouldQuery);
        }
        //spu编码
        if (StrUtil.isNotBlank(param.getSpuCode())) {
            boolQueryBuilder.filter(QueryBuilders.matchQuery(EsConstant.SPU_CODE, param.getSpuCode()));
        }

        // 商品条形码
        if (StrUtil.isNotBlank(param.getModelIds())) {
            boolQueryBuilder.filter(EsSearchUtil.termsQueryByArray(EsConstant.MODEL_ID, param.getModelIds()));
        }

        //发货方式  如果是商家发货的话只要过滤供应商发货的就可以
        if (Objects.nonNull(param.getSupplierDeliveryType())) {
            if (Objects.equals(param.getSupplierDeliveryType(), SupplierDeliveryType.SHOP_DELIVERY.value())) {
                boolQueryBuilder.mustNot(QueryBuilders.termQuery(EsConstant.SUPPLIER_DELIVERY_TYPE, SupplierDeliveryType.SUPPLIER_DELIVERY.value()));
            } else {
                boolQueryBuilder.must(QueryBuilders.termQuery(EsConstant.SUPPLIER_DELIVERY_TYPE, param.getSupplierDeliveryType()));
            }
        }
        //商品来源
        if (Objects.nonNull(param.getSpuOrigin())) {
            List<Integer> list = new ArrayList<>(Constant.INITIAL_CAPACITY);
            if (param.getSpuOrigin().equals(1)) {
                list.add(2);
                list.add(1);
            }
            if (param.getSpuOrigin().equals(0)) {
                list.add(0);
            }
            boolQueryBuilder.must(QueryBuilders.termsQuery(EsConstant.SUPPLIER_SPU_TYPE, list));
        }
        //过滤逻辑删除商品
        if (!BooleanUtil.isTrue(param.getGetDelete())) {
            boolQueryBuilder.mustNot(QueryBuilders.termQuery(EsConstant.SPU_STATUS, StatusEnum.DELETE.value()));
        }
        // 过滤非自提商品
        if (Objects.nonNull(param.getHasUserPickUp()) && param.getHasUserPickUp()) {
            boolQueryBuilder.filter(EsSearchUtil.nestedQuery(EsConstant.DELIVERY_MODE, EsConstant.DELIVERY_USER_MODE, param.getHasUserPickUp().toString()));
        }
    }

    /**
     * 过滤商品状态、库存、类型和类别
     * @param param
     * @param boolQueryBuilder
     * @return
     */
    private static List<Integer> filterStatusStockAndType(ProductSearchDTO param, BoolQueryBuilder boolQueryBuilder) {
        // spu状态
        List<Integer> statusList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        if (Objects.nonNull(param.getSpuStatus()) && !Objects.equals(param.getSpuStatus(), StatusEnum.DELETE.value())) {
            statusList.add(param.getSpuStatus());
        } else if (Objects.equals(param.getDataType(), DataType.DISABLE.value())) {
            statusList.add(StatusEnum.DISABLE.value());
            statusList.add(StatusEnum.OFFLINE.value());
            statusList.add(StatusEnum.WAIT_AUDIT.value());
            statusList.add(SpuStatus.PUBLISH_WAIT_AUDIT.value());
        }
        // 是否有库存
        if (Objects.nonNull(param.getHasStock())) {
            //不过滤供应商发货的代销商品
            if (Objects.isNull(param.getIsSupplierType())) {
                boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.HAS_STOCK, BooleanUtil.isTrue(param.getHasStock())));
            }

            if (Objects.nonNull(param.getSupplierDeliveryType())) {
                //商家端代销商品过滤掉发货方式为供应商的商品
                boolQueryBuilder.mustNot(QueryBuilders.termQuery(EsConstant.SUPPLIER_DELIVERY_TYPE, SupplierDeliveryType.SUPPLIER_DELIVERY.value()));
            }
        }
        // 商品类型(搜索全部商品时，不进行类型过滤)
        if (!Objects.equals(param.getDataType(), DataType.ALL_PROD.value())) {
            if (Objects.nonNull(param.getSpuType())) {
                if (param.getIsActive() == null) {
                    boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.SPU_TYPE, param.getSpuType()));
                } else {
                    boolQueryBuilder.filter(QueryBuilders.termsQuery(EsConstant.SPU_TYPE, param.getSpuType().toString(), 5));
                }
            } else {
                boolQueryBuilder.mustNot(QueryBuilders.termQuery(EsConstant.SPU_TYPE, SpuType.SCORE.value().toString()));
            }
        }
        // 不匹配的商品类型
        if (CollUtil.isNotEmpty(param.getMustNotProdTypes())) {
            for (Integer prodType : param.getMustNotProdTypes()) {
                boolQueryBuilder.mustNot(QueryBuilders.termQuery(EsConstant.SPU_TYPE, prodType.toString()));
            }
        }
        // 商品类别
        if (Objects.nonNull(param.getSpuMold())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.SPU_MOLD, param.getSpuMold()));
        }
        // 商品类别
        if (Objects.nonNull(param.getNotSpuMold())) {
            boolQueryBuilder.mustNot(QueryBuilders.termQuery(EsConstant.SPU_MOLD, param.getNotSpuMold()));
        }
        return statusList;
    }

    /**
     * 商品分类信息过滤
     *
     * @param param
     * @param boolQueryBuilder
     */
    private void categoryFilterQuery(ProductSearchDTO param, BoolQueryBuilder boolQueryBuilder) {
        // 商家一级分类
        if (Objects.nonNull(param.getShopPrimaryCategoryId())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.SHOP_PRIMARY_CATEGORY_ID, param.getShopPrimaryCategoryId()));
        }

        //商家二级分类
        if (Objects.nonNull(param.getShopSecondaryCategoryId())) {
            boolQueryBuilder.filter(EsSearchUtil.nestedQuery(EsConstant.SHOP_CATEGORY, EsConstant.SHOP_CATEGORY_UNION_ID, param.getShopSecondaryCategoryId()));
        }

        // 平台一级分类
        if (Objects.nonNull(param.getPrimaryCategoryId())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.PRIMARY_CATEGORY_ID, param.getPrimaryCategoryId()));
        }
        // 查询不在该集合中的商品
        if (Objects.nonNull(param.getNotPrimaryCategoryId())) {
            boolQueryBuilder.mustNot(QueryBuilders.termsQuery(EsConstant.PRIMARY_CATEGORY_ID, param.getNotPrimaryCategoryId().toString()));
        }

        // 平台二级分类
        if (Objects.nonNull(param.getSecondaryCategoryId())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.SECONDARY_CATEGORY_ID, param.getSecondaryCategoryId()));
        }

        // 平台三级分类
        if (Objects.nonNull(param.getCategoryId())) {
            boolQueryBuilder.filter(EsSearchUtil.nestedQuery(EsConstant.CATEGORY, EsConstant.CATEGORY_UNION_ID, param.getCategoryId()));
        }

        // 平台三级分类
        if (CollectionUtil.isNotEmpty(param.getCategoryIds())) {
            boolQueryBuilder.filter(EsSearchUtil.nestedQuery(EsConstant.CATEGORY, EsConstant.CATEGORY_UNION_ID, param.getCategoryIds()));
        }
    }

    public SearchResponse getLimitSpuResponse(ProductSearchLimitDTO productSearchLimitDTO) {
        Integer size = productSearchLimitDTO.getSize();
        if (Objects.isNull(size) || Objects.equals(size, 0)) {
            return null;
        }
        boolean error = CollUtil.isEmpty(productSearchLimitDTO.getShopIds())
                && CollUtil.isEmpty(productSearchLimitDTO.getBrandIds()) && CollUtil.isEmpty(productSearchLimitDTO.getTagIds());
        if (error) {
            return null;
        }

        // 每个分组最多只返回10条数据
        int maxSize = 10;
        if (size > maxSize) {
            size = maxSize;
        }
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        builderSearchSource(productSearchLimitDTO, size, searchSourceBuilder);
        SearchRequest searchRequest = new SearchRequest(new String[]{EsIndexEnum.PRODUCT.value()}, searchSourceBuilder);
        //2、执行检索请求
        return EsSearchUtil.search(searchRequest);
    }

    private void builderSearchSource(ProductSearchLimitDTO productSearchLimitDTO, Integer size, SearchSourceBuilder searchSourceBuilder) {
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        // 过滤、聚合分析
        String[] include = {EsConstant.SPU_NAME_ZH, EsConstant.SPU_NAME_EN, EsConstant.SELLING_POINT_ZH, EsConstant.SELLING_POINT_EN, EsConstant.MAIN_IMG_URL, EsConstant.SHOP_ID, EsConstant.BRAND_ID, EsConstant.SPU_ID, EsConstant.PRICE_FEE, EsConstant.MARKET_PRICE_FEE, EsConstant.SPU_STATUS, EsConstant.SUPPLIER_SPU_TYPE};
        TermsAggregationBuilder term = null;
        TopHitsAggregationBuilder topHitsAggregationBuilder = AggregationBuilders
                .topHits(EsConstant.TOP_HITS_DATA)
                .fetchSource(include, null)
                .size(size);
        // 店铺
        if (CollUtil.isNotEmpty(productSearchLimitDTO.getShopIds())) {
            boolQueryBuilder.filter(QueryBuilders.termsQuery(EsConstant.SHOP_ID, productSearchLimitDTO.getShopIds()));
            term = AggregationBuilders.terms(EsConstant.SPU_LIST).field(EsConstant.SHOP_ID);
        }
        // 品牌
        if (CollUtil.isNotEmpty(productSearchLimitDTO.getBrandIds())) {
            boolQueryBuilder.filter(QueryBuilders.termsQuery(EsConstant.BRAND_ID, productSearchLimitDTO.getBrandIds()));
            term = AggregationBuilders.terms(EsConstant.SPU_LIST).field(EsConstant.BRAND_ID);
        }
        //不显示供应商商品
        boolQueryBuilder.mustNot(QueryBuilders.termQuery(EsConstant.SUPPLIER_SPU_TYPE, SupplierSpuType.YES.value()));
        //不显示活动商品
        boolQueryBuilder.mustNot(QueryBuilders.termQuery(EsConstant.SPU_TYPE, SpuType.ACTIVE.value()));
        if (CollUtil.isNotEmpty(productSearchLimitDTO.getShopIds()) || CollUtil.isNotEmpty(productSearchLimitDTO.getBrandIds())) {
            // 商品按销量倒序
            topHitsAggregationBuilder.sort(EsConstant.SALE_NUM, SortOrder.DESC);
            Objects.requireNonNull(term).subAggregation(topHitsAggregationBuilder);
            searchSourceBuilder.aggregation(term);
        }
        boolQueryBuilder.filter(QueryBuilders.termsQuery(EsConstant.APP_DISPLAY, Boolean.TRUE));
        searchSourceBuilder.query(boolQueryBuilder);
        searchSourceBuilder.size(0);
        log.info("构建的DSL语句 {}", searchSourceBuilder);
    }

    public void supplierSpuTypeFilterQuery(ProductSearchDTO param, BoolQueryBuilder boolQueryBuilder) {
        if (!Objects.isNull(param.getSupplierSpuType())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.SUPPLIER_SPU_TYPE, param.getSupplierSpuType()));
        }
        if (Objects.equals(param.getIsSupplierType(), 1)) {
            boolQueryBuilder.mustNot(QueryBuilders.termQuery(EsConstant.SUPPLIER_SPU_TYPE, param.getIsSupplierType()));
        }
    }

    public void supplierIdFilterQuery(ProductSearchDTO param, BoolQueryBuilder boolQueryBuilder) {
        if (!Objects.isNull(param.getSupplierIds())) {
            boolQueryBuilder.filter(QueryBuilders.termsQuery(EsConstant.SUPPLIER_ID, param.getSupplierIds()));
            boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.SUPPLIER_SPU_TYPE, EsSupplierSpuStatus.SUPPLIER_SPU.value()));
        }

    }

    public void commissionSpuStatusFilterQuery(ProductSearchDTO param, BoolQueryBuilder boolQueryBuilder) {
        if (!Objects.isNull(param.getCommissionSpuStatus())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.COMMISSION_SPU_STATUS, param.getCommissionSpuStatus()));
        }
    }

    public void supplierNameFilterQuery(ProductSearchDTO param, BoolQueryBuilder boolQueryBuilder) {
        if (!Objects.isNull(param.getSupplierName()) && !Objects.equals(param.getSupplierName(), "")) {
//            if (!Objects.isNull(param.getCommissionSpuStatus())){
            boolQueryBuilder.filter(QueryBuilders.matchQuery(EsConstant.SUPPLIER_NAME, param.getSupplierName()));
//            }
        }
    }

    public void skuCodeFilterQuery(ProductSearchDTO param, BoolQueryBuilder boolQueryBuilder) {
        if (!Objects.isNull(param.getSkuCode()) && !Objects.equals(param.getSkuCode(), "")) {
            boolQueryBuilder.filter(QueryBuilders.matchQuery(EsConstant.PARTY_CODE, param.getSkuCode()));
        }
    }

    public void spuMoldFilterQuery(ProductSearchDTO param, BoolQueryBuilder boolQueryBuilder) {
        if (Objects.nonNull(param.getIsVirtual())) {
            boolQueryBuilder.mustNot(QueryBuilders.termQuery(EsConstant.SPU_MOLD, SpuMold.VIRTUAL.value()));
        }
        if (Objects.equals(param.getIsSupplierDelivery(), 1)) {
            boolQueryBuilder.mustNot(QueryBuilders.termQuery(EsConstant.SUPPLIER_SPU_TYPE, SupplierSpuType.YES.value()));
            boolQueryBuilder.mustNot(QueryBuilders.termQuery(EsConstant.SUPPLIER_DELIVERY_TYPE, SupplierDeliveryType.SUPPLIER_DELIVERY.value()));
        }
    }

    public void supplierStatusFilterQuery(ProductSearchDTO param, BoolQueryBuilder boolQueryBuilder) {
        if (Objects.nonNull(param.getShopQuerySupplierSpu()) && param.getShopQuerySupplierSpu()) {
            List<Integer> supplierSpuStatus = new ArrayList<>(Constant.INITIAL_CAPACITY);
            //只查询状态为上架或者下架的供应商品,
            supplierSpuStatus.add(StatusEnum.DISABLE.value());
            supplierSpuStatus.add(StatusEnum.ENABLE.value());
            boolQueryBuilder.filter(QueryBuilders.termsQuery(EsConstant.SPU_STATUS, supplierSpuStatus));
        }
    }
}
