package com.bawei.es.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.bawei.common.core.domain.R;
import com.bawei.common.core.exception.ServiceException;
import com.bawei.common.core.utils.StringUtils;
import com.bawei.es.domain.CommonMap;
import com.bawei.es.service.DocumentService;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
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.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.xcontent.XContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

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

/**
 * @Author: 31966
 * @Project: mall-product
 * @Package: com.bwie.es.service.impl
 * @ClassName: DocumentServiceImpl
 * @Description: Elasticsearch 文档服务实现类
 * @Date: 2024/4/22 20:58
 */
@Service
public class DocumentServiceImpl implements DocumentService {

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

    @Resource(name = "restHighLevelClient")
    private RestHighLevelClient restHighLevelClient;

    @Override
    public R queryList(String indexName, Map<String, Object> conditions) {
        // 验证索引名
        validateIndexName(indexName);

        // 构建搜索请求
        SearchRequest searchRequest = buildSearchRequest(indexName, conditions);

        // 执行搜索
        SearchResponse searchResponse;
        try {
            searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("Failed to execute search request", e);
            return R.fail("Query failed: " + e.getMessage());
        }

        // 解析搜索结果
        CommonMap result = processSearchResponse(searchResponse);

        return R.ok(result);
    }

    private SearchRequest buildSearchRequest(String indexName, Map<String, Object> conditions) {
        SearchRequest searchRequest = new SearchRequest(indexName);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 构造查询条件
        QueryBuilder queryBuilder = buildQueryBuilder(conditions);
        sourceBuilder.query(queryBuilder);

        // 设置分页参数
        setPaginationParameters(conditions, sourceBuilder);

        // 设置排序参数
        setSortParameters(conditions, sourceBuilder);

        // 设置高亮参数
        setHighlightParameters(conditions, sourceBuilder);

        searchRequest.source(sourceBuilder);

        // 记录搜索请求的详细信息（仅用于调试）
        log.debug("ES search request DDL: {}", sourceBuilder.toString());

        return searchRequest;
    }

