package com.yeejoin.amos.boot.module.jyjc.biz.service.impl;

import cn.hutool.core.date.DateUtil;
import com.yeejoin.amos.boot.biz.common.dto.CountDto;
import com.yeejoin.amos.boot.module.common.api.constant.TZSCommonConstant;
import com.yeejoin.amos.boot.module.common.api.dto.DPFilterParamDto;
import com.yeejoin.amos.boot.module.common.api.enums.ReginStepEnum;
import com.yeejoin.amos.boot.module.jyjc.api.dto.InspectTimeCountDto;
import com.yeejoin.amos.boot.module.jyjc.api.dto.InspectionTimelinesDto;
import com.yeejoin.amos.boot.module.jyjc.api.dto.PublicityInspectOrgInfoDto;
import com.yeejoin.amos.boot.module.jyjc.api.enums.BizTypeEnum;
import com.yeejoin.amos.boot.module.jyjc.api.enums.JYJCTypeEnum;
import com.yeejoin.amos.boot.module.jyjc.api.mapper.*;
import com.yeejoin.amos.boot.module.ymt.api.dto.EquipmentCategoryDto;
import com.yeejoin.amos.boot.module.ymt.api.enums.EquimentEnum;
import com.yeejoin.amos.boot.module.ymt.api.mapper.EquipmentCategoryMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.TzsUserInfoMapper;
import com.yeejoin.amos.component.feign.model.FeignClientResult;
import com.yeejoin.amos.feign.systemctl.Systemctl;
import com.yeejoin.amos.feign.systemctl.model.RegionModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.queryparser.classic.QueryParser;
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.client.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 大屏统计实现类
 *
 * @author Administrator
 */
@Service
@Slf4j
public class DPStatisticsServiceImpl {

    /**
     * 压力容器设备种类
     */
    private final static String EQU_LIST_CYLINDER = "2000";

    /**
     * 气瓶设备类别
     */
    private final static String EQU_CATEGORY_CYLINDER = "2300";

    private EquipmentCategoryMapper equipmentCategoryMapper;

    private JyjcInspectionApplicationEquipMapper inspectionApplicationEquipMapper;

    private JyjcInspectionApplicationMapper inspectionApplicationMapper;

    private TzsUserInfoMapper tzsUserInfoMapper;

    private JyjcBaseMapper jyjcBaseMapper;

    private JyjcInspectionResultMapper inspectionResultMapper;

    private JyjcOpeningApplicationMapper openingApplicationMapper;


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

    private static Map<String, List<RegionModel>> regionChildRegionMap = new ConcurrentHashMap<>();

    private RestHighLevelClient restHighLevelClient;

    public DPStatisticsServiceImpl(EquipmentCategoryMapper equipmentCategoryMapper, JyjcInspectionApplicationEquipMapper inspectionApplicationEquipMapper, JyjcInspectionApplicationMapper inspectionApplicationMapper, TzsUserInfoMapper tzsUserInfoMapper, JyjcBaseMapper jyjcBaseMapper, JyjcInspectionResultMapper inspectionResultMapper, JyjcOpeningApplicationMapper openingApplicationMapper, RestHighLevelClient restHighLevelClient) {
        this.equipmentCategoryMapper = equipmentCategoryMapper;
        this.inspectionApplicationEquipMapper = inspectionApplicationEquipMapper;
        this.inspectionApplicationMapper = inspectionApplicationMapper;
        this.tzsUserInfoMapper = tzsUserInfoMapper;
        this.jyjcBaseMapper = jyjcBaseMapper;
        this.inspectionResultMapper = inspectionResultMapper;
        this.openingApplicationMapper = openingApplicationMapper;
        this.restHighLevelClient = restHighLevelClient;
    }


    public Map<String, Object> inspectTimeCountByTypeAndEquList(DPFilterParamDto dpFilterParamDto) {
        // 1.查询条件构造未上送时间时，默认查询数据为近一个月数据
        this.setDefaultFilter(dpFilterParamDto);
        // 2.按照前端约定格式返回数据
        Map<String, Object> result = new HashMap<>();
        //2.1 图列数据构造
        List<BizTypeEnum> bizTypeEnums = getBizTypeList();
        result.put("legendData", this.getLegendData(bizTypeEnums));
        // 8大类设备种类
        List<EquipmentCategoryDto> equipmentCategoryDtos = equipmentCategoryMapper.selectClassify();
        //2.2 x轴数据构造
        result.put("xdata", this.getXData(equipmentCategoryDtos));
        //2.3 y轴数据构造
        this.buildYData(result, bizTypeEnums, dpFilterParamDto, equipmentCategoryDtos);
        return result;
    }

