package com.bawei.es.service.impl;

import com.bawei.common.core.exception.ServiceException;
import com.bawei.common.core.utils.StringUtils;
import com.bawei.es.service.EsIndexService;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.cluster.metadata.MappingMetadata;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xcontent.XContentFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

@Service
public class EsIndexServiceImpl implements EsIndexService {
    @Resource
    private RestHighLevelClient restHighLevelClient;
    private static final Logger logger = LoggerFactory.getLogger(EsIndexService.class);

    @Override
    public boolean findIndex(String indexName) {
        if (indexName == null || indexName.isEmpty()){
            throw new ServiceException("索引名称不能为空");
        }
        try {
            GetIndexRequest request = new GetIndexRequest(indexName);
            GetIndexResponse response = restHighLevelClient.indices().get(request, RequestOptions.DEFAULT);
            // 直接使用 response.indices() 是否包含 indexName 来判断
            String[] indices = response.getIndices();
            for (String index : indices) {
                if (index.equals(indexName)) {
                    return true;
                }
            }
            return false;
        } catch (Exception e) {
            // 特别处理 index_not_found_exception
            if (e.getMessage().contains("no such index")) {
                logger.info("索引 [{}] 不存在", indexName);
                return false;
            } else {
                // 记录其他类型的异常
                logger.error("查询索引 [{}] 状态时发生错误: {}", indexName, e.getMessage(), e);
                throw new ServiceException("查询索引状态时发生错误");
            }
        }
    }

    @Override
    public boolean createIndex(String indexName, Map<String,Object> docMsg) {
        if (StringUtils.isBlank(indexName)) {
            throw new ServiceException("索引名称不可为空");
        }
        // 判断索引是否存在
        boolean index = this.findIndex(indexName);
        if(index){
            throw new ServiceException("索引" + indexName + "已存在");
        }
        try {
            //
            Settings.Builder settingsBuilder = Settings.builder();
            XContentBuilder mappingBuilder = null;

            if(docMsg != null && !docMsg.isEmpty()){
                mappingBuilder = createMapping(docMsg);
            }
            CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName)
                    .settings(settingsBuilder);
            if(mappingBuilder != null){
                createIndexRequest.mapping(mappingBuilder);
            }
            CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
            return createIndexResponse.isAcknowledged();
        }
        catch (IOException e) {
            System.out.println("创建索引时发生错误: " + e.getMessage());
            throw new ServiceException("创建索引时发生错误");
        }
    }

    /**
     * 创建文档映射
     * @param docMsg 包含文档字段及其类型的映射
     * @return XContentBuilder 对象，包含构建的文档映射结构
     * @throws IOException 如果构建过程中发生IO异常
     */
    private XContentBuilder createMapping(Map<String,Object> docMsg) throws IOException {
        // 初始化XContentBuilder对象，开始构建JSON对象
        XContentBuilder xContentBuilder = XContentFactory.jsonBuilder()
                .startObject()
                .startObject("properties");

        // 遍历docMsg，为每个字段构建映射
        for (Map.Entry<String, Object> entry : docMsg.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            xContentBuilder.startObject(key);

            if(value instanceof Map){
                // 如果字段值是Map类型，则递归处理
                Map<String,Object> stringObjectMap = (Map<String, Object>) value;
                // 遍历内部映射，添加到当前字段
                for (Map.Entry<String, Object> stringObjectEntry : stringObjectMap.entrySet()) {
                    String key1 = stringObjectEntry.getKey();
                    Object value1 = stringObjectEntry.getValue();
                    xContentBuilder.field(key1,value1);
                }
            }else {
                // 如果字段值不是Map类型，将其作为类型字段添加
                xContentBuilder.field("type",value.toString());
            }
            xContentBuilder.endObject();
        }
        // 结束"properties"对象和整个JSON对象的构建
        xContentBuilder.endObject().endObject();
        return xContentBuilder;
    }


    @Override
    public boolean deleteIndex(String indexName) {
        // 判空
        if(StringUtils.isBlank(indexName)){
            throw new ServiceException("索引名称不可为空");
        }
        // 删除索引
        try {
            restHighLevelClient.indices().delete(new DeleteIndexRequest(indexName), RequestOptions.DEFAULT);
            return true;
        } catch (Exception e) {
            System.err.println("删除索引失败: " + e.getMessage());
            throw new ServiceException("删除索引失败");
        }
    }

    @Override
    public Map<String, Object> getMapping(String indexName) {
        if(StringUtils.isBlank(indexName)){
            throw new RuntimeException("索引名称不能为空");
        }
        // 创建索引请求
        GetIndexRequest getIndexRequest = new GetIndexRequest(indexName);
        try {
            // 获取索引
            GetIndexResponse getIndexResponse = restHighLevelClient.indices().get(getIndexRequest, RequestOptions.DEFAULT);
            for (String index : getIndexResponse.getIndices()) {
                // 判断索引
                if(index.equals(indexName)){
                    // 获取映射
                    Map<String, MappingMetadata> mappings = getIndexResponse.getMappings();
                    MappingMetadata mappingMetadata = mappings.get(indexName);
                    // 判断映射是否为空
                    if(mappingMetadata != null){
                        // 获取映射
                        Map<String,Object> properties = (Map<String, Object>) mappingMetadata.getSourceAsMap().get("properties");
                        // 判断映射是否为空
                        if(properties == null){
                            throw new ServiceException("索引映射为空");
                        }
                        // 返回映射
                        return properties;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        throw new ServiceException("索引不存在,请重试");
    }

    @Override
    public boolean updateIndex(String indexName, Map<String, Object> docMsg) {
        try {
            if (indexName!=null && !indexName.isEmpty()){
                if (Boolean.FALSE.equals(findIndex(indexName))) {
                    createIndex(indexName,docMsg);
                    return true;
                }else {
                    deleteIndex(indexName);
                    createIndex(indexName,docMsg);
                    return true;
                }
            }else {
                throw new ServiceException("索引名字为空,请重试!!!");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