    @Override
    public void batchOperation(String indexName, Map<String, Object> dataJson) {
        BulkRequest bulkRequest = new BulkRequest();

        // 根据dataJson中的key，进行批量操作
        for (Map.Entry<String, Object> entry : dataJson.entrySet()) {
            String id = entry.getKey();
            Map<String, Object> document = (Map<String, Object>) entry.getValue();

            // 示例代码仅处理索引（index）和删除（delete）操作
            IndexRequest indexRequest = new IndexRequest(indexName).id(id).source(document, XContentType.JSON);
            bulkRequest.add(indexRequest);
        }

        try {
            BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);

            // 检查批量操作结果，返回R对象
            if (bulkResponse.hasFailures()) {
                throw new ServiceException("Bulk operation failed: " + bulkResponse.buildFailureMessage());
            }
        } catch (IOException e) {
            throw new ServiceException("批量操作失败: " + e.getMessage());
        }
    }

    @Override
    public void batchDeletion(String indexName, List<String> ids) {
        // 参数校验
        validateIndexName(indexName);
        if (CollectionUtils.isEmpty(ids)) {
            throw new IllegalArgumentException("请输入需要删除的文档ID集合");
        }

        BulkRequest bulkRequest = new BulkRequest();
        // 构建批量删除请求
        for (String id : ids) {
            bulkRequest.add(new DeleteRequest(indexName, id));
        }

        try {
            // 执行批量删除操作
            BulkResponse bulkResponse = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            // 检查批量删除结果
            if (bulkResponse.hasFailures()) {
                throw new RuntimeException("批量删除失败: " + bulkResponse.buildFailureMessage());
            }
        } catch (IOException e) {
            throw new RuntimeException("执行批量删除操作时发生错误: " + e.getMessage(), e);
        }
    }

    /**
     * 校验索引名称是否为空
     * @param indexName 索引名称
     */
    private void validateIndexName(String indexName) {
        if (StringUtils.isBlank(indexName)) {
            throw new ServiceException("索引名为空,请重试!");
        }
    }

    private void setPaginationParameters(Map<String, Object> conditions, SearchSourceBuilder sourceBuilder) {
        // 从条件中获取分页信息
        Map<String, Object> pagination = (Map<String, Object>) conditions.get("pagination");
        if (pagination == null) {
            // 如果没有分页信息，则不设置分页参数
            return;
        }

        // 校验并获取分页参数
        int page;
        int limit;
        try {
            page = Integer.parseInt(pagination.getOrDefault("page", "1").toString());
            limit = Integer.parseInt(pagination.getOrDefault("limit", "10").toString());
        } catch (NumberFormatException e) {
            // 如果分页参数不是整数，则抛出异常
            throw new IllegalArgumentException("Invalid pagination parameters: page and limit must be integers", e);
        }

        // 设置分页参数
        int from = (page - 1) * limit;
        sourceBuilder.from(from).size(limit);

        // 记录日志（可选，根据实际需求决定是否记录）
        log.debug("Pagination parameters set: page={}, limit={}, from={}", page, limit, from);
    }

    private void setSortParameters(Map<String, Object> conditions, SearchSourceBuilder sourceBuilder) {
        Map sort = (Map) conditions.get("sort");
        if (sort != null) {
            Object sortOrderObject = sort.get("sortOrder");
            Object fieldObject = sort.get("field");

            if (sortOrderObject instanceof String && fieldObject instanceof String) {
                String sortOrder = (String) sortOrderObject;
                String field = (String) fieldObject;

                if ("asc".equalsIgnoreCase(sortOrder) || "desc".equalsIgnoreCase(sortOrder)) {
                    SortOrder sortOrderEnum = "asc".equalsIgnoreCase(sortOrder) ? SortOrder.ASC : SortOrder.DESC;
                    log.info("Applying sort: field={}, sortOrder={}", field, sortOrder);
                    sourceBuilder.sort(field, sortOrderEnum);
                } else {
                    SortOrder sortOrderEnum = SortOrder.ASC;
                    log.info("Applying sort: field={}, sortOrder={}", field, sortOrder);
                    sourceBuilder.sort(field, sortOrderEnum);
                }
            } else {
                throw new IllegalArgumentException("Invalid sort parameters. Both 'sortOrder' and 'field' must be strings.");
            }
        }
    }
    private void setHighlightParameters(Map<String, Object> conditions, SearchSourceBuilder sourceBuilder) {
        Map<String, Object> highlightParams = (Map<String, Object>) conditions.get("highlight");
        if (highlightParams != null) {
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            List<String> fieldNames = (List<String>) highlightParams.getOrDefault("fields", Collections.emptyList());
            String preTag = (String) highlightParams.getOrDefault("preTag", "<em>");
            String postTag = (String) highlightParams.getOrDefault("postTag", "</em>");

            for (String fieldName : fieldNames) {
                highlightBuilder.field(fieldName);
            }

            highlightBuilder.preTags(preTag);
            highlightBuilder.postTags(postTag);

            sourceBuilder.highlighter(highlightBuilder);
        }
    }

    private CommonMap processSearchResponse(SearchResponse searchResponse)  {
        CommonMap result = new CommonMap();
        long totalHits = searchResponse.getHits().getTotalHits().value;
        result.setTotal(totalHits);

        LinkedHashMap<String, Object> objectMap = new LinkedHashMap<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            String sourceAsString = hit.getSourceAsString();
            HashMap<String, Object> parsedObject = JSONObject.parseObject(sourceAsString, HashMap.class);
            String id = hit.getId();
            // 添加高亮信息到解析后的文档
            addHighlightedFields(hit.getHighlightFields(), parsedObject);

            objectMap.put(id, parsedObject);
            log.info("查询出来的数据为:{}",JSONObject.toJSONString(parsedObject));
        }
        log.info("查询出来的数据为:{}",JSONObject.toJSONString(objectMap));
        result.setObjectMap(objectMap);

        return result;
    }

    private void addHighlightedFields(Map<String, HighlightField> highlightFields, Map<String, Object> parsedObject) {
        if (!highlightFields.isEmpty()) {
            for (Map.Entry<String, HighlightField> entry : highlightFields.entrySet()) {
                String fieldName = entry.getKey();
                Text[] fragments = entry.getValue().fragments();
                StringBuilder highlightedValue = new StringBuilder();
                for (Text fragment : fragments) {
                    highlightedValue.append(fragment);
                }
                parsedObject.put(fieldName, highlightedValue);
            }
        }
    }

    /**
     * 根据条件构建Elasticsearch查询构建器
     *
     * @param conditions 查询条件（键值对形式）
     * @return Elasticsearch查询构建器
     */
    private QueryBuilder buildQueryBuilder(Map<String, Object> conditions) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        if (conditions != null && !conditions.isEmpty()) {
            for (Map.Entry<String, Object> entry : conditions.entrySet()) {
                String field = entry.getKey();
                Object value = entry.getValue();

                // 处理范围查询条件
                if (value instanceof Map && ((Map<?, ?>) value).containsKey("range")) {
                    Map<String, Object> rangeParams = (Map<String, Object>) value;
                    RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery(field);

                    String gt = (String) rangeParams.get("gt");
                    if (gt != null) {
                        rangeQueryBuilder.gt(gt);
                    }

                    String gte = (String) rangeParams.get("gte");
                    if (gte != null) {
                        rangeQueryBuilder.gte(gte);
                    }

                    String lt = (String) rangeParams.get("lt");
                    if (lt != null) {
                        rangeQueryBuilder.lt(lt);
                    }

                    String lte = (String) rangeParams.get("lte");
                    if (lte != null) {
                        rangeQueryBuilder.lte(lte);
                    }

                    boolQueryBuilder.filter(rangeQueryBuilder);
                }
                // 处理其他查询条件（如 match 查询）
                else if (value instanceof String) {
                    boolQueryBuilder.filter(QueryBuilders.matchQuery(field, value));
                }
            }
        }

        return boolQueryBuilder;
    }

}