package com.infynova.udi.service.helper;

import com.infynova.udi.mapper.UdiMapper;
import com.infynova.udi.vo.UdiMatchRateVo;
import com.infynova.udi.vo.UdiVo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

/**
 * @author liudong
 * 2024/4/29 16:16
 * @version 1.0
 */
@Slf4j
@Component
public class EsSearchHelper {

    private static final String INDEX_NAME = "udi";

    public static final RestHighLevelClient client;

    static{
        client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("localhost",9200,"http"))
        );
    }

    @SneakyThrows
    public CreateIndexResponse createIndex(){
        log.info("创建索引");
        CreateIndexRequest createIndexRequest = new CreateIndexRequest(INDEX_NAME);
        // 设置映射
        createIndexRequest.mapping(
                "{" +
                "  \"properties\": {" +
                "    \"id\": {" +
                "      \"type\": \"long\"" +
                "    }," +
                "    \"companyName\": {" +
                "      \"type\": \"text\"," +
                "      \"analyzer\": \"ik_max_word\"," +
                "      \"search_analyzer\": \"ik_smart\"" +
                "    }," +
                "    \"productFactoryCode\": {" +
                "      \"type\": \"text\"," +
                "      \"analyzer\": \"ik_max_word\"," +
                "      \"search_analyzer\": \"ik_smart\"" +
                "    }," +
                "    \"brandName\": {" +
                "      \"type\": \"text\"," +
                "      \"analyzer\": \"ik_max_word\"," +
                "      \"search_analyzer\": \"ik_smart\"" +
                "    }," +
                "    \"productName\": {" +
                "      \"type\": \"text\"," +
                "      \"analyzer\": \"ik_max_word\"," +
                "      \"search_analyzer\": \"ik_smart\"" +
                "    }," +
                "    \"specification\": {" +
                "      \"type\": \"text\"," +
                "      \"analyzer\": \"ik_max_word\"," +
                "      \"search_analyzer\": \"ik_smart\"" +
                "    }," +
                "    \"model\": {" +
                "      \"type\": \"text\"," +
                "      \"analyzer\": \"ik_max_word\"," +
                "      \"search_analyzer\": \"ik_smart\"" +
                "    }" +
                "  }" +
                "}"
                ,XContentType.JSON
        );
        
        CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
        return createIndexResponse;
    }

    @SneakyThrows
    public AcknowledgedResponse deleteIndex(){
        log.info("删除索引");
        DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(INDEX_NAME);
        AcknowledgedResponse delete = client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
        return delete;
    }

    @Resource
    private UdiMapper udiMapper;

    @SneakyThrows
    public void initData(){
        log.info("同步数据");
        StopWatch stopWatch = new StopWatch("开始");
        Integer pageSize = 5000;
        Long lastId = 0L;
        int i = 1;
        try{
            while (true){
                stopWatch.start("第"+i+"页");
                log.info("同步索引:第{}页,lastId:{}",i,lastId);
                List<UdiVo> records = udiMapper.getUdiIdPage(lastId,pageSize);
                if(CollectionUtils.isEmpty(records)){
                    return;
                }
                this.indexDocument(records);
                UdiVo udiVo = records.get(records.size()-1);
                lastId = udiVo.getId();
                i++;
                stopWatch.stop();
            }
        }catch (Exception e){
            log.error("");
            log.error("",e);
        }finally {
            stopWatch.stop();
            log.info(stopWatch.prettyPrint());
            log.info("总计耗时:{}",stopWatch.getTotalTimeSeconds());
        }
    }

    private Map<String,Object> getDoc(UdiVo udiVo){
        Map<String,Object> map = new HashMap<>();
        map.put("id",udiVo.getId());
        map.put("companyName",udiVo.getCompanyName());
        map.put("productFactoryCode",udiVo.getProductFactoryCode());
        map.put("brandName",udiVo.getBrandName());
        map.put("productName",udiVo.getProductName());
        map.put("specification",udiVo.getSpecification());
        map.put("model",udiVo.getModel());
        return map;
    }

    public void indexDocument(List<UdiVo> udiVos) throws IOException {
        BulkRequest bulkRequest = new BulkRequest();
        for (UdiVo udiVo : udiVos) {
            Map<String, Object> doc = getDoc(udiVo);
            IndexRequest request = new IndexRequest(INDEX_NAME)
                    .id(String.valueOf(udiVo.getId()))
                    .source(doc, XContentType.JSON);
            bulkRequest.add(request);
        }
        BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        if (bulkResponse.hasFailures()) {
            // 处理失败的情况
            log.error("Some documents failed to index: " + bulkResponse.buildFailureMessage());
        } else {
            log.info("Bulk indexing successful.");
        }
    }

    @SneakyThrows
    public Map<String, Object> getId(String id){
        GetRequest getRequest = new GetRequest(INDEX_NAME, id);
        GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);
        return getResponse.getSourceAsMap();
    }

    @SneakyThrows
    public SearchResponse searchThree(String companyName,String productFactoryCode){
        if(StringUtils.isBlank(companyName) && StringUtils.isBlank(productFactoryCode)){
            return null;
        }
        SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
        // 构建查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if(StringUtils.isNotBlank(companyName)){
            boolQueryBuilder.should(new MatchQueryBuilder("companyName", companyName))
                    .should(new TermQueryBuilder("companyName.keyword", companyName));
        }
        // boost 倾向性:查询时倾向于productFactoryCode
        if(StringUtils.isNotBlank(productFactoryCode)){
            boolQueryBuilder.should(new MatchQueryBuilder("productFactoryCode", productFactoryCode).boost(2))
                    .should(new TermQueryBuilder("productFactoryCode.keyword", productFactoryCode).boost(2));
        }

        // 构建搜索源
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().query(boolQueryBuilder);

        // 设置搜索请求的源
        searchRequest.source(searchSourceBuilder);
        // 执行搜索
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        return searchResponse;
    }

    /**
     * 规则三
     * @param companyName 企业名称
     * @param productFactoryCode 产品厂家编码
     */
    public List<UdiMatchRateVo> threeQuery(String companyName, String productFactoryCode){
        List<UdiMatchRateVo> resultList = new ArrayList<>();
        SearchResponse searchResponse = searchThree(companyName, productFactoryCode);
        if(Objects.isNull(searchResponse)){
            return new ArrayList<>();
        }
        // 处理搜索结果
        SearchHit[] searchHits = searchResponse.getHits().getHits();
        for (SearchHit hit : searchHits) {
            UdiMatchRateVo udiMatchRateVo = new UdiMatchRateVo();
            Long idQuery = Long.valueOf(hit.getSourceAsMap().get("id").toString());
            String companyNameQuery = Optional.ofNullable(hit.getSourceAsMap().get("companyName")).orElse("").toString();
            String productFactoryCodeQuery = Optional.ofNullable(hit.getSourceAsMap().get("productFactoryCode")).orElse("").toString();
            udiMatchRateVo.setId(idQuery);
            udiMatchRateVo.setCompanyName(companyNameQuery);
            udiMatchRateVo.setProductFactoryCode(productFactoryCodeQuery);
            resultList.add(udiMatchRateVo);
        }
        return resultList;
    }

    @SneakyThrows
    public SearchResponse searchFour(String brandName,String productName,String specification,String model){
        if(StringUtils.isBlank(brandName)
                && StringUtils.isBlank(productName)
                && StringUtils.isBlank(specification)
                && StringUtils.isBlank(model) ){
            return null;
        }
        SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
        // 构建查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if(StringUtils.isNotBlank(brandName)){
            boolQueryBuilder.should(new MatchQueryBuilder("brandName", brandName))
                    .should(new TermQueryBuilder("brandName.keyword", brandName));
        }
        if(StringUtils.isNotBlank(productName)){
            boolQueryBuilder.should(new MatchQueryBuilder("productName", productName))
                    .should(new TermQueryBuilder("productName.keyword", productName));
        }
        if(StringUtils.isNotBlank(specification)){
            boolQueryBuilder.should(new MatchQueryBuilder("specification", specification))
                    .should(new TermQueryBuilder("specification.keyword", specification));
        }
        if(StringUtils.isNotBlank(model)){
            boolQueryBuilder.should(new MatchQueryBuilder("model", model))
                    .should(new TermQueryBuilder("model.keyword", model));
        }

        // 构建搜索源
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().query(boolQueryBuilder);

        // 设置搜索请求的源
        searchRequest.source(searchSourceBuilder);
        // 执行搜索
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        return searchResponse;
    }

    /**
     * 规则四
     * @param brandName
     * @param productName
     * @param specification
     * @param model
     * @return
     */
    public List<UdiMatchRateVo> fourQuery(String brandName, String productName, String specification, String model){
        List<UdiMatchRateVo> resultList = new ArrayList<>();
        SearchResponse searchResponse = searchFour(brandName, productName, specification, model);
        // 处理搜索结果
        SearchHit[] searchHits = searchResponse.getHits().getHits();
        for (SearchHit hit : searchHits) {
            UdiMatchRateVo udiMatchRateVo = new UdiMatchRateVo();
            Long idQuery = Long.valueOf(hit.getSourceAsMap().get("id").toString());
            String brandNameQuery = Optional.ofNullable(hit.getSourceAsMap().get("brandName")).orElse("").toString();
            String productNameQuery = Optional.ofNullable(hit.getSourceAsMap().get("productName")).orElse("").toString();
            String specificationQuery = Optional.ofNullable(hit.getSourceAsMap().get("specification")).orElse("").toString();
            String modelQuery = Optional.ofNullable(hit.getSourceAsMap().get("model")).orElse("").toString();
            udiMatchRateVo.setId(idQuery);
            udiMatchRateVo.setBrandName(brandNameQuery);
            udiMatchRateVo.setProductName(productNameQuery);
            udiMatchRateVo.setSpecification(specificationQuery);
            udiMatchRateVo.setModel(modelQuery);
            resultList.add(udiMatchRateVo);
        }
        return resultList;
    }
}