package com.search.supersearch;

import cn.hutool.core.io.file.FileReader;
import cn.hutool.json.JSONUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
import com.google.common.collect.Lists;
import com.search.supersearch.domain.IamDataCategory;
import com.search.supersearch.domain.IamSearchCategoryidIndexname;
import com.search.supersearch.model.dto.IamCategoryIndexBean;
import com.search.supersearch.model.pojo.DocsIndex;
import com.search.supersearch.service.DocsService;
import com.search.supersearch.service.EsService;
import io.jsonwebtoken.lang.Maps;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 测试 elasticSearch client 文档相关的操作
 *
 * @author WT
 * @date 2021/12/28 16:27:45
 */
@Slf4j
@SpringBootTest
@ActiveProfiles("wr") //这里
public class ElasticsearchClientDocumentTest {

    private static final String INDEX_NAME = "fenpian-0";
    @Autowired
    private ElasticsearchClient elasticsearchClient;
    @Autowired
    private EsService esService;
    @Autowired
    private DocsService docsService;

    // 添加文档
    @Test
    public void add() throws IOException {
        IndexResponse indexResponse = elasticsearchClient.index(indexRequest -> {
//                indexRequest.index(INDEX_NAME).document(new AhaIndex().setName("wangWu").setAge(21))
            HashMap<String, String> map = new HashMap<>();
            map.put("index", "index");
            map.put("gongsi", "gongsi" + "finalI");
            indexRequest.index("fenpian-1").document(map);
            return indexRequest;
        });
        log.info("== response: {}, responseStatus: {}", indexResponse, indexResponse.result());
    }


    // 添加文档
    @Test
    @SneakyThrows
    public void run() {
        DocsIndex byFileId = esService.getByFileId("3855614e99034accabc3cb5c3eb7ba7b");
        System.out.println(JSONUtil.toJsonStr(byFileId));
    }

    // 添加文档
    @Test
    public void testAddDocument() throws IOException {
        String finalIndex = "indexname";
        for (int j = 0; j < 3; j++) {
            String index = finalIndex + j;
//            DeleteIndexResponse deleteIndexResponse = elasticsearchClient.indices()
//                    .delete(deleteIndexRequest ->
//                            deleteIndexRequest.index(index)
//                    );

//            log.info("== {} 索引创建是否删除成功: {}", "elasticsearch-client", deleteIndexResponse.acknowledged());
            for (int i = 0; i < 3; i++) {
                int finalI = i;
                IndexResponse indexResponse = elasticsearchClient.index(indexRequest -> {
//                indexRequest.index(INDEX_NAME).document(new AhaIndex().setName("wangWu").setAge(21))
                    HashMap<String, String> map = new HashMap<>();
                    map.put("index", index);
                    map.put("gongsi", "gongsi" + finalI);
                    indexRequest.index("fenpian-0").document(map);
                    return indexRequest;
                });
                log.info("== response: {}, responseStatus: {}", indexResponse, indexResponse.result());
            }
        }


    }

    // 获取文档信息
    @Test
    public void testGetDocument() throws IOException {
        GetResponse<Map> getResponse = elasticsearchClient.get(getRequest ->
                getRequest.index(INDEX_NAME).id("1"), Map.class
        );
        log.info("== document source: {}, response: {}", getResponse.source(), getResponse);
    }

    // 更新文档信息
    @Test
    public void testUpdateDocument() throws IOException {
        UpdateResponse<Map> updateResponse = elasticsearchClient.update(updateRequest ->
                        updateRequest.index(INDEX_NAME).id("tU4YAH4B395pyiY3b46F")
//                        .doc(new AhaIndex().setName("lisi1").setAge(22)), Map.class
                                .doc(Maps.of("name", "wangrui2")), Map.class
        );
        log.info("== response: {}, responseStatus: {}", updateResponse, updateResponse.result());
    }

    // 删除文档信息
    @Test
    public void testDeleteDocument() throws IOException {
        DeleteResponse deleteResponse = elasticsearchClient.delete(deleteRequest ->
                deleteRequest.index(INDEX_NAME).id("1")
        );
        log.info("== response: {}, result:{}", deleteResponse, deleteResponse.result());

    }