    private void buildYData(Map<String, Object> result, List<BizTypeEnum> bizTypeEnums, DPFilterParamDto dpFilterParamDto, List<EquipmentCategoryDto> equipmentCategoryDtos) {
        String orgCode = this.getAndSetOrgCode(dpFilterParamDto.getCityCode());
        // 待统计的数据本来sql可以单独统计，但是要求气瓶单独从压力容器里拎出来，与八大类同级，故java处理
        List<InspectTimeCountDto> inspectTimeCountDtos = inspectionApplicationEquipMapper.countInspectTimeCountByTypeAndEquList(orgCode,dpFilterParamDto);
        bizTypeEnums.forEach(bizTypeEnum -> {
            result.put(bizTypeEnum.getCode(), this.countNumByBizTypeAndEquList(equipmentCategoryDtos, bizTypeEnum.getCode(), inspectTimeCountDtos));
        });
    }

    private List<Integer> countNumByBizTypeAndEquList(List<EquipmentCategoryDto> equipmentCategoryDtos, String bizType, List<InspectTimeCountDto> inspectTimeCountDtos) {
        List<Integer> item = new ArrayList<>();
        // 8大类数据统计数量
        equipmentCategoryDtos.forEach(equipmentCategoryDto -> {
            int num = 0;
            // 压力容器要去掉气瓶2300，气瓶单独统计
            if (EQU_LIST_CYLINDER.equals(equipmentCategoryDto.getCode())) {
                num = inspectTimeCountDtos.stream().filter(c -> c.getBizType().equals(bizType) && c.getEquList().equals(equipmentCategoryDto.getCode()) && !EQU_CATEGORY_CYLINDER.equals(c.getEquCategory())).mapToInt(InspectTimeCountDto::getNum).sum();
            } else {
                num = inspectTimeCountDtos.stream().filter(c -> c.getBizType().equals(bizType) && c.getEquList().equals(equipmentCategoryDto.getCode())).mapToInt(InspectTimeCountDto::getNum).sum();
            }
            item.add(num);
        });
        // 再增加气瓶(设备类别2300)专项
        int num = inspectTimeCountDtos.stream().filter(c -> c.getBizType().equals(bizType) && EQU_CATEGORY_CYLINDER.equals(c.getEquCategory())).mapToInt(InspectTimeCountDto::getNum).sum();
        item.add(num);
        return item;
    }

    private List<String> getXData(List<EquipmentCategoryDto> equipmentCategoryDtos) {
        // 8大类  + 气瓶 注意数据顺序和要和这个x轴一致
        List<String> names = equipmentCategoryDtos.stream().map(EquipmentCategoryDto::getName).collect(Collectors.toList());
        names.add("气瓶");
        return names;
    }

    private List<BizTypeEnum> getBizTypeList() {
        return Arrays.asList(BizTypeEnum.FIRST_INSPECTION, BizTypeEnum.SUPERVISE, BizTypeEnum.DETECTION);
    }

    private List<Map<String, Object>> getLegendData(List<BizTypeEnum> bizTypeEnums) {
        return bizTypeEnums.stream().map(b -> {
            Map<String, Object> item = new HashMap<>();
            item.put("dataKey", b.getCode());
            item.put("value", b.getName());
            return item;
        }).collect(Collectors.toList());
    }

    private void setDefaultFilter(DPFilterParamDto dpFilterParamDto) {
        if (StringUtils.isEmpty(dpFilterParamDto.getBeginDate())) {
            dpFilterParamDto.setBeginDate(DateUtil.lastMonth().toDateStr());
        }
        if (StringUtils.isEmpty(dpFilterParamDto.getEndDate())) {
            dpFilterParamDto.setEndDate(DateUtil.today());
        }
    }

