package cn.com.taiji.service.impl;

import cn.com.taiji.domain.FusionData;
import cn.com.taiji.domain.FusionQuery;
import cn.com.taiji.domain.LeaveOutData;
import cn.com.taiji.domain.StaticOrDynamicData;
import cn.com.taiji.domain.dto.LeaceOutDto;
import cn.com.taiji.service.FusionAnalysisService;
import cn.com.taiji.utils.DateUtils;
import cn.hutool.core.io.LineHandler;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.config.RequestConfig;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.HttpAsyncResponseConsumerFactory;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedDoubleTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.ParsedTopHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.text.ParseException;
import java.util.*;

import static cn.com.taiji.constants.EsIndexConstants.*;


/**
 * @author xhl
 * @date 2023/2/6
 */
@Service
public class FusionAnalysisServiceImpl implements FusionAnalysisService {

    private static final RequestOptions COMMON_OPTIONS;

    static {
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(5000)
                .setSocketTimeout(60000)
                .build();
        RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
        builder.setRequestConfig(requestConfig).setHttpAsyncResponseConsumerFactory(
                // 设置查询内容大小限制,默认100 * 1024 * 1024
                new HttpAsyncResponseConsumerFactory.HeapBufferedResponseConsumerFactory(5*1024 * 1024 * 1024)
        );
        COMMON_OPTIONS = builder.build();
    }

    @Autowired
    private RestHighLevelClient client;