    // 批量插入文档
    @Test
    public void testBatchInsert() throws IOException {

        List<BulkOperation> bulkOperationList = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
//            AhaIndex ahaIndex = new AhaIndex().setName("lisi" + i).setAge(20 + i);
            int finalI = i;
            bulkOperationList.add(new BulkOperation.Builder().create(e -> e.document(Maps.of("name", "wangrui" + finalI))).build());
        }

        BulkResponse bulkResponse = elasticsearchClient.bulk(bulkRequest ->
                bulkRequest.index(INDEX_NAME).operations(bulkOperationList)
        );

        // 这边插入成功的话显示的是 false
        log.info("== errors: {}", bulkResponse.errors());
    }


    @Test
    public void testRestClient() throws IOException {
        SearchResponse<DocsIndex> search2 = elasticsearchClient.search(s -> s.index("doc_1")
                        .query(q -> q
                                .bool(b -> b
                                        .should(s1 -> s1.match(v -> v.field("content").query("智能")))
                                        .should(s2 -> s2.match(v -> v.field("businessDataPrimaryKey").query("businessDataPrimaryKey文字文稿1.docx")))

                                ))
                        .highlight(h -> h.fields("content", hf -> hf).fields("filename", hf -> hf))
                        .size(10)
                        .from(0)
                ,
                DocsIndex.class);
        for (Hit<DocsIndex> hit : search2.hits().hits()) {
            log.info("== hit: {}", hit.source());
        }
    }

    @Test
    public void run2() throws IOException {
        SearchResponse<DocsIndex> search2 = elasticsearchClient.search(s -> s.index("001001")
                        .query(q -> q
                                .bool(b -> b
                                        .should(s1 -> s1.match(v -> v.field("content").query("智能")))
                                        .should(s2 -> s2.match(v -> v.field("businessDataPrimaryKey").query("businessDataPrimaryKey文字文稿1.docx")))
                                ))
                        .sort(sort -> sort.field(v -> v.field("metaDate").order(SortOrder.Asc)))
                        .searchAfter(sa -> sa.stringValue("1692116220000"))
                        .size(10),
                DocsIndex.class);
        for (Hit<DocsIndex> hit : search2.hits().hits()) {
            log.info("== hit: {}", hit.sort().get(0)._get());
        }
    }

    @Test
    public void run3() throws IOException {
        ArrayList<String> strings = Lists.newArrayList("test1", "test2");
        SearchResponse<Map> search2 = elasticsearchClient.search(s -> s.index("")
                        .query(q -> q
                                .bool(b -> b
                                        .should(s1 -> s1.match(v -> v.field("response").query("response")))
                                ))
                        .size(10)
                ,
                Map.class);

        for (Hit<Map> hit : search2.hits().hits()) {
            log.info("== hit: {}", hit.source());
        }
    }

    @Test
    public void run4() throws IOException {

        ArrayList<String> strings = Lists.newArrayList("indexname1", "indexname2", "indexname0");
        SearchResponse<Map> search2 = elasticsearchClient.search(s -> s.index(strings)
                        .query(q -> q
                                .bool(b -> b
                                        .should(should -> should
                                                .bool(sb -> sb
                                                        .must(m -> m
                                                                .terms(t -> t
                                                                        .field("gongsi")
                                                                        .terms(tt -> tt.value(Lists.newArrayList(FieldValue.of("gongsi1"))))))
                                                        .must(m -> m
                                                                .terms(t -> t
                                                                        .field("index")
                                                                        .terms(tt -> tt.value(Lists.newArrayList(FieldValue.of("indexname1"))))))

                                                )
                                        )
                                        .should(should -> should
                                                .bool(sb -> sb
                                                        .must(m -> m
                                                                .terms(t -> t
                                                                        .field("gongsi")
                                                                        .terms(tt -> tt.value(Lists.newArrayList()))))
                                                        .must(m -> m
                                                                .terms(t -> t
                                                                        .field("index")
                                                                        .terms(tt -> tt.value(Lists.newArrayList(FieldValue.of("indexname2"))))))

                                                )
                                        )
                                )


                        )
                        .size(10)
                ,
                Map.class);

        for (Hit<Map> hit : search2.hits().hits()) {
            log.info("== hit: {}", hit.source());
        }
    }

    @Test
    public void run5() throws IOException {

        ArrayList<String> strings = Lists.newArrayList("indexname1", "indexname2", "indexname0");
        SearchResponse<Map> search2 = elasticsearchClient.search(s -> {
                    SearchRequest.Builder index = s.index(strings);
                    index.query(q -> q
                                            .bool(b -> {
                                                        b
                                                                .should(should -> should
                                                                        .bool(sb -> sb
                                                                                .must(m -> m
                                                                                        .terms(t -> t
                                                                                                .field("gongsi")
                                                                                                .terms(tt -> tt.value(Lists.newArrayList(FieldValue.of("gongsi1"))))))
                                                                                .must(m -> m
                                                                                        .terms(t -> t
                                                                                                .field("index")
                                                                                                .terms(tt -> tt.value(Lists.newArrayList(FieldValue.of("indexname1"))))))

                                                                        )
                                                                )
                                                                .should(should -> should
                                                                        .bool(sb -> sb
                                                                                .must(m -> m
                                                                                        .terms(t -> t
                                                                                                .field("gongsi")
                                                                                                .terms(tt -> tt.value(Lists.newArrayList(FieldValue.of("gongsi1"))))))
                                                                                .must(m -> m
                                                                                        .terms(t -> t
                                                                                                .field("index")
                                                                                                .terms(tt -> tt.value(Lists.newArrayList(FieldValue.of("indexname2"))))))

                                                                        )
                                                                );
//                                                strings.remove(1);
                                                        return b;
                                                    }
                                            )
                            )


                            .size(10);
                    return index;
                }
                ,
                Map.class);

        for (Hit<Map> hit : search2.hits().hits()) {
            log.info("== hit: {}", hit.source());
        }
    }

    @Test
    public void run6() throws IOException {
        SearchResponse<DocsIndex> search2 = elasticsearchClient.search(s -> s.index("indexname1", "indexname2")
                        .query(q -> q
                                .bool(b -> b)
                        )
                ,
                DocsIndex.class);
        for (Hit<DocsIndex> hit : search2.hits().hits()) {
            log.info("== hit: {}", hit.source());
        }
    }

    @Test
    public void run7() throws IOException {
        FileReader fileReader = new FileReader("tmp.txt");
        String result = fileReader.readString();

        List<IamCategoryIndexBean> category = JSONUtil.toList(result, IamCategoryIndexBean.class);

        if (category.size() < 1) {
            System.out.println("该用户没有任何权限");
            return;
        }

        for (IamCategoryIndexBean iamDataCategory : category) {
            IamDataCategory dataCategoryBean = iamDataCategory.getDataCategoryBean();

            List<String> index = iamDataCategory.getIndexBeanList().stream().map(IamSearchCategoryidIndexname::getIndexName).collect(Collectors.toList());
            Map<String, List<String>> map = iamDataCategory.getIndexBeanList().stream().collect(Collectors.toMap(IamSearchCategoryidIndexname::getIndexName, i -> Optional.ofNullable(i.getOrgCodes()).orElse(Lists.newArrayList())));

            categoryAllIndex(index, map, iamDataCategory);
            SearchResponse<Map> search = docsService.searchHitv2("测试", 0,0, index, 10, null, map);
            if (search == null) {
                continue;
            }
            HitsMetadata<Map> hits = search.hits();
            if (hits.total() == null || hits.total().value() == 0) {
                continue;
            }
        }
    }

    private void categoryAllIndex(List<String> index, Map<String, List<String>> map, IamCategoryIndexBean iamCategoryIndexBean) {
        List<IamCategoryIndexBean> children = iamCategoryIndexBean.getChildren();
        if (children != null && children.size() > 0) {
            for (IamCategoryIndexBean child : children) {
                List<String> collect = child.getIndexBeanList().stream().map(IamSearchCategoryidIndexname::getIndexName).collect(Collectors.toList());
                Map<String, List<String>> map2 = child.getIndexBeanList().stream().collect(Collectors.toMap(IamSearchCategoryidIndexname::getIndexName, i -> Optional.ofNullable(i.getOrgCodes()).orElse(Lists.newArrayList())));
                map.putAll(map2);
                index.addAll(collect);
                categoryAllIndex(index, map, child);
            }
        }
    }
}
