package com.tmerclub.cloud.search.manager;

import com.tmerclub.cloud.api.product.dto.WarehouseSearchDTO;
import com.tmerclub.cloud.api.product.feign.WarehouseFeignClient;
import com.tmerclub.cloud.common.order.vo.WarehouseVO;
import com.tmerclub.cloud.api.dto.EsPageDTO;
import com.tmerclub.cloud.api.order.bo.EsAllotOrderBO;
import com.tmerclub.cloud.api.vo.EsPageVO;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.order.dto.AllotOrderSearchDTO;
import com.tmerclub.cloud.common.order.vo.EsAllotOrderVO;
import com.tmerclub.cloud.common.util.BeanUtil;
import com.tmerclub.cloud.common.util.Json;
import com.tmerclub.cloud.search.constant.EsIndexEnum;
import org.apache.dubbo.config.annotation.DubboReference;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 调拨订单搜索管理
 * @author gaozijie
 * @since 2023-11-27
 */
@Component
public class AllotOrderSearchManager {

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

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @DubboReference
    private WarehouseFeignClient warehouseFeignClient;

    /**
     * 通过搜索信息分页搜索es数据的信息
     *
     * @param param 退款订单搜索条件
     * @return 搜索结果
     */
    public EsPageVO<EsAllotOrderVO> page(EsPageDTO pageDTO, AllotOrderSearchDTO param) {
        param.setPageSize(pageDTO.getPageSize());
        param.setPageNum(pageDTO.getPageNum());
        EsPageVO<EsAllotOrderVO> allotOrderPage = pageSearchResult(param);
        this.fillInfo(allotOrderPage.getList());
        return allotOrderPage;
    }

    /**
     * 补充信息
     * @param allotOrders 调拨订单集合
     */
    private void fillInfo(List<EsAllotOrderVO> allotOrders) {
        if (CollectionUtils.isEmpty(allotOrders)) {
            return;
        }
        // 补充仓库名称
        Set<Long> warehouseIds = new HashSet<>(Constant.INITIAL_CAPACITY);
        for (EsAllotOrderVO allotOrder : allotOrders) {
            warehouseIds.add(allotOrder.getOutWarehouseId());
            warehouseIds.add(allotOrder.getInWarehouseId());
        }
        WarehouseSearchDTO warehouseSearchDTO = new WarehouseSearchDTO();
        warehouseSearchDTO.setWarehouseIds(new ArrayList<>(warehouseIds));
        List<WarehouseVO> warehouses = warehouseFeignClient.listWarehouse(warehouseSearchDTO);
        Map<Long, String> warehouseMap = new HashMap<>(Constant.INITIAL_CAPACITY);
        if (!CollectionUtils.isEmpty(warehouses)) {
            warehouseMap = warehouses.stream().collect(Collectors.toMap(WarehouseVO::getWarehouseId, WarehouseVO::getWarehouseName));
        }
        for (EsAllotOrderVO allotOrder : allotOrders) {
            allotOrder.setOutWarehouseName(warehouseMap.getOrDefault(allotOrder.getOutWarehouseId(), ""));
            allotOrder.setInWarehouseName(warehouseMap.getOrDefault(allotOrder.getInWarehouseId(), ""));
        }
    }

    /**
     * 通过搜索信息分页搜索es数据的信息
     *
     * @param param 退款订单搜索条件
     * @return 搜索结果
     */
    public EsPageVO<EsAllotOrderVO> pageSearchResult(AllotOrderSearchDTO param) {
        if (Objects.isNull(param.getPageNum())) {
            param.setPageNum(1);
        }
        if (Objects.isNull(param.getPageSize())) {
            param.setPageSize(10);
        }
        //1、查询订单数据
        SearchResponse response = this.searchResult(param);
        //2.处理响应的数据
        return this.pageEsOrderBO(response, param.getPageSize());
    }

    private EsPageVO<EsAllotOrderVO> pageEsOrderBO(SearchResponse response, Integer pageSize) {
        EsPageVO<EsAllotOrderVO> pageVO = new EsPageVO<>();
        List<EsAllotOrderVO> allotOrders = new ArrayList<>(Constant.INITIAL_CAPACITY);
        EsAllotOrderBO allotOrder;
        for (SearchHit hit : response.getHits().getHits()) {
            allotOrder = Json.parseObject(hit.getSourceAsString(), EsAllotOrderBO.class);
            allotOrders.add(BeanUtil.map(allotOrder, EsAllotOrderVO.class));
        }
        pageVO.setList(allotOrders);
        buildSearchPage(pageVO, response, pageSize);
        return pageVO;
    }

    /**
     * 构建分页数据
     *
     * @param esPageVO
     * @param response
     * @param pageSize
     */
    private void buildSearchPage(EsPageVO<?> esPageVO, SearchResponse response, Integer pageSize) {
        //总记录数
        long total = response.getHits().getTotalHits().value;
        esPageVO.setTotal(total);
        // 总页码
        int totalPages = (int) total % pageSize == 0 ?
                (int) total / pageSize : ((int) total / pageSize + 1);
        esPageVO.setPages(totalPages);
    }

    /**
     * 搜索结果
     * @param param 搜索参数
     * @return es搜索响应数据
     */
    private SearchResponse searchResult(AllotOrderSearchDTO param) {
        // 封装检索条件
        SearchRequest searchRequest = this.buildSearchRequest(param);
        SearchResponse response;
        try {
            //2、执行检索请求
            response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            log.info("搜索返回结果：{}", response.toString());
        } catch (IOException e) {
            log.error(e.toString());
            throw new LuckException("搜索服务出了点小差，请稍后再试", e);
        }
        return response;
    }

    /**
     * 准备检索请求
     *
     * @param param 搜索参数
     * @return es搜索请求
     */
    private SearchRequest buildSearchRequest(AllotOrderSearchDTO param) {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 构建bool-query
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
        // 过滤
        this.filterQueryIfNecessary(param, boolQueryBuilder);
        // 排序
        this.sort(searchSourceBuilder, boolQueryBuilder);
        if (Objects.nonNull(param.getPageNum()) && Objects.nonNull(param.getPageSize())) {
            //分页
            searchSourceBuilder.from((param.getPageNum() - 1) * param.getPageSize());
            searchSourceBuilder.size(param.getPageSize());
        }
        log.info("构建的DSL语句 {}", searchSourceBuilder);
        return new SearchRequest(new String[]{EsIndexEnum.ALLOT_ORDER.value()}, searchSourceBuilder);
    }

    /**
     * 过滤查询条件，如果有必要的话
     *
     * @param param            查询条件
     * @param boolQueryBuilder 组合进boolQueryBuilder
     */
    private void filterQueryIfNecessary(AllotOrderSearchDTO param, BoolQueryBuilder boolQueryBuilder) {
        // 店铺id
        if (Objects.nonNull(param.getShopId())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("shopId", param.getShopId()));
        }
        // 系统类型
        if (Objects.nonNull(param.getSysType())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("sysType", param.getSysType()));
        }
        // 调拨订单id
        if (Objects.nonNull(param.getAllotOrderId())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("allotOrderId", param.getAllotOrderId()));
        }
        // 状态 0:已作废 1:待入库 2.部分入库 3:已完成
        if (Objects.nonNull(param.getStatus())) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("status", param.getStatus()));
        }
    }

    /**
     * 进行排序
     */
    private void sort(SearchSourceBuilder searchSourceBuilder, BoolQueryBuilder boolQueryBuilder) {
        searchSourceBuilder.sort("createTime", SortOrder.DESC);
        searchSourceBuilder.query(boolQueryBuilder);
    }
}