    @Override
    public void fusionAnalysisExcelOne(FusionQuery query, HttpServletResponse response) throws IOException, ParseException {
        List<FusionData> list = new ArrayList<>();
        Date startTime = DateUtils.parse(query.getStartTime(),"yyyy-MM-dd");
        String time = DateUtils.format(startTime,"yyyy-MM-dd");
        SearchRequest request = new SearchRequest(INDEX_SEAT_REALTIMETRAJECTORY+time);
        // 构建查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        boolQueryBuilder.filter(QueryBuilders.rangeQuery("mergeTime").gte(query.getStartTime()).lte(query.getEndTime()));
        searchSourceBuilder.query(boolQueryBuilder);
//        TermsAggregationBuilder aggBuilder = AggregationBuilders.terms("ship_field_agg")
//                .field("mergeTarget")
//                .size(query.getPageSize())
//                .subAggregation(
//                        AggregationBuilders.topHits("ship_field_agg_top1")
//                                .size(100)
//                                .sort(
//                                        SortBuilders.fieldSort("mergeTime").order(SortOrder.ASC)
//                                )
//                );
        searchSourceBuilder
                .trackTotalHits(true)
                .sort(SortBuilders.fieldSort("mergeTime").order(SortOrder.ASC))
//                .aggregation(aggBuilder)
                .size(query.getPageSize())
                .timeout(TimeValue.timeValueHours(1L))
                .timeout(TimeValue.timeValueMinutes(30L))
                .timeout(TimeValue.timeValueSeconds(500L));
        request.source(searchSourceBuilder);
        SearchResponse search = client.search(request, COMMON_OPTIONS);
        SearchHits searchHits = search.getHits();
        SearchHit[] hits = searchHits.getHits();
        List<Map<String, Object>> inList = new ArrayList<Map<String, Object>>();
        List<Map<String, Object>> outList = new ArrayList<Map<String, Object>>();
        for (SearchHit hit : hits) {
            Map<String, Object> map = hit.getSourceAsMap();
            inList.add(map);
        }
        outList = change(inList, "mergeTarget", outList);
        outList.forEach(map->{
            JSONObject maps = JSONObject.parseObject(JSON.toJSONString(map));
//            JSONObject maps = new JSONObject();
//            Iterator it = map.keySet().iterator();
//            while (it.hasNext()) {
//                String key = (String) it.next();
//                maps.put(key, map.get(key));
//            }
            JSONArray jsonArray =JSONArray.parseArray(maps.getString("array"));
            if (jsonArray.size()>0){
                FusionData data = new FusionData();
                Integer num = 0;
                for (int i = 0; i < jsonArray.size(); i++) {
                    if (i<jsonArray.size()-1){
                        JSONObject job = jsonArray.getJSONObject(i);
                        JSONObject job2 = jsonArray.getJSONObject(i+1);
                        Date date = null;
                        Date date2 = null;
                        try {
                            date = DateUtils.parse(job.get("mergeTime").toString(),"yyyy-MM-dd HH:mm:ss.SSS");
                            date2 = DateUtils.parse(job2.get("mergeTime").toString(),"yyyy-MM-dd HH:mm:ss.SSS");
                        } catch (ParseException e) {
                            e.printStackTrace();
                        }
                        Long interval = date2.getTime()-date.getTime();
                        if (interval>6500L){
                            num++;
                        }
                    }
                }
                if (num>0){
                    JSONObject sourceItem = jsonArray.getJSONObject(0);
                    JSONObject sourceItem2 = jsonArray.getJSONObject(jsonArray.size()-1);
                    data.setMergeTarget(sourceItem.getString("mergeTarget"));
                    data.setTrackCount((long) jsonArray.size());
                    data.setStartTime(sourceItem.getString("mergeTime"));
                    data.setEndTime(sourceItem2.getString("mergeTime"));
                    data.setFluctuateNumber(num);
                    list.add(data);
                }
            }
        });
//        Aggregations aggregations = search.getAggregations();
//        ParsedStringTerms aggregation = aggregations.get("ship_field_agg");
//        for (Terms.Bucket bucket : aggregation.getBuckets()) {
//            FusionData data = new FusionData();
//            ParsedTopHits topHits = bucket.getAggregations().get("ship_field_agg_top1");
//            SearchHits searchHits = topHits.getHits();
//            Long value = searchHits.getTotalHits().value;
//            SearchHit[] hits = searchHits.getHits();
//            Integer num = 0;
//            for (int i = 0; i < hits.length; i++) {
//                if (i != hits.length-1){
//                    Map<String, Object> map = hits[i].getSourceAsMap();
//                    Map<String, Object> map2 = hits[i+1].getSourceAsMap();
//                    Date date = DateUtils.parse(map.get("mergeTime").toString(),"yyyy-MM-dd");
//                    Date date2 = DateUtils.parse(map2.get("mergeTime").toString(),"yyyy-MM-dd");
//                    Long interval = date2.getTime()-date.getTime();
//                    if (interval>6500L){
//                        num++;
//                    }
//                }
//            }
//            if (num>0){
//                JSONObject sourceItem = JSONObject.parseObject(hits[0].getSourceAsString());
//                JSONObject sourceItem2 = JSONObject.parseObject(hits[value.intValue()-1].getSourceAsString());
//                data.setMergeTarget(sourceItem.getString("mergeTarget"));
//                data.setTrackCount(value);
//                data.setStartTime(sourceItem.getString("mergeTime"));
//                data.setEndTime(sourceItem2.getString("mergeTime"));
//                data.setFluctuateNumber(num);
//                list.add(data);
//            }
//        }
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("识别融合数据率波动问题", "UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), FusionData.class).sheet("识别融合数据率波动问题")
                    .doWrite(list);
        } catch (Exception e) {
            // 重置response
            System.out.println("导出识别融合数据率波动问题excel失败:{}" + e.getMessage() + e);
        }
    }

