package cn.reghao.tnb.search.esapp.es;

import cn.reghao.jutil.jdk.web.log.NginxLog;
import cn.reghao.jutil.jdk.string.SnowFlake;
import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchAllQuery;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * @author reghao
 * @date 2025-03-12 10:45:58
 */
@Slf4j
@Service
public class DocumentService {
    private final ElasticsearchClient esClient;
    private final ElasticsearchAsyncClient asyncClient;
    private final SnowFlake idGenerator;

    public DocumentService(ElasticService elasticService) {
        this.esClient = elasticService.getElasticsearchClient();
        this.asyncClient = elasticService.getElasticsearchAsyncClient();
        this.idGenerator = new SnowFlake(1, 1);
    }

    public void save(String indexName, NginxLog nginxLog) throws IOException {
        long id = idGenerator.nextId();
        IndexResponse indexResponse = esClient.index(i -> i.index(indexName).id(id + "").document(nginxLog));
        //log.info("add one document result: {}", indexResponse.result().jsonValue());
    }

    public void saveAll(String indexName, List<NginxLog> nginxLogs) throws IOException {
        List<BulkOperation> bulkOperations = new ArrayList<>();
        nginxLogs.forEach(doc -> bulkOperations.add(BulkOperation.of(b -> b.index(c -> c.id(doc.getId()).document(doc)))));
        BulkResponse bulkResponse = esClient.bulk(s -> s.index(indexName).operations(bulkOperations));
        if (bulkResponse.errors()) {
            bulkResponse.items().forEach(b -> log.error("bulk response result = {}", b.error()));
        }
    }

    public void update(String indexName, NginxLog nginxLog) throws IOException {
        String id = nginxLog.getId();
        UpdateResponse<NginxLog> updateResponse = esClient.update(s -> s.index(indexName).id(id).doc(nginxLog), NginxLog.class);
        //log.info("update doc result: {}", updateResponse.result());
    }

    public void deleteById(String indexName, String id) {
        try {
            DeleteResponse deleteResponse = esClient.delete(s -> s.index(indexName).id(id));
            log.info("del doc result: {}", deleteResponse.result());
        } catch (IOException e) {
            log.error("del doc failed, error: ", e);
        }
    }

    public void deleteByIdAsync(String indexName) {
        int id = 1;
        asyncClient.delete(i -> i.index(indexName).id("" + id)).whenComplete((success, failure)->{
            System.out.println(success.index());
            System.out.println(success.version());
        });
    }

    public void deleteByIds(String indexName, List<String> ids) {
        List<BulkOperation> bulkOperations = new ArrayList<>();
        ids.forEach(a -> bulkOperations.add(BulkOperation.of(b -> b.delete(c -> c.id(a)))));
        try {
            BulkResponse bulkResponse = esClient.bulk(a -> a.index(indexName).operations(bulkOperations));
            bulkResponse.items().forEach(a -> log.info("batch del result: {}", a.result()));
            log.error("batch del bulk resp errors: {}", bulkResponse.errors());
        } catch (IOException e) {
            log.error("batch del doc failed, error: ", e);
        }
    }

    /**
     * 删除索引下的所有文档
     *
     * @param
     * @return
     * @date 2025-03-13 16:26:20
     */
    public void deleteByIndexName(String indexName) {
        try {
            DeleteByQueryRequest deleteByQueryRequest = DeleteByQueryRequest.of(s -> s.index(indexName)
                    .query(m -> m.matchAll(new MatchAllQuery.Builder().build()))
            );
            DeleteByQueryResponse deleteByQueryResponse = esClient.deleteByQuery(deleteByQueryRequest);
            log.info("del doc result: {}", deleteByQueryResponse.total());
        } catch (IOException e) {
            log.error("del doc failed, error: ", e);
        }
    }

    public void deleteByIndexNameAsync(String indexName) {
        DeleteByQueryRequest deleteByQueryRequest = DeleteByQueryRequest.of(s -> s.index(indexName)
                .query(m -> m.matchAll(new MatchAllQuery.Builder().build()))
        );
        CompletableFuture<DeleteByQueryResponse> future = asyncClient.deleteByQuery(deleteByQueryRequest);
        future.whenComplete((deleteByQueryResponse, throwable) -> {
            if (throwable != null) {
                log.error("{}", throwable.getMessage());
            }

            if (deleteByQueryResponse != null) {
                deleteByQueryResponse.failures().forEach(failure -> log.error("delete doc result = {}", failure.toString()));
            }

            log.info("delete doc done...");
        });
    }
}