    public Map<String, Object> inspectTimeCount(DPFilterParamDto dpFilterParamDto) {
        Map<String, Object> returnMap = new HashMap<>();
        LocalDate today = LocalDate.now();
        List xDataList = new ArrayList();
        List<Integer> yDataList = new ArrayList();
        DateTimeFormatter sdf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        for (int i = 2; i >= 0; i--) {
            LocalDate firstDayOfPrevMonth = today.minusMonths(i).with(TemporalAdjusters.firstDayOfMonth());
            LocalDate lastDayOfPrevMonth = today.minusMonths(i).with(TemporalAdjusters.lastDayOfMonth());
            dpFilterParamDto.setBeginDate(LocalDateTime.of(firstDayOfPrevMonth, java.time.LocalTime.MIN).format(sdf));
            dpFilterParamDto.setEndDate(LocalDateTime.of(lastDayOfPrevMonth, java.time.LocalTime.MAX).format(sdf));
            Integer inspectTimeCount = inspectionApplicationEquipMapper.inspectTimeCount(dpFilterParamDto);
            xDataList.add(firstDayOfPrevMonth.getMonthValue() + "月");
            yDataList.add(null == inspectTimeCount ? 0 : inspectTimeCount);
        }
        returnMap.put("xdata", xDataList);
        returnMap.put("ydata", yDataList);
        return returnMap;
    }

    public Map<String, Object> inspectPersonCount(DPFilterParamDto dpFilterParamDto) {
        // 2.按照前端约定格式返回数据
        Map<String, Object> result = new HashMap<>();
        List<RegionModel> childRegion = this.getRegionList(dpFilterParamDto);
        if (childRegion.isEmpty()) {
            return new HashMap<>(0);
        }
        //2.1 x轴数据构造
        result.put("xdata", this.getXDataForInspectPersonCount(childRegion));
        //2.3 y轴数据构造
        this.buildYDataForInspectPersonCount(result, childRegion);
        return result;
    }

    private List<RegionModel> setRegionIfRootParent(String regionCode) throws Exception {
        List<RegionModel> regionList = Systemctl.regionClient.queryByParentRegionCode(Integer.parseInt(regionCode)).getResult();
        // 陕西省时需要在地图返回独立的地级市:韩城、杨凌、西咸
        if (regionCode.equals(TZSCommonConstant.SHAN_XI_REGION_CODE)) {
            List<RegionModel> independentRegions = ReginStepEnum.enum2RegionList("map");
            regionList.addAll(independentRegions);
        }
        return regionList;
    }


    private void buildYDataForInspectPersonCount(Map<String, Object> result, List<RegionModel> childRegion) {
        List<Long> yData = new ArrayList<>();
        childRegion.forEach(regionModel -> {
            String orgCode = this.getAndSetOrgCode(regionModel.getRegionCode() + "");
            if (StringUtils.isEmpty(orgCode)) {
                yData.add(0L);
            } else {
                Long num = tzsUserInfoMapper.countUserByPostAndAreaCode(orgCode, "6615",regionModel.getRegionCode() + "");
                yData.add(num);
            }
        });
        result.put("ydata", yData);
    }

    private String getAndSetOrgCode(String regionCode) {
        String orgCode = regionCodeOrgCodeMap.get(regionCode);
        if (orgCode == null) {
            orgCode = jyjcBaseMapper.getOrgCodeByCompanyCode(regionCode);
            if (orgCode == null) {
                return "";
            }
            regionCodeOrgCodeMap.put(regionCode, orgCode);
        }
        return orgCode;
    }

    private List<String> getXDataForInspectPersonCount(List<RegionModel> childRegion) {
        return childRegion.stream().map(RegionModel::getRegionName).collect(Collectors.toList());
    }

    private List<RegionModel> getRegionList(DPFilterParamDto dpFilterParamDto) {
        try {
            if (regionChildRegionMap.get(dpFilterParamDto.getCityCode()) == null) {
                List<RegionModel> regionModels = this.setRegionIfRootParent(dpFilterParamDto.getCityCode());
                regionChildRegionMap.put(dpFilterParamDto.getCityCode(), regionModels);
                return regionModels;
            } else {
                return regionChildRegionMap.get(dpFilterParamDto.getCityCode());
            }
        } catch (Exception e) {
            log.error("查询行政区域失败：{}", e.getMessage());
        }
        return new ArrayList<>();
    }

