package com.bawei.mall.search.es.service;

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson2.JSONObject;
import com.bawei.common.core.exception.ServiceException;
import com.bawei.common.core.utils.reflect.ReflectUtils;
import com.bawei.mall.product.domain.reponse.ProductInfoResponse;
import com.bawei.mall.search.es.instance.EsInstance;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.xcontent.XContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;

/**
 * @author DongZl
 * @description: Es操作数据
 * @Date 2022-10-14 下午 02:09
 */
@Service
public class EsDataService {

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


    private final EsInstance clientInstance;

    public EsDataService (EsInstance clientInstance) {
        this.clientInstance = clientInstance;
    }

    /**
     * 商品搜索
     * 1、索引的类型、结构
     * 2、同步数据（全量、增量）
     * 3、搜索方式
     * 4、数据维护
     */
    /**
     * 进行添加数据
     * @param index 索引
     * @param dataJson 数据json
     * @return
     */
    public boolean insertOrUpdate(String index , ProductInfoResponse dataJson){
        JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(dataJson));
        jsonObject.put("createTime", dataJson.getCreateTime().getTime());
        IndexRequest indexRequest = clientInstance.indexRequestBuilder(index).source(
                jsonObject.toJSONString(),
                XContentType.JSON
        );
        try {
            IndexResponse indexResponse = clientInstance.getClient().index(
                    indexRequest, RequestOptions.DEFAULT
            );
            RestStatus status = indexResponse.status();
            if (status.getStatus() == RestStatus.OK.getStatus()){
                return true;
            }
        } catch (IOException e) {
            log.info("索引数据添加异常：[{},{}]",index,dataJson);
            throw new ServiceException(e.getMessage());
        }
        return false;
    }

    /**
     * 批量数据
     * @param index
     * @param dataList
     * @return
     */
    public boolean bulkInsertOrUpdate(String index , List<?> dataList){
        BulkRequest bulkRequest = new BulkRequest();
        dataList.forEach( data -> bulkRequest.add(
                clientInstance.indexRequestBuilder(index).source(
                        JSONObject.toJSONString(data),
                        XContentType.JSON
                ).id(ReflectUtils.invokeGetter(data,"id").toString())
        ));
        try {
            BulkResponse bulkItemResponses =
                    clientInstance.getClient().bulk(bulkRequest, RequestOptions.DEFAULT);
            BulkItemResponse[] bulkResponse = bulkItemResponses.getItems();
            for (BulkItemResponse bulkItemResponse : bulkResponse) {
                DocWriteResponse itemResponse = bulkItemResponse.getResponse();
                switch (bulkItemResponse.getOpType()) {
                    case INDEX:
                    case CREATE:
                        IndexResponse indexResponse = (IndexResponse) itemResponse;
                        RestStatus createStatus = indexResponse.status();
                        if (createStatus.getStatus() != RestStatus.CREATED.getStatus()
                        && createStatus.getStatus() != RestStatus.OK.getStatus() ){
                            log.error("请求失败: 索引：[{}] , itemId:[{}]",
                                    bulkItemResponse.getIndex(),
                                    bulkItemResponse.getItemId());
                        }
                        break;
                    case UPDATE:
                        UpdateResponse updateResponse = (UpdateResponse) itemResponse;
                        RestStatus updateStatus = updateResponse.status();
                        if (updateStatus.getStatus() != RestStatus.OK.getStatus()){
                            log.error("请求失败: 索引：[{}] , itemId:[{}]",
                                    bulkItemResponse.getIndex(),
                                    bulkItemResponse.getItemId());
                        }
                        break;
                    case DELETE:
                        DeleteResponse deleteResponse = (DeleteResponse) itemResponse;
                        RestStatus deleteStatus = deleteResponse.status();
                        if (deleteStatus.getStatus() != RestStatus.OK.getStatus()){
                            log.error("请求失败: 索引：[{}] , itemId:[{}]",
                                    bulkItemResponse.getIndex(),
                                    bulkItemResponse.getItemId());
                        }
                }
            }
        } catch (IOException e) {
            log.info("批量请求异常", e);
            throw new ServiceException(e.getMessage());
        }
        return true;
    }

    /**
     * 删除索引
     * @param index
     * @param docId
     * @return
     */
    public boolean deleteByDocId(String index, String docId){
        DeleteRequest deleteRequest = clientInstance.DeleteRequestBuilder(index).id(docId);
        try {
            DeleteResponse deleteResponse = clientInstance.getClient().delete(deleteRequest, RequestOptions.DEFAULT);
            RestStatus status = deleteResponse.status();
            if (status.getStatus() == RestStatus.OK.getStatus()){
                return true;
            }
        } catch (IOException e) {
            log.error("文档删除出现异常 索引：[{}]，文档：[{}]", index , docId, e);
            throw new ServiceException(e.getMessage());
        }
        return false;
    }
}