    @Override
    public void fusionAnalysisExcelTwo(FusionQuery query, HttpServletResponse response) throws IOException, ParseException {

        List<FusionData> list = new ArrayList<>();
        Date startTime = DateUtils.parse(query.getStartTime(),"yyyy-MM-dd");
        String time = DateUtils.format(startTime,"yyyy-MM-dd");
        SearchRequest request = new SearchRequest(INDEX_SEAT_REALTIMETRAJECTORY+time);
        // 构建查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        boolQueryBuilder.filter(QueryBuilders.rangeQuery("mergeTime").gte(query.getStartTime()).lte(query.getEndTime()));
        searchSourceBuilder.query(boolQueryBuilder);
        TermsAggregationBuilder aggBuilder = AggregationBuilders.terms("ship_field_agg")
                .field("mergeTarget")
                .size(query.getPageSize())
                .subAggregation(
                        AggregationBuilders.terms("ship_field_agg_one")
                                .field("targetCourse")
                                .size(query.getPageSize())
                                .subAggregation(
                                        AggregationBuilders.terms("ship_field_agg_two")
                                                .field("targetSpeed")
                                                .size(query.getPageSize())
                                                .subAggregation(AggregationBuilders.topHits("ship_field_agg_top1")
                                                        .size(100)
                                                        .sort(
                                                                SortBuilders.fieldSort("mergeTime").order(SortOrder.ASC)
                                                        ))
                                )
                );
        searchSourceBuilder
                .trackTotalHits(true)
                .aggregation(aggBuilder)
                .size(query.getPageSize())
                .timeout(TimeValue.timeValueHours(1L))
                .timeout(TimeValue.timeValueMinutes(30L))
                .timeout(TimeValue.timeValueSeconds(500L));
        request.source(searchSourceBuilder);
        SearchResponse search = client.search(request, COMMON_OPTIONS);
        Aggregations aggregations = search.getAggregations();
        ParsedStringTerms aggregation = aggregations.get("ship_field_agg");
        for (Terms.Bucket bucket : aggregation.getBuckets()) {
            FusionData data = new FusionData();
            ParsedStringTerms terms = bucket.getAggregations().get("ship_field_agg_one");
            Integer num = 0;
            for (Terms.Bucket buc : terms.getBuckets()){
                ParsedDoubleTerms termsTwo = buc.getAggregations().get("ship_field_agg_two");
                for (Terms.Bucket ket : termsTwo.getBuckets()){
                    ParsedTopHits topHit = ket.getAggregations().get("ship_field_agg_top1");
                    SearchHits searchHit = topHit.getHits();
                    SearchHit[] hit = searchHit.getHits();
                    for (int i = 0; i < hit.length; i++) {
                        if (num>2){
                            data.setFluctuateNumber(data.getFluctuateNumber()+1);
                            data.setMergeTarget(bucket.getKeyAsString());
                            data.setTrackCount(bucket.getDocCount());
                            data.setStartTime(query.getStartTime());
                            data.setEndTime(query.getEndTime());
                            list.add(data);
                            num =0;
                        }
                        if (i != hit.length-1){
                            Map<String, Object> map = hit[i].getSourceAsMap();
                            Map<String, Object> map2 = hit[i+1].getSourceAsMap();
                            Date date = DateUtils.parse(map.get("mergeTime").toString(),"yyyy-MM-dd");
                            Date date2 = DateUtils.parse(map2.get("mergeTime").toString(),"yyyy-MM-dd");
                            Long interval = date2.getTime()-date.getTime();
                            if (interval<6500L){
                                num++;
                            }
                        }
                    }
                }
            }
        }
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("虚假推送问题", "UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), FusionData.class).sheet("虚假推送问题")
                    .doWrite(list);
        } catch (Exception e) {
            // 重置response
            System.out.println("导出虚假推送问题excel失败:{}" + e.getMessage() + e);
        }
    }