    public Map<String, Object> queryAllFlowingAndFinishedInspectApp(DPFilterParamDto dpFilterParamDto) {
        // 1.查询条件构造未上送时间时，默认查询数据为近一个月数据
        this.setDefaultFilter(dpFilterParamDto);
        // 2.按照前端约定格式返回数据
        Map<String, Object> result = new HashMap<>();
        JYJCTypeEnum[] jyjcTypeEnums = JYJCTypeEnum.values();
        //2.1 x轴数据构造
        result.put("xdata", this.getXDataForInspectBizNumCount(jyjcTypeEnums));
        //2.3 y轴数据构造
        this.buildYDataForFlowingAndFinishedInspectApp(result, jyjcTypeEnums, dpFilterParamDto);
        return result;
    }

    public Map<String, Object> queryAllPendingResultInspectApp(DPFilterParamDto dpFilterParamDto) {
        // 1.查询条件构造未上送时间时，默认查询数据为近一个月数据
        this.setDefaultFilter(dpFilterParamDto);
        // 2.按照前端约定格式返回数据
        Map<String, Object> result = new HashMap<>();
        JYJCTypeEnum[] jyjcTypeEnums = JYJCTypeEnum.values();
        //2.1 x轴数据构造
        result.put("xdata", this.getXDataForInspectBizNumCount(jyjcTypeEnums));
        //2.3 y轴数据构造
        this.buildYDataForPendingResultInspectApp(result, jyjcTypeEnums, dpFilterParamDto);
        return result;
    }

    private void buildYDataForPendingResultInspectApp(Map<String, Object> result, JYJCTypeEnum[] jyjcTypeEnums, DPFilterParamDto dpFilterParamDto) {
        String orgCode = this.getAndSetOrgCode(dpFilterParamDto.getCityCode());
        List<CountDto> countDtoList = inspectionApplicationMapper.queryAllPendingResultInspectApp(orgCode, dpFilterParamDto);
        fillJYJCYData(result, jyjcTypeEnums, countDtoList);
    }

    private void fillJYJCYData(Map<String, Object> result, JYJCTypeEnum[] jyjcTypeEnums, List<CountDto> countDtoList) {
        List<Long> yData = new ArrayList<>();
        for (JYJCTypeEnum jyjcTypeEnum : jyjcTypeEnums) {
            Long num = countDtoList.stream().filter(c -> c.getKeyStr().equals(jyjcTypeEnum.getCode())).mapToLong(CountDto::getLongValue).sum();
            yData.add(num);
        }
        result.put("ydata", yData);
    }

    private void buildYDataForFlowingAndFinishedInspectApp(Map<String, Object> result, JYJCTypeEnum[] jyjcTypeEnums, DPFilterParamDto dpFilterParamDto) {
        String orgCode = this.getAndSetOrgCode(dpFilterParamDto.getCityCode());
        List<CountDto> countDtoList = inspectionApplicationMapper.queryAllFlowingAndFinishedInspectApp(orgCode, dpFilterParamDto);
        fillJYJCYData(result, jyjcTypeEnums, countDtoList);
    }

    private List<String> getXDataForInspectBizNumCount(JYJCTypeEnum[] jyjcTypeEnums) {
        return Arrays.stream(jyjcTypeEnums).map(JYJCTypeEnum::getName).collect(Collectors.toList());
    }

    public List<InspectionTimelinesDto> queryInspectionTimelinessTopXX(String top, DPFilterParamDto dpFilterParamDto) {
        String orgCode = this.getAndSetOrgCode(dpFilterParamDto.getCityCode());
        return inspectionResultMapper.queryInspectionTimelinessTopXX(top, orgCode, dpFilterParamDto);
    }

    public List<PublicityInspectOrgInfoDto> queryInspectionOrgListForPublicity(DPFilterParamDto dpFilterParamDto) {
        String orgCode = this.getAndSetOrgCode(dpFilterParamDto.getCityCode());
        return openingApplicationMapper.queryInspectionOrgListForPublicity(orgCode, dpFilterParamDto);
    }

