package shop.alien.store.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.elasticsearch.action.DocWriteResponse;
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.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.List;
import java.util.UUID;

/**
 * @author ssk
 * @version 1.0
 * @date 2025/4/22 9:10
 */
@Slf4j
@Component
@RefreshScope
public class ElasticSearchComponent {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Value("${spring.elasticsearch.rest.uris}")
    private String elasticSearchUrl;

    /**
     * 创建客户端
     */
    @PostConstruct
    public void init() {
        HttpHost host = HttpHost.create(elasticSearchUrl);
        RestClientBuilder builder = RestClient.builder(host);
        restHighLevelClient = new RestHighLevelClient(builder);
        log.info("ElasticSearchComponent.init 客户端已打开");
    }

    /**
     * 关闭客户端
     */
    @PreDestroy
    public void close() {
        try {
            restHighLevelClient.close();
            log.info("ElasticSearchComponent.init 客户端已关闭");
        } catch (Exception e) {
            log.error("ElasticSearchComponent.close ERROR Msg={}", e.getMessage());
        }
    }

    /**
     * 创建索引
     *
     * @param indexName 索引名称
     * @return boolean
     */
    public boolean createIndex(String indexName) {
        try {
            CreateIndexRequest request = new CreateIndexRequest(indexName);
            restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
            return true;
        } catch (Exception e) {
            log.error("ElasticSearchComponent.createIndex ERROR Msg={}", e.getMessage());
            return false;
        }
    }

    /**
     * 创建索引
     *
     * @param indexName 索引名称
     * @param json      分词器json
     * @return boolean
     */
    public boolean createIndex(String indexName, String json) {
        try {
            //在通过ES客户端创建索引
            CreateIndexRequest request = new CreateIndexRequest(indexName);
            //设置请求中的参数（添加分词器）
            request.source(json, XContentType.JSON);
            restHighLevelClient.indices().create(request, RequestOptions.DEFAULT);
            return true;
        } catch (Exception e) {
            log.error("ElasticSearchComponent.createIndex ERROR Msg={}", e.getMessage());
            return false;
        }
    }


    /**
     * 删除索引
     *
     * @param indexName 索引库名
     * @return boolean
     */
    public boolean deleteIndex(String indexName) {
        try {
            DeleteIndexRequest request = new DeleteIndexRequest(indexName);
            restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
            return true;
        } catch (Exception e) {
            log.error("ElasticSearchComponent.deleteIndex ERROR Msg={}", e.getMessage());
            return false;
        }
    }

    /**
     * 添加文档-单条
     *
     * @param indexName 索引名称
     * @param t         单个实体类
     * @return boolean
     */
    public <T> boolean createIndexDocOne(String indexName, T t) {
        try {
            String json = JSON.toJSONString(t);
            //指定添加的文档的id为getId()/uuid，需要添加文档的索引为indexName
            IndexRequest request = new IndexRequest(indexName);
            //传入数据
            request.source(json, XContentType.JSON);
            IndexResponse index = restHighLevelClient.index(request, RequestOptions.DEFAULT);
            DocWriteResponse.Result result = index.getResult();
            return result == DocWriteResponse.Result.CREATED;
        } catch (Exception e) {
            log.error("ElasticSearchComponent.createIndexDocOne ERROR Msg={}", e.getMessage());
            return false;
        }
    }

    /**
     * 添加文档-多条
     *
     * @param indexName 索引名称
     * @param t         单个实体类
     * @return boolean
     */
    public <T> boolean createIndexDocMore(String indexName, List<T> t) {
        try {
            //BulkRequest的对象，可以将该对象理解为是一个保存request对象的容器，
            //将所有的请求都初始化好后，添加到BulkRequest对象中，再使用BulkRequest对象的bulk方法，一次性执行完毕
            BulkRequest bulk = new BulkRequest();
            for (T t1 : t) {
                String json = JSON.toJSONString(t1);
                //指定添加的文档的id为getId()/uuid，需要添加文档的索引为indexName
                IndexRequest request = new IndexRequest(indexName).id(UUID.randomUUID().toString());
                //传入数据
                request.source(json, XContentType.JSON);
                //把数据放进BulkRequest对象里面
                bulk.add(request);
            }
            BulkResponse bulk1 = restHighLevelClient.bulk(bulk, RequestOptions.DEFAULT);
            return !bulk1.hasFailures();
        } catch (Exception e) {
            log.error("ElasticSearchComponent.createIndexDocMore ERROR Msg={}", e.getMessage());
            return false;
        }
    }

    /**
     * 查询文档
     *
     * @param indexName 索引名称
     * @param id        文档id
     * @return JSONObject
     */
    public JSONObject getDoc(String indexName, String id) {
        try {
            // 根据id查询
//            GetRequest request = new GetRequest(indexName, id);
            GetRequest request = new GetRequest();
            GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);
            //获取查询到的数据中的source属性的数据
            String json = response.getSourceAsString();
            return JSON.parseObject(json);
        } catch (Exception e) {
            log.error("ElasticSearchComponent.getDoc ERROR Msg={}", e.getMessage());
            return null;
        }
    }

    /**
     * 搜索文档
     *
     * @param indexName 索引名称
     * @param fieldName 字段名称
     * @param content   查询内容
     * @return JSONArray
     */
    public JSONArray searchDoc(String indexName, String fieldName, String content) {
        try {
            SearchRequest request = new SearchRequest(indexName);
            //创建条件查询对象
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            //设置查询条件,对指定字段执行精确匹配查询。
//            searchSourceBuilder.query(QueryBuilders.termQuery(fieldName, content));
            //对指定字段执行全文搜索查询。默认会对文本进行分词处理，然后进行搜索。
            searchSourceBuilder.query(QueryBuilders.matchQuery(fieldName, content));
            //把查询条件放进请求中
            request.source(searchSourceBuilder);
            //根据请求获取返回数据
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            //获取返回数据里面的hits属性（获取的具体属性，可以看上面的postman操作）
            SearchHits hits = response.getHits();
            JSONArray jsonArray = new JSONArray();
            for (SearchHit hit : hits) {
                String source = hit.getSourceAsString();
                jsonArray.add(JSON.parseObject(source));
            }
            return jsonArray;
        } catch (Exception e) {
            log.error("ElasticSearchComponent.searchDoc ERROR Msg={}", e.getMessage());
            return null;
        }
    }


}