    @Override
    public void tianAoLeaveOutExcel(FusionQuery query, HttpServletResponse response) throws IOException, ParseException {
        List<LeaveOutData> list = new ArrayList<>();
        List<LeaceOutDto> dtos = new ArrayList<>();
        Date startTime = DateUtils.parse(query.getStartTime(),"yyyy-MM-dd");
        String time = DateUtils.format(startTime,"yyyy-MM-dd");
        SearchRequest request = new SearchRequest(INDEX_SEAT_TRACK_RADAR+time);
        // 构建查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        boolQueryBuilder.filter(QueryBuilders.rangeQuery("receiveTime").gte(query.getStartTime()).lte(query.getEndTime()));
        searchSourceBuilder.query(boolQueryBuilder);
//        TermsAggregationBuilder aggBuilder = AggregationBuilders.terms("ship_field_agg")
//                .field("fusionBatchNum")
//                .size(query.getPageSize());
        searchSourceBuilder
                .trackTotalHits(true)
//                .aggregation(aggBuilder)
                .size(query.getPageSize())
                .sort(SortBuilders.fieldSort("receiveTime").order(SortOrder.ASC))
                .timeout(TimeValue.timeValueHours(1L))
                .timeout(TimeValue.timeValueMinutes(30L))
                .timeout(TimeValue.timeValueSeconds(500L));
        request.source(searchSourceBuilder);
        SearchResponse search = client.search(request, COMMON_OPTIONS);
        SearchHits searchHits = search.getHits();
        SearchHit[] hits = searchHits.getHits();
        List<Map<String, Object>> inList = new ArrayList<Map<String, Object>>();
        List<Map<String, Object>> outList = new ArrayList<Map<String, Object>>();
        for (SearchHit hit : hits) {
            Map<String, Object> map = hit.getSourceAsMap();
            inList.add(map);
        }
        outList = change(inList, "fusionBatchNum", outList);
        outList.forEach(map-> {
                    JSONObject maps = JSONObject.parseObject(JSON.toJSONString(map));
//            JSONObject maps = new JSONObject();
//            Iterator it = map.keySet().iterator();
//            while (it.hasNext()) {
//                String key = (String) it.next();
//                maps.put(key, map.get(key));
//            }
                    JSONArray jsonArray = JSONArray.parseArray(maps.getString("array"));
                    if (jsonArray.size() > 0) {
                        JSONObject job = jsonArray.getJSONObject(0);
                        LeaceOutDto dto = new LeaceOutDto();
                        dto.setBatchNumber(job.getString("fusionBatchNum"));
            dto.setCount((long) jsonArray.size());
            dtos.add(dto);
                    }
                });
//        Aggregations aggregations = search.getAggregations();
//        ParsedStringTerms aggregation = aggregations.get("ship_field_agg");
//        for (Terms.Bucket bucket : aggregation.getBuckets()) {
//            LeaceOutDto dto = new LeaceOutDto();
//            dto.setBatchNumber(bucket.getKeyAsString());
//            dto.setCount(bucket.getDocCount());
//            dtos.add(dto);
//        }
        dtos.forEach(item->{
            LeaveOutData data = new LeaveOutData();
            SearchRequest request2 = new SearchRequest(INDEX_SEAT_REALTIMETRAJECTORY+time);
            // 构建查询条件
            BoolQueryBuilder boolQueryBuilder2 = QueryBuilders.boolQuery();
            SearchSourceBuilder searchSourceBuilder2 = new SearchSourceBuilder();
            boolQueryBuilder2.filter(QueryBuilders.wildcardQuery("trackDeviceNo", "*,"+ item.getBatchNumber() +",*"));
            boolQueryBuilder2.filter(QueryBuilders.rangeQuery("mergeTime").gte(query.getStartTime()).lte(query.getEndTime()));
            boolQueryBuilder2.filter(QueryBuilders.termsQuery("mergeType","RADAR","AIS_RADAR","BEIDOU_RADAR","AIS_BEIDOU_RADAR"));
            searchSourceBuilder2.query(boolQueryBuilder2)
                    .trackTotalHits(true)
                    .size(query.getPageSize())
                    .timeout(TimeValue.timeValueHours(1L))
                    .timeout(TimeValue.timeValueMinutes(30L))
                    .timeout(TimeValue.timeValueSeconds(500L));
            request2.source(searchSourceBuilder2);
            try {
                SearchResponse search2 = client.search(request2, COMMON_OPTIONS);
                SearchHits searchHits2 = search2.getHits();
                Long totalHits = searchHits2.getTotalHits().value;
                if (totalHits<5) {
                    SearchHit[] hits2 = searchHits2.getHits();
                    if (hits2.length > 0) {
                        JSONObject sourceItem = JSONObject.parseObject(hits2[0].getSourceAsString());
                        data.setMergeTarget(sourceItem.getString("mergeTarget"));
                        data.setStartTime(query.getStartTime());
                        data.setEndTime(query.getEndTime());
                        data.setBatchNumber(item.getBatchNumber());
                        data.setOriginalCount(item.getCount());
                        data.setTrackCount(totalHits);
                        list.add(data);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("天奥轨迹数据遗漏", "UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), LeaveOutData.class).sheet("天奥轨迹数据遗漏")
                    .doWrite(list);
        } catch (Exception e) {
            // 重置response
            System.out.println("导出天奥轨迹数据遗漏excel失败:{}" + e.getMessage() + e);
        }
    }

    @Override
    public void beiDouLeaveOutExcel(FusionQuery query, HttpServletResponse response) throws IOException, ParseException {
        List<LeaveOutData> list = new ArrayList<>();
        List<LeaceOutDto> dtos = new ArrayList<>();
        Date startTime = DateUtils.parse(query.getStartTime(),"yyyy-MM-dd");
        String time = DateUtils.format(startTime,"yyyy-MM-dd");
        SearchRequest request = new SearchRequest(INDEX_SEAT_TRACK_BEIDOU+time);
        // 构建查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        boolQueryBuilder.filter(QueryBuilders.rangeQuery("locationTime").gte(query.getStartTime()).lte(query.getEndTime()));
        searchSourceBuilder.query(boolQueryBuilder);
//        TermsAggregationBuilder aggBuilder = AggregationBuilders.terms("ship_field_agg")
//                .field("fusionBatchNum")
//                .size(query.getPageSize());
        searchSourceBuilder
                .trackTotalHits(true)
//                .aggregation(aggBuilder)
                .size(query.getPageSize())
                .sort(SortBuilders.fieldSort("locationTime").order(SortOrder.ASC))
                .timeout(TimeValue.timeValueHours(1L))
                .timeout(TimeValue.timeValueMinutes(30L))
                .timeout(TimeValue.timeValueSeconds(500L));
        request.source(searchSourceBuilder);
        SearchResponse search = client.search(request, COMMON_OPTIONS);
        SearchHits searchHits = search.getHits();
        SearchHit[] hits = searchHits.getHits();
        List<Map<String, Object>> inList = new ArrayList<Map<String, Object>>();
        List<Map<String, Object>> outList = new ArrayList<Map<String, Object>>();
        for (SearchHit hit : hits) {
            Map<String, Object> map = hit.getSourceAsMap();
            inList.add(map);
        }
        outList = change(inList, "devideNo", outList);
        outList.forEach(map-> {
            JSONObject maps = JSONObject.parseObject(JSON.toJSONString(map));
//            JSONObject maps = new JSONObject();
//            Iterator it = map.keySet().iterator();
//            while (it.hasNext()) {
//                String key = (String) it.next();
//                maps.put(key, map.get(key));
//            }
            JSONArray jsonArray = JSONArray.parseArray(maps.getString("array"));
            if (jsonArray.size() > 0) {
                JSONObject job = jsonArray.getJSONObject(0);
                LeaceOutDto dto = new LeaceOutDto();
                dto.setBatchNumber(job.getString("devideNo"));
                dto.setCount((long) jsonArray.size());
                dtos.add(dto);
            }
        });
//        Aggregations aggregations = search.getAggregations();
//        ParsedStringTerms aggregation = aggregations.get("ship_field_agg");
//        for (Terms.Bucket bucket : aggregation.getBuckets()) {
//            LeaceOutDto dto = new LeaceOutDto();
//            dto.setBatchNumber(bucket.getKeyAsString());
//            dto.setCount(bucket.getDocCount());
//            dtos.add(dto);
//        }
        dtos.forEach(item->{
            LeaveOutData data = new LeaveOutData();
            SearchRequest request2 = new SearchRequest(INDEX_SEAT_REALTIMETRAJECTORY+time);
            // 构建查询条件
            BoolQueryBuilder boolQueryBuilder2 = QueryBuilders.boolQuery();
            SearchSourceBuilder searchSourceBuilder2 = new SearchSourceBuilder();
            boolQueryBuilder2.filter(QueryBuilders.wildcardQuery("trackDeviceNo", "*,"+ item.getBatchNumber() +",*"));
            boolQueryBuilder2.filter(QueryBuilders.rangeQuery("mergeTime").gte(query.getStartTime()).lte(query.getEndTime()));
            boolQueryBuilder2.filter(QueryBuilders.termsQuery("mergeType","BEIDOU","AIS_BEIDOU","BEIDOU_RADAR","AIS_BEIDOU_RADAR"));
            searchSourceBuilder2.query(boolQueryBuilder2)
                    .trackTotalHits(true)
                    .size(query.getPageSize())
                    .timeout(TimeValue.timeValueHours(1L))
                    .timeout(TimeValue.timeValueMinutes(30L))
                    .timeout(TimeValue.timeValueSeconds(500L));
            request2.source(searchSourceBuilder2);
            try {
                SearchResponse search2 = client.search(request2, COMMON_OPTIONS);
                SearchHits searchHits2 = search2.getHits();
                Long totalHits = searchHits2.getTotalHits().value;
                if (totalHits<5) {
                    SearchHit[] hits2 = searchHits2.getHits();
                    if (hits2.length > 0) {
                        JSONObject sourceItem = JSONObject.parseObject(hits2[0].getSourceAsString());
                        data.setMergeTarget(sourceItem.getString("mergeTarget"));
                        data.setStartTime(query.getStartTime());
                        data.setEndTime(query.getEndTime());
                        data.setBatchNumber(item.getBatchNumber());
                        data.setOriginalCount(item.getCount());
                        data.setTrackCount(totalHits);
                        list.add(data);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("北斗轨迹数据遗漏", "UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), LeaveOutData.class).sheet("北斗轨迹数据遗漏")
                    .doWrite(list);
        } catch (Exception e) {
            // 重置response
            System.out.println("导出北斗轨迹数据遗漏excel失败:{}" + e.getMessage() + e);
        }
    }

    @Override
    public void hlxyjrhLeaveOutExcel(FusionQuery query, HttpServletResponse response) throws IOException, ParseException {
        List<LeaveOutData> list = new ArrayList<>();
        List<LeaceOutDto> dtos = new ArrayList<>();
        Date startTime = DateUtils.parse(query.getStartTime(),"yyyy-MM-dd");
        String time = DateUtils.format(startTime,"yyyy-MM-dd");
        SearchRequest request = new SearchRequest(INDEX_SEAT_HLX_FUSION_SHIP+time);
        // 构建查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        boolQueryBuilder.filter(QueryBuilders.rangeQuery("time").gte(query.getStartTime()).lte(query.getEndTime()));
        searchSourceBuilder.query(boolQueryBuilder);
//        TermsAggregationBuilder aggBuilder = AggregationBuilders.terms("ship_field_agg")
//                .field("fusionBatchNum")
//                .size(query.getPageSize());
        searchSourceBuilder
                .trackTotalHits(true)
//                .aggregation(aggBuilder)
                .size(query.getPageSize())
                .sort(SortBuilders.fieldSort("time").order(SortOrder.ASC))
                .timeout(TimeValue.timeValueHours(1L))
                .timeout(TimeValue.timeValueMinutes(30L))
                .timeout(TimeValue.timeValueSeconds(500L));
        request.source(searchSourceBuilder);
        SearchResponse search = client.search(request, COMMON_OPTIONS);
        SearchHits searchHits = search.getHits();
        SearchHit[] hits = searchHits.getHits();
        List<Map<String, Object>> inList = new ArrayList<Map<String, Object>>();
        List<Map<String, Object>> outList = new ArrayList<Map<String, Object>>();
        for (SearchHit hit : hits) {
            Map<String, Object> map = hit.getSourceAsMap();
            inList.add(map);
        }
        outList = change(inList, "targetID", outList);
        outList.forEach(map-> {
            JSONObject maps = JSONObject.parseObject(JSON.toJSONString(map));
//            JSONObject maps = new JSONObject();
//            Iterator it = map.keySet().iterator();
//            while (it.hasNext()) {
//                String key = (String) it.next();
//                maps.put(key, map.get(key));
//            }
            JSONArray jsonArray = JSONArray.parseArray(maps.getString("array"));
            if (jsonArray.size() > 0) {
                JSONObject job = jsonArray.getJSONObject(0);
                LeaceOutDto dto = new LeaceOutDto();
                dto.setBatchNumber(job.getString("targetID"));
                dto.setCount((long) jsonArray.size());
                dtos.add(dto);
            }
        });
//        Aggregations aggregations = search.getAggregations();
//        ParsedStringTerms aggregation = aggregations.get("ship_field_agg");
//        for (Terms.Bucket bucket : aggregation.getBuckets()) {
//            LeaceOutDto dto = new LeaceOutDto();
//            dto.setBatchNumber(bucket.getKeyAsString());
//            dto.setCount(bucket.getDocCount());
//            dtos.add(dto);
//        }
        dtos.forEach(item->{
            LeaveOutData data = new LeaveOutData();
            SearchRequest request2 = new SearchRequest(INDEX_SEAT_REALTIMETRAJECTORY+time);
            // 构建查询条件
            BoolQueryBuilder boolQueryBuilder2 = QueryBuilders.boolQuery();
            SearchSourceBuilder searchSourceBuilder2 = new SearchSourceBuilder();
            boolQueryBuilder2.filter(QueryBuilders.wildcardQuery("trackDeviceNo", "*,"+ item.getBatchNumber() +",*"));
            boolQueryBuilder2.filter(QueryBuilders.rangeQuery("mergeTime").gte(query.getStartTime()).lte(query.getEndTime()));
            boolQueryBuilder2.filter(QueryBuilders.termsQuery("mergeType","AIS","RADAR","AIS_BEIDOU","AIS_RADAR","BEIDOU_RADAR","AIS_BEIDOU_RADAR"));
            searchSourceBuilder2.query(boolQueryBuilder2)
                    .trackTotalHits(true)
                    .size(query.getPageSize())
                    .timeout(TimeValue.timeValueHours(1L))
                    .timeout(TimeValue.timeValueMinutes(30L))
                    .timeout(TimeValue.timeValueSeconds(500L));
            request2.source(searchSourceBuilder2);
            try {
                SearchResponse search2 = client.search(request2, COMMON_OPTIONS);
                SearchHits searchHits2 = search2.getHits();
                Long totalHits = searchHits2.getTotalHits().value;
                if (totalHits<5) {
                    SearchHit[] hits2 = searchHits2.getHits();
                    if (hits2.length > 0) {
                        JSONObject sourceItem = JSONObject.parseObject(hits2[0].getSourceAsString());
                        data.setMergeTarget(sourceItem.getString("mergeTarget"));
                        data.setStartTime(query.getStartTime());
                        data.setEndTime(query.getEndTime());
                        data.setBatchNumber(item.getBatchNumber());
                        data.setOriginalCount(item.getCount());
                        data.setTrackCount(totalHits);
                        list.add(data);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("海兰信1级融合轨迹数据遗漏", "UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), LeaveOutData.class).sheet("海兰信1级融合轨迹数据遗漏")
                    .doWrite(list);
        } catch (Exception e) {
            // 重置response
            System.out.println("导出海兰信1级融合轨迹数据遗漏excel失败:{}" + e.getMessage() + e);
        }
    }

    @Override
    public void tianaoStaticOrDynamicLeaveOutExcel(FusionQuery query, HttpServletResponse response) throws IOException, ParseException {
        List<StaticOrDynamicData> list = new ArrayList<>();
        List<LeaceOutDto> dtos = new ArrayList<>();
        Date startTime = DateUtils.parse(query.getStartTime(),"yyyy-MM-dd");
        String time = DateUtils.format(startTime,"yyyy-MM-dd");
        SearchRequest request = new SearchRequest(INDEX_SEAT_TRACK_RADAR+time);
        // 构建查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        boolQueryBuilder.filter(QueryBuilders.rangeQuery("receiveTime").gte(query.getStartTime()).lte(query.getEndTime()));
        boolQueryBuilder.filter(QueryBuilders.termQuery("targetProper","1"));
        searchSourceBuilder.query(boolQueryBuilder);
//        TermsAggregationBuilder aggBuilder = AggregationBuilders.terms("ship_field_agg")
//                .field("fusionBatchNum")
//                .size(query.getPageSize());
        searchSourceBuilder
                .trackTotalHits(true)
//                .aggregation(aggBuilder)
                .size(query.getPageSize())
                .timeout(TimeValue.timeValueHours(1L))
                .timeout(TimeValue.timeValueMinutes(30L))
                .timeout(TimeValue.timeValueSeconds(500L));
        request.source(searchSourceBuilder);
        SearchResponse search = client.search(request, COMMON_OPTIONS);
        SearchHits searchHits = search.getHits();
        SearchHit[] hits = searchHits.getHits();
        List<Map<String, Object>> inList = new ArrayList<Map<String, Object>>();
        List<Map<String, Object>> outList = new ArrayList<Map<String, Object>>();
        for (SearchHit hit : hits) {
            Map<String, Object> map = hit.getSourceAsMap();
            inList.add(map);
        }
        outList = change(inList, "fusionBatchNum", outList);
        outList.forEach(map-> {
            JSONObject maps = JSONObject.parseObject(JSON.toJSONString(map));
//            JSONObject maps = new JSONObject();
//            Iterator it = map.keySet().iterator();
//            while (it.hasNext()) {
//                String key = (String) it.next();
//                maps.put(key, map.get(key));
//            }
            JSONArray jsonArray = JSONArray.parseArray(maps.getString("array"));
            if (jsonArray.size() > 0) {
                JSONObject job = jsonArray.getJSONObject(0);
                LeaceOutDto dto = new LeaceOutDto();
                dto.setBatchNumber(job.getString("fusionBatchNum"));
                dto.setCount((long) jsonArray.size());
                dtos.add(dto);
            }
        });
        dtos.forEach(item->{
            StaticOrDynamicData data = new StaticOrDynamicData();
            SearchRequest request2 = new SearchRequest(INDEX_SEAT_REALTIMETRAJECTORY+time);
            // 构建查询条件
            BoolQueryBuilder boolQueryBuilder2 = QueryBuilders.boolQuery();
            SearchSourceBuilder searchSourceBuilder2 = new SearchSourceBuilder();
            boolQueryBuilder2.filter(QueryBuilders.wildcardQuery("trackDeviceNo", "*,"+ item.getBatchNumber() +",*"));
            boolQueryBuilder2.filter(QueryBuilders.termQuery("targetType","0"));
            boolQueryBuilder2.filter(QueryBuilders.rangeQuery("mergeTime").gte(query.getStartTime()).lte(query.getEndTime()));
            boolQueryBuilder2.filter(QueryBuilders.termsQuery("mergeType","RADAR","AIS_RADAR","BEIDOU_RADAR","AIS_BEIDOU_RADAR"));
            searchSourceBuilder2.query(boolQueryBuilder2)
                    .trackTotalHits(true)
                    .size(query.getPageSize())
                    .timeout(TimeValue.timeValueHours(1L))
                    .timeout(TimeValue.timeValueMinutes(30L))
                    .timeout(TimeValue.timeValueSeconds(500L));
            request2.source(searchSourceBuilder2);
            try {
                SearchResponse search2 = client.search(request2, COMMON_OPTIONS);
                SearchHits searchHits2 = search2.getHits();
                SearchHit[] hits2 = searchHits2.getHits();
                if (hits2.length > 0) {
                    JSONObject sourceItem = JSONObject.parseObject(hits2[0].getSourceAsString());
                    data.setMergeTarget(sourceItem.getString("mergeTarget"));
                    data.setBatchNumber(item.getBatchNumber());
                    list.add(data);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            String fileName = URLEncoder.encode("天奥静态数据与动态轨迹融合", "UTF-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), StaticOrDynamicData.class).sheet("天奥静态数据与动态轨迹融合")
                    .doWrite(list);
        } catch (Exception e) {
            // 重置response
            System.out.println("导出天奥静态数据与动态轨迹融合excel失败:{}" + e.getMessage() + e);
        }
    }

    /**
     * 按照List<Map<String,Object>>里面map的某个value重新封装成多个不同的list, 原始数据类型List<Map<String,Object>>, 转换后数据类型Map<String,List<Map<String,Object>>>
     * @param inList
     * @param oneMapKey
     * @param outList
     * @return
     */
    private static List<Map<String, Object>> change(List<Map<String, Object>> inList, String oneMapKey,
                                                    List<Map<String, Object>> outList) {
        // 1.将某个key的值存在set中
        Set<Object> setTmp = new HashSet<Object>();
        for (Map<String, Object> tmp : inList) {
            setTmp.add(tmp.get(oneMapKey));
        }
        // 2.遍历set
        Iterator<Object> it = setTmp.iterator();
        while (it.hasNext()) {
            String oneMapValueStr = "";
            String oneSetTmpStr = (String) it.next();
            Map<String, Object> oneSetTmpMap = new HashMap<String, Object>();
            List<Map<String, Object>> oneSetTmpList = new ArrayList<Map<String, Object>>();

            for (Map<String, Object> tmp : inList) {
                oneMapValueStr = (String) tmp.get(oneMapKey);
                if (oneSetTmpStr.equals(oneMapValueStr)) {
                    oneSetTmpMap.put("text", oneSetTmpStr);
                    oneSetTmpList.add(tmp);
                }
            }
            oneSetTmpMap.put("array", oneSetTmpList);
            outList.add(oneSetTmpMap);
        }
        return outList;
    }
}


class text{
    @Autowired
    public RestHighLevelClient client;

    public static void main(String[] args) {
        String source = "[{\"track_device_no\":\"15013798\",\"track_id\":\"15013798\",\"id\":\"82717282\",\"time\":\"2023 - 02 - 07 00: 59: 30.069\",\"type\":\"BEIDOU\"}]";
        String json = JSON.toJSONString(source);
        System.out.println(json);

    }
}