    public Map<String, Object> queryInspectionEquipByEquList(DPFilterParamDto dpFilterParamDto) {
        Map<String, Object> result = new HashMap<>();
        // 1.查询条件构造未上送时间时，默认查询数据为近一个月数据
        this.setDefaultFilter(dpFilterParamDto);
        String orgCode = this.getAndSetOrgCode(dpFilterParamDto.getCityCode());
        // 2.x轴数据构建
        List<EquipmentCategoryDto> equipmentCategoryDtos = equipmentCategoryMapper.selectClassify();
        this.setXDataForInspectionEquipByEquList(result, equipmentCategoryDtos);
        // 3.y轴数据设置
        // 目前都单设备报检故统计主表即可
        List<CountDto> countDtos = inspectionApplicationMapper.queryAppByEquListForDP(orgCode, dpFilterParamDto);
        Map<String, List<CountDto>> groupByMap = countDtos.stream().collect(Collectors.groupingBy(CountDto::getLabel));
        this.setYDataForInspectionEquipByEquList(result, groupByMap, equipmentCategoryDtos);
        // 4.图列数据设置
        this.setLegendDataForInspectionEquipByEquList(result);
        return result;
    }

    private void setYDataForInspectionEquipByEquList(Map<String, Object> result, Map<String, List<CountDto>> groupByMap, List<EquipmentCategoryDto> equipmentCategoryDtos) {
        groupByMap.forEach((key, value) -> result.put(key, this.setInspectionEquipData(value, equipmentCategoryDtos)));
    }

    private List<Long> setInspectionEquipData(List<CountDto> countDtos, List<EquipmentCategoryDto> equipmentCategoryDtos) {
        return equipmentCategoryDtos.stream().map(e -> countDtos.stream().filter(c -> c.getKeyStr().equals(e.getCode())).mapToLong(CountDto::getLongValue).sum()).collect(Collectors.toList());
    }

    private void setLegendDataForInspectionEquipByEquList(Map<String, Object> result) {
        Map<String, Object> item1 = new LinkedHashMap<>();
        item1.put("dataKey", "pending");
        item1.put("value", "待检数量");
        Map<String, Object> item2 = new LinkedHashMap<>();
        item2.put("dataKey", "reporting");
        item2.put("value", "报检数量");
        result.put("legendData", Arrays.asList(item1, item2));
    }

    private void setXDataForInspectionEquipByEquList(Map<String, Object> result, List<EquipmentCategoryDto> equipmentCategoryDtos) {
        // 8大类
        List<String> names = equipmentCategoryDtos.stream().map(EquipmentCategoryDto::getName).collect(Collectors.toList());
        result.put("xdata", names);
    }


    private List<String> getEquListXDataCommon(List<EquipmentCategoryDto> equipmentCategoryDtos) {
        // 8大类
        return equipmentCategoryDtos.stream().map(EquipmentCategoryDto::getName).collect(Collectors.toList());
    }


    public Map<String, Object> getCenterMapCountDataForGlobal(DPFilterParamDto dpFilterParamDto) {
        Map<String, Object> result = new HashMap<>();
        // 1.报检数量统计
        this.staticsCenterMapCountDataReporting(result, dpFilterParamDto);
        // 2.检验检测临期设备数数量统计
        this.staticsCenterMapCountDataTemporary(result, dpFilterParamDto);
        // 3.检验检测超期设备数数量统计
        this.staticsCenterMapCountDataOverdue(result, dpFilterParamDto);
        return result;
    }

