package com.jay.monitor.data.server.componts;

import com.jay.monitor.data.server.utils.DataUtils;
import com.jay.monitor.data.server.utils.ESUtils;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
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.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.zxp.esclientrhl.annotation.ESID;
import org.zxp.esclientrhl.index.ElasticsearchIndex;
import org.zxp.esclientrhl.repository.*;
import org.zxp.esclientrhl.util.*;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 支持动态索引类型的ES实现类
 *
 * @param <T> document对象
 * @param <M> 主键
 */
public class ElasticSearchPartitionImpl<T, M> extends ElasticsearchTemplateImpl<T, M>
    implements ElasticSearchPartition<T, M> {

    private Logger logger = LoggerFactory.getLogger(ElasticSearchPartitionImpl.class);

    private static Map<Class, String> classIDMap = new ConcurrentHashMap();

    @Autowired
    private RestHighLevelClient client;

    @Autowired
    private ElasticsearchIndex elasticsearchIndex;

    @Override
    public PageList<T> searchPartitionPage(String indexName, T t, int pageNo, int pageSize, Sort.Order[] sort)
        throws Exception {
        QueryBuilder queryBuilder = ESUtils.beanToQueryBuilder(t);
        return searchPartitionPage(indexName, queryBuilder, pageNo, pageSize, t.getClass(), sort);
    }

    @Override
    public PageList<T> searchPartitionPage(String indexName, QueryBuilder queryBuilder, int pageNo, int pageSize,
        Class clazz, Sort.Order[] sort) throws Exception {
        Attach attach = builderAttach(pageNo, pageSize, sort);
        PageList<T> pageList = super.search(queryBuilder, attach, clazz, indexName);
        return pageList;
    }

    @Override
    public List<T> searchPartition(String indexName, T t) throws Exception {
        QueryBuilder queryBuilder = ESUtils.beanToQueryBuilder(t);
        return super.search(queryBuilder, (Class<T>)t.getClass(), indexName);
    }

    private Attach builderAttach(int pageNo, int pageSize, Sort.Order[] ordered) {
        Attach attach = new Attach();
        PageSortHighLight pageSortHighLight = new PageSortHighLight(pageNo, pageSize);
        if (ordered != null) {
            pageSortHighLight.setSort(new Sort(ordered));
        }
        attach.setPageSortHighLight(pageSortHighLight);
        return attach;
    }

    @Override
    public List<T> search(QueryBuilder queryBuilder, Class<T> clazz, String... indexs) throws Exception {
        MetaData metaData = IndexTools.getIndexType(clazz);
        List<T> list = new ArrayList();
        SearchRequest searchRequest = new SearchRequest(indexs);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(Constant.DEFALT_PAGE_SIZE);
        searchRequest.source(searchSourceBuilder);
        if (metaData.isPrintLog()) {
            this.logger.info(searchSourceBuilder.toString());
        }

        SearchResponse searchResponse = this.client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits hits = searchResponse.getHits();
        SearchHit[] searchHits = hits.getHits();
        SearchHit[] var12 = searchHits;
        int var13 = searchHits.length;

        for (int var14 = 0; var14 < var13; ++var14) {
            SearchHit hit = var12[var14];
            T t = JsonUtils.string2Obj(hit.getSourceAsString(), clazz);
            this.correctID(clazz, t, hit.getId());
            list.add(t);
        }

        return list;
    }

    private void correctID(Class clazz, T t, String _id) {
        try {
            if (StringUtils.isEmpty(_id)) {
                return;
            }

            if (classIDMap.containsKey(clazz)) {
                Field field = clazz.getDeclaredField((String)classIDMap.get(clazz));
                field.setAccessible(true);
                if (field.get(t) == null) {
                    field.set(t, _id);
                }

                return;
            }

            for (int i = 0; i < clazz.getDeclaredFields().length; ++i) {
                Field field = clazz.getDeclaredFields()[i];
                field.setAccessible(true);
                if (field.getAnnotation(ESID.class) != null) {
                    classIDMap.put(clazz, field.getName());
                    if (field.get(t) == null) {
                        field.set(t, _id);
                    }
                }
            }
        } catch (Exception var6) {
            this.logger.error("correctID error!", var6);
        }

    }

    @Override
    public boolean savePartition(T indexEntity, String indexName, String routing) throws Exception {
        MetaData metaData = IndexTools.getIndexType(indexEntity.getClass());
        String indexname = DataUtils.getDefaultValue(indexName, metaData.getIndexname());
        String indextype = DataUtils.getDefaultValue(metaData.getIndextype(), "");

        String id = Tools.getESId(indexEntity);
        IndexRequest indexRequest = null;
        if (StringUtils.isEmpty(id)) {
            indexRequest = new IndexRequest(indexname, indextype);
        } else {
            indexRequest = new IndexRequest(indexname, indextype, id);
        }

        String source = JsonUtils.obj2String(indexEntity);
        indexRequest.source(source, XContentType.JSON);
        if (!StringUtils.isEmpty(routing)) {
            indexRequest.routing(routing);
        }

        IndexResponse indexResponse = null;
        indexResponse = this.client.index(indexRequest, RequestOptions.DEFAULT);
        if (indexResponse.getResult() == DocWriteResponse.Result.CREATED) {
            this.logger.info("INDEX CREATE SUCCESS");
            this.elasticsearchIndex.rollover(indexEntity.getClass(), true);
        } else {
            if (indexResponse.getResult() != DocWriteResponse.Result.UPDATED) {
                return false;
            }
            this.logger.info("INDEX UPDATE SUCCESS");
        }
        return true;
    }

    @Override
    public boolean save(T t, String routing) throws Exception {
        return savePartition(t, null, null);
    }

    @Override
    public BulkResponse[] saveBatchPartition(List<T> list, String indexName) throws Exception {
        if (list != null && list.size() != 0) {
            T t = list.get(0);
            MetaData metaData = IndexTools.getIndexType(t.getClass());
            String indexname = DataUtils.getDefaultValue(indexName, metaData.getIndexname());
            List<List<T>> lists = Tools.splitList(list, true);
            BulkResponse[] bulkResponses = new BulkResponse[lists.size()];

            for (int i = 0; i < lists.size(); ++i) {
                bulkResponses[i] = this.savePart((List)lists.get(i), indexname);
            }
            return bulkResponses;
        } else {
            return null;
        }
    }

    private BulkResponse savePart(List<T> list, String indexname) throws Exception {
        BulkRequest rrr = new BulkRequest();
        Class clazz = null;

        for (int i = 0; i < list.size(); ++i) {
            T tt = list.get(i);
            clazz = tt.getClass();
            String sourceJsonStr = JsonUtils.obj2String(tt);
            rrr.add((new IndexRequest(indexname)).source(sourceJsonStr, XContentType.JSON));
        }

        BulkResponse bulkResponse = this.client.bulk(rrr, RequestOptions.DEFAULT);
        this.elasticsearchIndex.rollover(clazz, true);
        return bulkResponse;
    }
}
