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

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yeejoin.amos.boot.biz.common.bo.ReginParams;
import com.yeejoin.amos.boot.biz.common.dto.CountDto;
import com.yeejoin.amos.boot.biz.common.dto.JyjcInspectionApplicationDto;
import com.yeejoin.amos.boot.biz.common.utils.RedisKey;
import com.yeejoin.amos.boot.module.common.api.dto.AttachmentDto;
import com.yeejoin.amos.boot.module.common.api.dto.DPFilterParamDto;
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.entity.JyjcInspectionApplication;
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.JyjcInspectionApplicationEquipMapper;
import com.yeejoin.amos.boot.module.jyjc.api.mapper.JyjcInspectionApplicationMapper;
import com.yeejoin.amos.boot.module.jyjc.api.mapper.JyjcInspectionResultMapper;
import com.yeejoin.amos.boot.module.jyjc.api.mapper.JyjcOpeningApplicationMapper;
import com.yeejoin.amos.boot.module.statistics.api.mapper.JYJCStatisticsMapper;
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.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.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

import javax.validation.constraints.NotBlank;
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.stream.Collectors;

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

    /**
     * 压力容器设备种类
     */
    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 JyjcInspectionResultMapper inspectionResultMapper;

    private JyjcOpeningApplicationMapper openingApplicationMapper;

    private RestHighLevelClient restHighLevelClient;

    private StCommonServiceImpl stCommonService;

    private JYJCStatisticsMapper jyjcStatisticsMapper;

    /**
     * 法定检验机构名单
     */
    @Value("${jyjc.legal.companyCode:12610100750228848W,12610300MB2943942F,12610400435630992M,12610200435252143F,126105007326878566,12610600MB29845683,126108004366752362,12610700MB296441XY,12610900353680128G,126110004363154256,126100004352004822}")
    private String legalCompanyCodes;

    public JYJCDPStatisticsServiceImpl(EquipmentCategoryMapper equipmentCategoryMapper, JyjcInspectionApplicationEquipMapper inspectionApplicationEquipMapper, JyjcInspectionApplicationMapper inspectionApplicationMapper, TzsUserInfoMapper tzsUserInfoMapper, JyjcInspectionResultMapper inspectionResultMapper, JyjcOpeningApplicationMapper openingApplicationMapper, RestHighLevelClient restHighLevelClient, StCommonServiceImpl stCommonService, JYJCStatisticsMapper jyjcStatisticsMapper) {
        this.equipmentCategoryMapper = equipmentCategoryMapper;
        this.inspectionApplicationEquipMapper = inspectionApplicationEquipMapper;
        this.inspectionApplicationMapper = inspectionApplicationMapper;
        this.tzsUserInfoMapper = tzsUserInfoMapper;
        this.inspectionResultMapper = inspectionResultMapper;
        this.openingApplicationMapper = openingApplicationMapper;
        this.restHighLevelClient = restHighLevelClient;
        this.stCommonService = stCommonService;
        this.jyjcStatisticsMapper = jyjcStatisticsMapper;
    }


    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 = stCommonService.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(cn.hutool.core.date.DateUtil.offsetDay(new Date(), -30).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 = stCommonService.setRegionIfRootParent(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 void buildYDataForInspectPersonCount(Map<String, Object> result, List<RegionModel> childRegion) {
        List<Long> yData = new ArrayList<>();
        childRegion.forEach(regionModel -> {
            String orgCode = stCommonService.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 List<String> getXDataForInspectPersonCount(List<RegionModel> childRegion) {
        return childRegion.stream().map(RegionModel::getRegionName).collect(Collectors.toList());
    }


    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 = stCommonService.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 = stCommonService.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 = stCommonService.getAndSetOrgCode(dpFilterParamDto.getCityCode());
        return inspectionResultMapper.queryInspectionTimelinessTopXX(top, orgCode, dpFilterParamDto);
    }

    public List<PublicityInspectOrgInfoDto> queryInspectionOrgListForPublicity(DPFilterParamDto dpFilterParamDto) {
        String orgCode = stCommonService.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 = stCommonService.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<>();
        String orgCode = stCommonService.getAndSetOrgCode(dpFilterParamDto.getCityCode());
        if (StringUtils.isEmpty(orgCode)) {
            return result;
        }
        // 1.气瓶统计
        long cylinderNum = stCommonService.staticsCenterMapCountDataForCylinder(result, orgCode);
        // 2.8大类统计
        stCommonService.staticsCenterMapCountDataForEquip(result, cylinderNum, orgCode);
        // 3.压力管道统计
        stCommonService.staticsCenterMapCountDataForPipeline(result, orgCode);
        // 4.报检数量统计
        this.staticsCenterMapCountDataReporting(result, dpFilterParamDto);
        // 5.检验检测临期设备数数量统计
        this.staticsCenterMapCountDataTemporary(result, dpFilterParamDto);
        // 6.检验检测超期设备数数量统计
        this.staticsCenterMapCountDataOverdue(result, dpFilterParamDto);
        // 7.检验机构总量 inspectionAgencyCount
        this.countAllRegInspectCompany(result, orgCode,dpFilterParamDto.getCityCode());
        // 8.第三方检验机构数量  thirdInspectionAgencyCount
        this.countAllRegThirdInspectCompany(result, orgCode,dpFilterParamDto.getCityCode());
        // 7.业务开通机构数量  bizKtCount
        this.countAllOpenBizInspectCompany(result, orgCode,dpFilterParamDto.getCityCode());
        return result;
    }

    private void countAllRegInspectCompany(Map<String, Object> result, String orgCode, String regionCode) {
        Long num = jyjcStatisticsMapper.countAllRegInspectCompany(orgCode,regionCode);
        result.put("inspectionAgencyCount", num);
    }

    private void countAllRegThirdInspectCompany(Map<String, Object> result, String orgCode, String regionCode) {
        Long num = jyjcStatisticsMapper.countAllRegThirdInspectCompany(orgCode, Arrays.asList(legalCompanyCodes.split(",")), regionCode);
        result.put("thirdInspectionAgencyCount", num);
    }

    private void countAllOpenBizInspectCompany(Map<String, Object> result, String orgCode, String regionCode) {
        Long num = jyjcStatisticsMapper.countAllOpenBizInspectCompany(orgCode, regionCode);
        result.put("bizKtCount", num);
    }

    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 = stCommonService.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();
        // 且查询 下次检验日期 <= 当前天+30天 极为临期
        long currentDayAfter30DayTime = DateUtil.offsetDay(DateUtil.parse(DateUtil.today(), "yyy-MM-dd"), 30).getTime();
        boolMust.must(QueryBuilders.rangeQuery("NEXT_INSPECT_DATE").gte(currentDayTime).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 = stCommonService.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 = stCommonService.getAndSetOrgCode(dpFilterParamDto.getCityCode());
        CountDto countDto = inspectionApplicationMapper.queryAppByEquListForReporting(orgCode, dpFilterParamDto);
        result.put("bjCount", countDto.getLongValue());
    }


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


    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 = stCommonService.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 = stCommonService.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);
    }



    public Page<JyjcInspectionApplicationDto> queryForInspectAppPageList(Page<JyjcInspectionApplicationDto> page, JyjcInspectionApplicationDto model) {
        String orgCode = stCommonService.getAndSetOrgCode(model.getCityCode());
        if(orgCode == null){
            page.setTotal(0);
            return page;
        }
        return jyjcStatisticsMapper.queryForInspectAppPageList(page, model, orgCode);
    }

    public JSONObject queryDetailsMatui(Long sequenceNbr, JSONObject jsonObject) {
        List<Map<String, Object>> dataByApplicationSeq = jyjcStatisticsMapper.getDataByApplicationSeq(sequenceNbr);
        Map<String, Object> attMap = new HashMap<>();
        for (Map<String, Object> maps : dataByApplicationSeq) {
            List<AttachmentDto> data = JSONArray.parseArray(maps.get("attachment_url").toString(), AttachmentDto.class);
            attMap.put(maps.get("attachment_type").toString(), data);
        }
        JSONArray subs = jsonObject.getJSONArray("subs");
        subs.stream().forEach(x -> {
            JSONObject xObj = (JSONObject) x;
            JSONArray datas = xObj.getJSONArray("datas");
            datas.stream().forEach(y -> {
                JSONObject yObj = (JSONObject) y;
                yObj.put("value", !ValidationUtil.isEmpty(attMap.get(yObj.getString("key"))) ? attMap.get(yObj.getString("key")) : new JSONArray());
            });
        });
        return jsonObject;
    }
}