    private void staticsCenterMapCountDataTemporary(Map<String, Object> result, DPFilterParamDto dpFilterParamDto) {
        long num = 0;
        CountRequest request = new CountRequest();
        request.indices("idx_biz_view_jg_all");
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        String orgCode = this.getAndSetOrgCode(dpFilterParamDto.getCityCode());
        // 按照管辖机构区域信息模糊查询
        boolMust.must(QueryBuilders.wildcardQuery("ORG_BRANCH_CODE.keyword", QueryParser.escape(orgCode) + "*"));
        // 且在用状态设备
        boolMust.must(QueryBuilders.termQuery("EQU_STATE", EquimentEnum.ZAIYONG.getCode()));
        // 且下次检验日期大于等于当天
        long currentDayTime = DateUtil.parse(DateUtil.today(), "yyy-MM-dd").getTime();
        boolMust.must(QueryBuilders.rangeQuery("NEXT_INSPECT_DATE").gte(currentDayTime));
        // 且查询 下次检验日期 <= 当前天+30天 极为临期
        long currentDayAfter30DayTime = DateUtil.offsetDay(DateUtil.parse(DateUtil.today(), "yyy-MM-dd"), 30).getTime();
        boolMust.must(QueryBuilders.rangeQuery("NEXT_INSPECT_DATE").lte(currentDayAfter30DayTime));
        request.query(boolMust);
        try {
            CountResponse response = restHighLevelClient.count(request, RequestOptions.DEFAULT);
            num = response.getCount();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        result.put("jyjclqsbCount", num);
    }

    private void staticsCenterMapCountDataOverdue(Map<String, Object> result, DPFilterParamDto dpFilterParamDto) {
        long num = 0;
        CountRequest request = new CountRequest();
        request.indices("idx_biz_view_jg_all");
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        String orgCode = this.getAndSetOrgCode(dpFilterParamDto.getCityCode());
        // 按照管辖机构区域信息模糊查询
        boolMust.must(QueryBuilders.wildcardQuery("ORG_BRANCH_CODE.keyword", QueryParser.escape(orgCode) + "*"));
        // 在用状态设备
        boolMust.must(QueryBuilders.termQuery("EQU_STATE", EquimentEnum.ZAIYONG.getCode()));
        // 查询下次检验日期小于当前天的设备，即为超期检验超期设备
        long currentDayTime = DateUtil.parse(DateUtil.now(), "yyy-MM-dd").getTime();
        boolMust.must(QueryBuilders.rangeQuery("NEXT_INSPECT_DATE").lt(currentDayTime));
        request.query(boolMust);
        try {
            CountResponse response = restHighLevelClient.count(request, RequestOptions.DEFAULT);
            num = response.getCount();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        result.put("jyjccqsbCount", num);
    }


    private void staticsCenterMapCountDataReporting(Map<String, Object> result, DPFilterParamDto dpFilterParamDto) {
        String orgCode = this.getAndSetOrgCode(dpFilterParamDto.getCityCode());
        CountDto countDto = inspectionApplicationMapper.queryAppByEquListForReporting(orgCode, dpFilterParamDto);
        result.put("bjCount", countDto.getLongValue());
    }

    public List<Map<String, Object>> getCenterMapCountDataForOverview(DPFilterParamDto dpFilterParamDto) {
        return getRegionList(dpFilterParamDto).parallelStream().map(r -> {
            DPFilterParamDto filterParamDto = new DPFilterParamDto();
            filterParamDto.setCityCode(r.getRegionCode().toString());
            Map<String, Object> itemResult = getCenterMapOverviewData(filterParamDto);
            itemResult.put("regionCode", r.getRegionCode());
            itemResult.put("regionName", r.getRegionName());
            return itemResult;
        }).collect(Collectors.toList());
    }

    private Map<String, Object> getCenterMapOverviewData(DPFilterParamDto filterParamDto) {
        Map<String, Object> result = new HashMap<>();
        // 1.报检数量统计
        this.staticsCenterMapCountDataReporting(result, filterParamDto);
        // 2.检验检测临期设备数数量统计
        this.staticsCenterMapCountDataTemporary(result, filterParamDto);
        // 3.检验检测超期设备数数量统计
        this.staticsCenterMapCountDataOverdue(result, filterParamDto);
        return result;
    }

    public Map<String, Object> equipInspectTimeCountByEquList(DPFilterParamDto dpFilterParamDto) {
        // 1.按照前端约定格式返回数据
        Map<String, Object> result = new HashMap<>();
        // 1.1 图列数据构造
        result.put("legendData", this.getLegendDataForJyTime());
        // 8大类设备种类
        List<EquipmentCategoryDto> equipmentCategoryDtos = equipmentCategoryMapper.selectClassify();
        // 2.x轴数据构造
        result.put("xdata", this.getEquListXDataCommon(equipmentCategoryDtos));
        // 3.y轴数据构造
        this.buildYDataForJyTime(result, dpFilterParamDto, equipmentCategoryDtos);
        return result;
    }

    private void buildYDataForJyTime(Map<String, Object> result, DPFilterParamDto dpFilterParamDto, List<EquipmentCategoryDto> equipmentCategoryDtos) {
        // 1.检验检测临期设备数数量统计
        result.put("approach", staticsCenterMapCountDataForJyTimeTemporary(dpFilterParamDto, equipmentCategoryDtos));
        // 2.检验检测超期设备数数量统计
        result.put("overdue", staticsCenterMapCountDataForJyTimeOverdue(dpFilterParamDto, equipmentCategoryDtos));
    }

    private List<Long> staticsCenterMapCountDataForJyTimeTemporary(DPFilterParamDto dpFilterParamDto, List<EquipmentCategoryDto> equipmentCategoryDtos) {
        List<Long> seresData = new ArrayList<>();
        SearchRequest request = new SearchRequest();
        request.indices("idx_biz_view_jg_all");
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        String orgCode = this.getAndSetOrgCode(dpFilterParamDto.getCityCode());
        // 按照管辖机构区域信息模糊查询
        boolMust.must(QueryBuilders.wildcardQuery("ORG_BRANCH_CODE.keyword", QueryParser.escape(orgCode) + "*"));
        // 且在用状态设备
        boolMust.must(QueryBuilders.termQuery("EQU_STATE", EquimentEnum.ZAIYONG.getCode()));
        // 且下次检验日期大于等于当天 且查询 下次检验日期 <= 当前天+30天 极为临期
        long currentDayTime = DateUtil.parse(DateUtil.today(), "yyy-MM-dd").getTime();
        long currentDayAfter30DayTime = DateUtil.offsetDay(DateUtil.parse(DateUtil.today(), "yyy-MM-dd"), 30).getTime();
        boolMust.must(QueryBuilders.rangeQuery("NEXT_INSPECT_DATE").gte(currentDayTime).lte(currentDayAfter30DayTime));
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(boolMust);
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("count_by_equ_list_code").field("EQU_LIST_CODE");
        builder.aggregation(aggregationBuilder);
        request.source(builder);
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            Terms terms = response.getAggregations().get("count_by_equ_list_code");
            Map<String, Long> countMap = new HashMap<>();
            for (Terms.Bucket bucket : terms.getBuckets()) {
                countMap.put(bucket.getKeyAsString(), bucket.getDocCount());
            }
            // 按照8大类枚举，进行加工。目的：固定八大类防止没统计数据导致缺少分类、将设备种类的code换成前端定义的key
            equipmentCategoryDtos.forEach(c -> {
                seresData.add(countMap.getOrDefault(c.getCode(), 0L));
            });
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return seresData;
    }

    private List<Long> staticsCenterMapCountDataForJyTimeOverdue(DPFilterParamDto dpFilterParamDto, List<EquipmentCategoryDto> equipmentCategoryDtos) {
        List<Long> seresData = new ArrayList<>();
        SearchRequest request = new SearchRequest();
        request.indices("idx_biz_view_jg_all");
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        // 区域信息模糊查询
        String orgCode = this.getAndSetOrgCode(dpFilterParamDto.getCityCode());
        // 按照管辖机构区域信息模糊查询
        boolMust.must(QueryBuilders.wildcardQuery("ORG_BRANCH_CODE.keyword", QueryParser.escape(orgCode) + "*"));
        // 在用状态设备
        boolMust.must(QueryBuilders.termQuery("EQU_STATE", EquimentEnum.ZAIYONG.getCode()));
        // 查询下次检验日期小于当前天的设备，即为超期检验超期设备
        long currentDayTime = DateUtil.parse(DateUtil.now(), "yyy-MM-dd").getTime();
        boolMust.must(QueryBuilders.rangeQuery("NEXT_INSPECT_DATE").lt(currentDayTime));
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(boolMust);
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("count_by_equ_list_code").field("EQU_LIST_CODE");
        builder.aggregation(aggregationBuilder);
        request.source(builder);
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            Terms terms = response.getAggregations().get("count_by_equ_list_code");
            Map<String, Long> countMap = new HashMap<>();
            for (Terms.Bucket bucket : terms.getBuckets()) {
                countMap.put(bucket.getKeyAsString(), bucket.getDocCount());
            }
            // 按照8大类枚举，进行加工。目的：固定八大类防止没统计数据导致缺少分类、将设备种类的code换成前端定义的key
            equipmentCategoryDtos.forEach(c -> {
                seresData.add(countMap.getOrDefault(c.getCode(), 0L));
            });
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return seresData;
    }

    private Object getLegendDataForJyTime() {
        Map<String, Object> item1 = new LinkedHashMap<>();
        item1.put("dataKey", "approach");
        item1.put("value", "临期");
        Map<String, Object> item2 = new LinkedHashMap<>();
        item2.put("dataKey", "overdue");
        item2.put("value", "超期");
        return Arrays.asList(item1, item2);
    }
}
