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

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yeejoin.amos.boot.biz.common.dto.CountDto;
import com.yeejoin.amos.boot.biz.common.entity.DataDictionary;
import com.yeejoin.amos.boot.biz.common.service.impl.DataDictionaryServiceImpl;
import com.yeejoin.amos.boot.module.common.api.dto.DPFilterParamDto;
import com.yeejoin.amos.boot.module.common.api.dto.DPFilterParamForDateDto;
import com.yeejoin.amos.boot.module.common.api.dto.DPFilterParamForDetailDto;
import com.yeejoin.amos.boot.module.common.api.entity.AlertRescueStatistics;
import com.yeejoin.amos.boot.module.common.api.entity.AlertUseUnitStatistics;
import com.yeejoin.amos.boot.module.common.api.enums.AlertCallEnum;
import com.yeejoin.amos.boot.module.statistics.api.dto.AlertUseUnitStatisticsDto;
import com.yeejoin.amos.boot.module.statistics.api.mapper.AlertRescueStatisticsMapper;
import com.yeejoin.amos.boot.module.statistics.api.mapper.AlertStatisticsMapper;
import com.yeejoin.amos.boot.module.statistics.api.mapper.AlertUseUnitStatisticsMapper;
import com.yeejoin.amos.boot.module.ymt.api.dto.AlertPaperInfoDto;
import com.yeejoin.amos.boot.module.ymt.api.enums.DispatchPaperEnums;
import com.yeejoin.amos.boot.module.ymt.api.enums.EquipmentClassifityEnum;
import com.yeejoin.amos.boot.module.ymt.api.mapper.AlertCalledMapper;
import com.yeejoin.amos.boot.module.ymt.api.mapper.DispatchTaskMapper;
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.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.typroject.tyboot.core.foundation.utils.Bean;
import org.typroject.tyboot.core.foundation.utils.DateTimeUtil;
import org.typroject.tyboot.core.foundation.utils.DateUtil;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.restful.utils.ResponseHelper;
import org.typroject.tyboot.core.restful.utils.ResponseModel;

import java.io.IOException;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

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

    private AlertCalledMapper alertCalledMapper;

    private AlertRescueStatisticsMapper alertRescueStatisticsMapper;

    private AlertUseUnitStatisticsMapper alertUseUnitStatisticsMapper;

    private AlertStatisticsMapper alertStatisticsMapper;

    private DispatchTaskMapper dispatchTaskMapper;

    private RestHighLevelClient restHighLevelClient;

    private StCommonServiceImpl stCommonService;

    private DataDictionaryServiceImpl dataDictionaryService;

    private static final Map<String, String> BLL_LX_LEGEND = new LinkedHashMap<>();

    static {
        BLL_LX_LEGEND.put("trapped", "困人");
        BLL_LX_LEGEND.put("complaint", "投诉");
        BLL_LX_LEGEND.put("fault", "故障");
    }

    /**
     * 电梯设备品种
     */
    private final static String ELEVATOR_EQU_DEFINE_CODES = "3410,3420,3430,3310,3320,3210,3220,3120,3130,3110";


    public YJDPStatisticsServiceImpl(AlertCalledMapper alertCalledMapper, AlertRescueStatisticsMapper alertRescueStatisticsMapper, AlertUseUnitStatisticsMapper alertUseUnitStatisticsMapper, AlertStatisticsMapper alertStatisticsMapper, DispatchTaskMapper dispatchTaskMapper, RestHighLevelClient restHighLevelClient, StCommonServiceImpl stCommonService, DataDictionaryServiceImpl dataDictionaryService) {
        this.alertCalledMapper = alertCalledMapper;
        this.alertRescueStatisticsMapper = alertRescueStatisticsMapper;
        this.alertUseUnitStatisticsMapper = alertUseUnitStatisticsMapper;
        this.alertStatisticsMapper = alertStatisticsMapper;
        this.dispatchTaskMapper = dispatchTaskMapper;
        this.restHighLevelClient = restHighLevelClient;
        this.stCommonService = stCommonService;
        this.dataDictionaryService = dataDictionaryService;
    }

    public JSONObject eventStatByDay(DPFilterParamDto dpFilterParamDto) throws Exception {
        String beginDate = DateUtil.formatDate(DateTimeUtil.addDays(new Date(), -6), DateUtil.Y_M_D);
        String endDate = DateUtil.getNow(DateUtil.Y_M_D);
        String orgCode = stCommonService.getAndSetOrgCode(dpFilterParamDto);

        JSONObject jsonObject = new JSONObject();
        List<String> everyDay = this.getEveryDay(beginDate, endDate);
        this.buildLegendData(jsonObject);
        List<String> xdata = new ArrayList<>();
        List<Object> trapped = new ArrayList<>();
        List<Object> complaint = new ArrayList<>();
        List<Object> fault = new ArrayList<>();
        List<Map<String, Object>> maps = new ArrayList<>();
        if (orgCode != null) {
            maps = alertCalledMapper.queryNearlyList(beginDate, endDate, orgCode);
        }
        List<Map<String, Object>> finalMaps = maps;
        everyDay.forEach(day -> {
            try {
                xdata.add(DateUtil.formatDate(DateUtil.formatStringToDate(day, DateUtil.Y_M_D), "MM.dd"));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            Map<String, Object> map = finalMaps.stream().filter(x -> day.equals(x.get("day"))).collect(Collectors.toMap(
                    item -> (String) item.get("alarmType"),
                    item -> item.get("majorAlertCount")));
            trapped.add(!ValidationUtil.isEmpty(map.get("困人救援")) ? Integer.parseInt(map.get("困人救援").toString()) : 0);
            complaint.add(!ValidationUtil.isEmpty(map.get("投诉咨询")) ? Integer.parseInt(map.get("投诉咨询").toString()) : 0);
            fault.add(!ValidationUtil.isEmpty(map.get("故障维修")) ? Integer.parseInt(map.get("故障维修").toString()) : 0);
        });
        jsonObject.put("xdata", xdata);
        jsonObject.put("trapped", trapped);
        jsonObject.put("complaint", complaint);
        jsonObject.put("fault", fault);
        return jsonObject;
    }

    public JSONObject elevatorCountStat(DPFilterParamDto dpFilterParamDto) {
        List<RegionModel> regionList = stCommonService.setRegionIfRootParentAndNoAccessIf3Level(dpFilterParamDto);
        List<String> xdata = regionList.stream().map(RegionModel::getRegionName).collect(Collectors.toList());

        List<Long> ydata = new ArrayList<>();
        regionList.forEach(x -> {
            String orgCode = stCommonService.getAndSetOrgCode(x.getRegionCode().toString());
            if (!ValidationUtil.isEmpty(orgCode)) {
                ydata.add(elevatorCountByES(orgCode));
            } else {
                ydata.add(0L);
            }
        });
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("xdata", xdata);
        jsonObject.put("ydata", ydata);
        return jsonObject;
    }

    public JSONObject eventStatByLocation(DPFilterParamDto dpFilterParamDto) throws Exception {
        dpFilterParamDto.setBeginDate(DateUtil.formatDate(DateTimeUtil.getMinValueOfOneDay(DateTimeUtil.addMonths(new Date(), -1)), DateUtil.Y_M_D_HMS));
        dpFilterParamDto.setEndDate(DateUtil.formatDate(DateTimeUtil.getMaxValueOfOneDay(new Date()), DateUtil.Y_M_D_HMS));
        // 查询字典 ADDRESS id name
        List<DataDictionary> dataDictionaries = dataDictionaryService.getByType("ADDRESS");
        List<Object> xdata = dataDictionaries.stream().map(DataDictionary::getName).collect(Collectors.toList());
        List<Object> ydata;
        String orgCode = stCommonService.getAndSetOrgCode(dpFilterParamDto);
        if (orgCode == null) {
            ydata = dataDictionaries.stream().map(d -> 0L).collect(Collectors.toList());
        } else {
            List<CountDto> maps = alertCalledMapper.queryListByLocation(orgCode, dpFilterParamDto);
            Map<String, Long> addressNumMap = maps.stream().collect(Collectors.toMap(CountDto::getKeyStr, CountDto::getLongValue));
            ydata = dataDictionaries.stream().map(d -> {
                Long num = 0L;
                // 目前USE_PLACE字段存放字典的code
                if (addressNumMap.get(d.getCode()) != null) {
                    num = addressNumMap.get(d.getCode());
                }
                // 数据库中老数据历史问题存放字典的name,兼容对老数据的统计
                if (addressNumMap.get(d.getName()) != null) {
                    num = num + addressNumMap.get(d.getName());
                }
                return num;
            }).collect(Collectors.toList());
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("xdata", xdata);
        jsonObject.put("ydata", ydata);
        return jsonObject;
    }

    public JSONObject faultCauseRatio(DPFilterParamDto dpFilterParamDto) {
        JSONObject jsonObject = new JSONObject();
        String orgCode = stCommonService.getAndSetOrgCode(dpFilterParamDto);
        if (orgCode == null) {
            return jsonObject;
        }
        List<CountDto> maps = alertCalledMapper.faultCauseRatio(orgCode);
        List<Object> xdata = maps.stream().map(CountDto::getKeyStr).collect(Collectors.toList());
        List<Object> ydata = maps.stream().map(CountDto::getLongValue).collect(Collectors.toList());
        jsonObject.put("xdata", xdata);
        jsonObject.put("ydata", ydata);
        return jsonObject;
    }

    public List<AlertPaperInfoDto> instantAlert(DPFilterParamDto dpFilterParamDto) {
        List<String> regionCodes = new ArrayList<>();
        regionCodes.add(dpFilterParamDto.getCityCode());
        return alertCalledMapper.getAlertPaperInfoList(regionCodes, false);
    }

    public Page<Map<String,Object>> instantAlertList(DPFilterParamForDetailDto dpFilterParamForDetailDto,Page page) {
        String orgCode = stCommonService.getAndSetOrgCode(dpFilterParamForDetailDto.getCityCode());
        dpFilterParamForDetailDto.setOrgCode(orgCode);
        return alertCalledMapper.getInstantAlertPage(page,dpFilterParamForDetailDto);
    }

    public List<Map<String, Object>> getAlertCallType(DPFilterParamForDetailDto dpFilterParamForDetailDto) {
        List<HashMap<String, Object>> enumList = AlertCallEnum.getTypeEnumList();
        List<Map<String,Object>> result = new ArrayList<>();
        Map<String,Object> map = new HashMap<>();
        map.put("title","警情类型");
        map.put("value","0");
        map.put("children",enumList);
        result.add(map);
        return result;
    }

    public Map<String,List<Map<String,Object>>> getAlertCallSearch(DPFilterParamForDetailDto dpFilterParamForDetailDto) {
        Map<String,List<Map<String,Object>>> enumMap = AlertCallEnum.getSearchEnumList();
        return enumMap;
    }

    public JSONObject trappedUserCount(DPFilterParamDto dpFilterParamDto) throws Exception {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("xdata", Arrays.asList("30分钟内到达次数", "超过30分钟到次数", "一级救援次数", "二级救援次数", "三级救援次数"));
        String orgCode = stCommonService.getAndSetOrgCode(dpFilterParamDto.getCityCode());
        if (orgCode == null) {
            jsonObject.put("ydata", Arrays.asList(0L, 0L, 0L, 0L, 0L));
            return jsonObject;
        }
        String date = DateUtil.formatDate(DateTimeUtil.addMonths(new Date(), -1), "yyyy-MM");
        LambdaQueryWrapper<AlertRescueStatistics> lambda = new QueryWrapper<AlertRescueStatistics>().lambda();
        lambda.likeRight(AlertRescueStatistics::getSupervisoryUnitOrgCode, orgCode);
        lambda.eq(AlertRescueStatistics::getStatisticsDate, date);
        List<AlertRescueStatistics> alertRescueStatistics = alertRescueStatisticsMapper.selectList(lambda);
        List<Long> ydata = new ArrayList<>();
        ydata.add(alertRescueStatistics.stream().mapToLong(AlertRescueStatistics::getLessNum).sum());
        ydata.add(alertRescueStatistics.stream().mapToLong(AlertRescueStatistics::getGreaterNum).sum());
        ydata.add(alertRescueStatistics.stream().mapToLong(AlertRescueStatistics::getLevelOne).sum());
        ydata.add(alertRescueStatistics.stream().mapToLong(AlertRescueStatistics::getLevelTwo).sum());
        ydata.add(alertRescueStatistics.stream().mapToLong(AlertRescueStatistics::getLevelThree).sum());
        jsonObject.put("ydata", ydata);
        return jsonObject;
    }

    public List<AlertUseUnitStatisticsDto> trappedUserHighCompanyCount(DPFilterParamDto dpFilterParamDto) throws Exception {
        String date = DateUtil.formatDate(DateTimeUtil.addMonths(new Date(), -1), "yyyy-MM");
        String orgCode = stCommonService.getAndSetOrgCode(dpFilterParamDto);
        if (orgCode == null) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<AlertUseUnitStatistics> lambda = new QueryWrapper<AlertUseUnitStatistics>().lambda();
        lambda.likeRight(AlertUseUnitStatistics::getSupervisoryUnitOrgCode, orgCode);
        lambda.eq(AlertUseUnitStatistics::getStatisticsDate, date);
        lambda.isNotNull(AlertUseUnitStatistics::getUseUnitCode);
        List<AlertUseUnitStatistics> alertUseUnitStatistics = alertUseUnitStatisticsMapper.selectList(lambda);
        alertUseUnitStatistics.sort(Comparator.comparing(
                (AlertUseUnitStatistics a) -> a.getFaultNum() + a.getTrappedNum()
        ).reversed());
        return Bean.toModels(alertUseUnitStatistics, AlertUseUnitStatisticsDto.class);
    }

    public List<Map<String, Object>> rankUnitByRescueTime(DPFilterParamDto dpFilterParamDto) {
        String orgCode = stCommonService.getAndSetOrgCode(dpFilterParamDto);
        if (orgCode == null) {
            return new ArrayList<>();
        }
        List<Map<String, Object>> maps = dispatchTaskMapper.rankUnitByRescueTime(orgCode);
        maps.forEach(x -> {
            String avgTime = "";
            Long seconds = Long.valueOf(x.get("avgTime").toString());
            long days = TimeUnit.SECONDS.toDays(seconds);
            long hours = TimeUnit.SECONDS.toHours(seconds) - TimeUnit.DAYS.toHours(days);
            long minutes = TimeUnit.SECONDS.toMinutes(seconds) - TimeUnit.HOURS.toMinutes(hours) - TimeUnit.SECONDS.toMinutes(days);
            long sec = seconds - (TimeUnit.DAYS.toSeconds(days) + TimeUnit.HOURS.toSeconds(hours) + TimeUnit.MINUTES.toSeconds(minutes));
            if (days > 0) {
                avgTime = avgTime + days + "天";
            }
            if (hours > 0) {
                avgTime = avgTime + hours + "小时";
            }
            if (minutes > 0) {
                avgTime = avgTime + minutes + "分钟";
            }
            if (sec > 0) {
                avgTime = avgTime + sec + "秒";
            }
            x.put("avgTime", avgTime);
        });
        return maps;
    }

    public Page<Map<String, Object>> rankUnitByRescueTimePage(Page<Map<String, Object>> page, DPFilterParamForDetailDto dpFilterParamForDetailDto) {
        String orgCode = stCommonService.getAndSetOrgCode(dpFilterParamForDetailDto.getCityCode());
        if (orgCode == null) {
            return page;
        }else {
            dpFilterParamForDetailDto.setOrgCode(orgCode);
        }

        Page<Map<String, Object>> pageList = dispatchTaskMapper.rankUnitByRescueTimePage(page,dpFilterParamForDetailDto);
        return pageList;
    }

    public Map<String, Object> rankUnitByRescueTimeDetail(DPFilterParamForDetailDto dpFilterParamForDetailDto) {

        List<RegionModel> regionModels = stCommonService.setRegionIfRootParent(dpFilterParamForDetailDto.getCityCode());
        List<Map<String,Object>> result =  regionModels.parallelStream().map(r -> {
            String orgCode = stCommonService.getAndSetOrgCode(r.getRegionCode()+"");
            Map<String, Object> itemResult = dispatchTaskMapper.rankUnitByRescueTimeDetail(orgCode);
            itemResult.put("xdata",r.getRegionName());
            return itemResult;
        }).collect(Collectors.toList());

        Map<String,Object> returnMap = new HashMap<>();
        List<Map<String,Object>> legendData = new ArrayList<>();
        for(int i = 0;i<2; i++){
            Map<String,Object> map = new HashMap<>();
            if(i == 0){
                map.put("dataKey","count");
                map.put("value","应急时间");
                map.put("chartType","bar");
            }else{
                map.put("dataKey","avgTime");
                map.put("value","平均救援时间");
                map.put("chartType","line");
            }
            legendData.add(map);
        }
        returnMap.put("legendData",legendData);

        List xdata = new ArrayList();
        List count = new ArrayList();
        List avgTime = new ArrayList();

        for(int i = 0;i<result.size();i++){
            xdata.add(result.get(i).get("xdata"));
            count.add(result.get(i).get("count") == null ? "0" : result.get(i).get("count"));
            avgTime.add(result.get(i).get("avgTime") == null ? "0" : result.get(i).get("avgTime"));
        }

        returnMap.put("xdata",xdata);
        returnMap.put("count",count);
        returnMap.put("avgTime",avgTime);

        return returnMap;
    }

    public List<Map<String, Object>> rankUnitByRescueTimeType(DPFilterParamForDetailDto dpFilterParamForDetailDto) {
        List<Map<String,Object>> result = new ArrayList<>();
        List<HashMap<String, Object>> list = new ArrayList<>();
        HashMap<String, Object> map = new HashMap<>();
        map.put("title", "维保单位");
        map.put("value", "repairUnit");
        list.add(map);
        Map<String,Object> resultMap = new HashMap<>();
        resultMap.put("title","企业类型");
        resultMap.put("value","0");
        resultMap.put("children",list);
        result.add(resultMap);
        return result;
    }

    public JSONObject regionEventRank(DPFilterParamDto dpFilterParamDto) {
        JSONObject jsonObject = new JSONObject();
        String orgCodeParent = stCommonService.getAndSetOrgCode(dpFilterParamDto.getCityCode());
        if (orgCodeParent == null) {
            return jsonObject;
        }
        List<RegionModel> childRegion = stCommonService.setRegionIfRootParentAndNoAccessIf3Level(dpFilterParamDto);
        Map<String, Long> map = new HashMap<>();
        childRegion.forEach(x -> {
            String orgCode = stCommonService.getAndSetOrgCode(x.getRegionCode().toString());
            if (ValidationUtil.isEmpty(orgCode)) {
                map.put(x.getRegionName(), 0L);
            } else {
                Long num = alertStatisticsMapper.countEmergencyEventsByOrgCodeAndDate(orgCode, dpFilterParamDto);
                map.put(x.getRegionName(), num);
            }
        });
        List<String> xdata = new ArrayList<>(map.keySet());
        List<Long> ydata = new ArrayList<>();
        xdata.sort(Comparator.comparingLong(map::get).reversed());
        xdata.forEach(x -> ydata.add(map.get(x)));
        jsonObject.put("xdata", xdata);
        jsonObject.put("ydata", ydata);
        return jsonObject;
    }


    /**
     * 获取两个时间段之间的每一天
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 结果
     */
    public List<String> getEveryDay(String startTime, String endTime) {
        List<String> dateList = new ArrayList<>();
        LocalDate startDate = LocalDate.parse(startTime);
        LocalDate endDate = LocalDate.parse(endTime);
        long numOfDays = ChronoUnit.DAYS.between(startDate, endDate);
        for (int i = 0; i <= numOfDays; i++) {
            LocalDate currentDate = startDate.plusDays(i);
            String format = currentDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            dateList.add(format);
        }
        return dateList;
    }

    public List<Map<String, Object>> getCenterMapCountDataForOverview(DPFilterParamDto dpFilterParamDto) {
        return stCommonService.setRegionIfRootParent(dpFilterParamDto).stream().map(r -> {
            DPFilterParamDto filterParamDto = new DPFilterParamDto();
            filterParamDto.setCityCode(r.getRegionCode().toString());
            String orgCode = stCommonService.getAndSetOrgCode(filterParamDto);
            Map<String, Object> itemResult = new HashMap<>();
            if (StringUtils.isNotEmpty(orgCode)) {
                this.setDefaultFilter(filterParamDto);
                itemResult = getCenterMapOverviewData(orgCode, filterParamDto);
            }
            itemResult.put("regionCode", r.getRegionCode());
            itemResult.put("regionName", r.getRegionName());
            return itemResult;
        }).collect(Collectors.toList());
    }


    private void buildLegendData(JSONObject jsonObject) {
        JSONArray jsonArray = new JSONArray();
        BLL_LX_LEGEND.forEach((k, v) -> {
            JSONObject item = new JSONObject();
            item.put("dataKey", k);
            item.put("value", v);
            jsonArray.add(item);
        });
        jsonObject.put("legendData", jsonArray);
    }

    private Map<String, Object> getCenterMapOverviewData(String orgCode, DPFilterParamDto filterParamDto) {
        Map<String, Object> result = new HashMap<>();
        // 统计完成的事件包括困人、故障、投诉咨询
        List<CountDto> countDtos = alertStatisticsMapper.countEmergencyEventsByOrgCodeAndDate2(orgCode, filterParamDto);
        Map<String, Long> alertTypeNumMap = countDtos.stream().collect(Collectors.toMap(CountDto::getKeyStr, CountDto::getLongValue));
        Map<String, Long> equDefineNumMap = staticsElevatorByEquDefine(filterParamDto.getCityCode());
        // 电梯总量(台)
        result.put("dtCount", equDefineNumMap.values().stream().mapToLong(e -> e).sum());
        // 曳引驱动乘客电梯(台)
        result.put("zyqdcjdtCount", equDefineNumMap.getOrDefault("3110", 0L));
        // 曳引驱动载货电梯(台)
        result.put("zyqdzhdtCount", equDefineNumMap.getOrDefault("3120", 0L));
        // 强制驱动载货电梯(台)
        result.put("qzqdzgdtCount", equDefineNumMap.getOrDefault("3130", 0L));
        // 液压乘客电梯(台)
        result.put("yackdtount", equDefineNumMap.getOrDefault("3210", 0L));
        // 液压载货电梯(台)
        result.put("yyzhdtCount", equDefineNumMap.getOrDefault("3220", 0L));
        // 自动扶梯(台)
        result.put("zdftCount", equDefineNumMap.getOrDefault("3310", 0L));
        // 自动人行道(台)
        result.put("zdrxdCount", equDefineNumMap.getOrDefault("3320", 0L));
        // 防爆电梯(台)
        result.put("fbdtCount", equDefineNumMap.getOrDefault("3410", 0L));
        // 消防员电梯(台)
        result.put("xfydtCount", equDefineNumMap.getOrDefault("3420", 0L));
        // 杂物电梯(台)
        result.put("zhdtCount", equDefineNumMap.getOrDefault("3430", 0L));
        // 应急事件(起) = 困人救援事件(起) + 故障维修(起) + 投诉咨询(起)
        result.put("alarmCount", alertTypeNumMap.getOrDefault(DispatchPaperEnums.KRJY.getId(), 0L) +
                alertTypeNumMap.getOrDefault(DispatchPaperEnums.GZWX.getId(), 0L) +
                alertTypeNumMap.getOrDefault(DispatchPaperEnums.TSZX.getId(), 0L));
        // 困人救援事件(起)
        result.put("krjysjCount", alertTypeNumMap.getOrDefault(DispatchPaperEnums.KRJY.getId(), 0L));
        // 故障维修(起)
        result.put("gzwxCount", alertTypeNumMap.getOrDefault(DispatchPaperEnums.GZWX.getId(), 0L));
        // 投诉咨询(起)
        result.put("tszxCount", alertTypeNumMap.getOrDefault(DispatchPaperEnums.TSZX.getId(), 0L));
        // 解救被困乘客数(人)
        result.put("jjbkcksCount", alertStatisticsMapper.countRescuedPersonNum(orgCode, filterParamDto));
        return result;
    }


    public Map<String, Object> getCenterMapCountDataForGlobal(DPFilterParamDto dpFilterParamDto) {
        // this.setDefaultFilter(dpFilterParamDto);
        String orgCode = stCommonService.getAndSetOrgCode(dpFilterParamDto);
        if (StringUtils.isNotEmpty(orgCode)) {
            return this.getCenterMapOverviewData(orgCode, dpFilterParamDto);
        }
        return new HashMap<>();
    }

    private void setDefaultFilter(DPFilterParamDto dpFilterParamDto) {
        if (StringUtils.isEmpty(dpFilterParamDto.getBeginDate())) {
            dpFilterParamDto.setBeginDate(cn.hutool.core.date.DateUtil.offsetDay(new Date(), -30).toString("yyyy-MM-dd HH:mm:ss"));
        }
        if (StringUtils.isEmpty(dpFilterParamDto.getEndDate())) {
            dpFilterParamDto.setEndDate(cn.hutool.core.date.DateUtil.now());
        }
    }

    private long elevatorCountByES(String orgCode) {
        long num = 0L;
        CountRequest request = new CountRequest();
        request.indices("idx_biz_view_jg_all");
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        // 按照管辖机构区域信息模糊查询
        boolMust.must(QueryBuilders.wildcardQuery("ORG_BRANCH_CODE.keyword", QueryParser.escape(orgCode) + "*"));
        // 只统计已纳管设备
        boolMust.must(QueryBuilders.termQuery("IS_INTO_MANAGEMENT", Boolean.TRUE));
        // 设备种类是电梯的
        boolMust.must(QueryBuilders.termQuery("EQU_LIST_CODE", EquipmentClassifityEnum.DT.getCode()));
        request.query(boolMust);
        try {
            CountResponse response = restHighLevelClient.count(request, RequestOptions.DEFAULT);
            num = response.getCount();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return num;
    }

    private Map<String, Long> staticsElevatorByEquDefine(String regionCode) {
        String orgCode = stCommonService.getAndSetOrgCode(regionCode);
        Map<String, Long> countMap = new HashMap<>();
        SearchRequest request = new SearchRequest();
        request.indices("idx_biz_view_jg_all");
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        // 按照管辖机构区域信息模糊查询
        boolMust.must(QueryBuilders.wildcardQuery("ORG_BRANCH_CODE.keyword", QueryParser.escape(orgCode) + "*"));
        //已赋码
        boolMust.must(QueryBuilders.existsQuery("SUPERVISORY_CODE"));
        boolMust.mustNot(QueryBuilders.termQuery("SUPERVISORY_CODE","null"));
        //状态为已认领
        String[] status = {"草稿","已拒领","待认领"};
        boolMust.mustNot(QueryBuilders.termsQuery("STATUS",Arrays.asList(status)));

        // 且设备品种3级,按照真实的过滤，防止有脏数据
        boolMust.must(QueryBuilders.termsQuery("EQU_DEFINE_CODE.keyword", ELEVATOR_EQU_DEFINE_CODES.split(",")));
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(boolMust);
        // 原因默认10个，由于业务最多有10个，担心有脏数据，故多查询
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("count_by_equ_define_code").field("EQU_DEFINE_CODE.keyword").size(20);
        builder.aggregation(aggregationBuilder);
        request.source(builder);
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            Terms terms = response.getAggregations().get("count_by_equ_define_code");
            for (Terms.Bucket bucket : terms.getBuckets()) {
                countMap.put(bucket.getKeyAsString(), bucket.getDocCount());
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return countMap;
    }

    public JSONObject alertRecordBarChartForDP(DPFilterParamForDetailDto recordFilterVo) {

        JSONObject res = new JSONObject();
        JSONArray legendData = new JSONArray();

        legendData.addAll(createLegendData());

        List<RegionModel> regionList = stCommonService.setRegionIfRootParentAndNoAccessIf3Level(ValidationUtil.isEmpty(recordFilterVo.getCityCode()) ? "610000" : recordFilterVo.getCityCode());

        // 获取区域名称并过滤
        List<String> xData = regionList.stream()
                .map(RegionModel::getRegionName)
                .filter(regionName -> !"西咸新区".equals(regionName))
                .collect(Collectors.toList());

        List<Long> alertRecordTotal = regionList.stream().map(region -> {
            String orgCode = stCommonService.getAndSetOrgCode(String.valueOf(region.getRegionCode()));
            if (ValidationUtil.isEmpty(orgCode)) {
                return 0L;
            }
            if (recordFilterVo.getTimeSearchOne() == null) {
                recordFilterVo.setTimeSearchOne(new DPFilterParamForDateDto());
            }
            if (!ValidationUtil.isEmpty(recordFilterVo.getTreeValue())){
                recordFilterVo.setAlertTypeCode(recordFilterVo.getTreeValue());
            }
            return alertStatisticsMapper.countAlertRecordByOrgCodeAndDate(orgCode, recordFilterVo);
        }).collect(Collectors.toList());
        Long totalCount = alertRecordTotal.stream().reduce(0L, Long::sum);
        res.put("legendData", legendData);
        res.put("xdata", xData);
        res.put("alertCount", alertRecordTotal);

        List<Long> totalCountList = new ArrayList();
        List<String> rateList = new ArrayList();
        // 计算比率
        double completionRate = 0.0;
        for(int i = 0;i<xData.size();i++){
            totalCountList.add(totalCount);
            if(totalCount != 0 && alertRecordTotal.get(i) != 0){
                completionRate = (double) alertRecordTotal.get(i) / totalCount;
            }
            DecimalFormat df = new DecimalFormat("#,##0.00");
            String rate = df.format(completionRate);
            rateList.add(rate);
        }
        res.put("totalCount", totalCountList);
        res.put("rate", rateList);

        return res;
    }

    private JSONArray createLegendData() {

        JSONArray legendData = new JSONArray();

        for(int i = 0;i<3; i++){
            JSONObject legendSubData = new JSONObject();
            if(i == 0){
                legendSubData.put("dataKey", "alertCount");
                legendSubData.put("value", "发生数量");
                legendSubData.put("chartType", "bar");
            }else if (i == 1){
                legendSubData.put("dataKey", "totalCount");
                legendSubData.put("value", "总量");
                legendSubData.put("chartType", "bar");
            }else{
                legendSubData.put("dataKey", "rate");
                legendSubData.put("value", "比率");
                legendSubData.put("chartType", "line");
            }
            legendData.add(legendSubData);
        }

        return legendData;
    }


    public JSONObject alertOperations() {
        Collection<DataDictionary> JQLXList = dataDictionaryService.list(
                new QueryWrapper<DataDictionary>()
                        .eq("type", "JQLX")
                        .eq("is_delete", false)
                        .orderByAsc("sort_num")
        );
        List<JSONObject> subList = JQLXList.stream()
                .map(jq -> {
                    JSONObject obj = new JSONObject();
                    obj.put("value", jq.getCode());
                    obj.put("title", jq.getName());
                    return obj;
                }).collect(Collectors.toList());

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("title", "应急事件");
        jsonObject.put("value", "yjsj");
        jsonObject.put("children", subList);
        return jsonObject;
    }

    public ResponseModel<IPage<Map<String, Object>>> alertRecordTableForDP(DPFilterParamForDetailDto recordFilterVo) {
        String orgCode = stCommonService.getAndSetOrgCode(recordFilterVo.getCityCode());
        if (orgCode == null) {
            return ResponseHelper.buildResponse(new Page<>());
        }
        if (!ValidationUtil.isEmpty(recordFilterVo.getTreeValue())){
            recordFilterVo.setAlertTypeCode(recordFilterVo.getTreeValue());
        }
        Page<Map<String, Object>> mapPage = alertStatisticsMapper.alertRecordForPage(new Page<>(recordFilterVo.getCurrent(), recordFilterVo.getSize()),recordFilterVo,orgCode);
        return ResponseHelper.buildResponse(mapPage);
    }

    public ResponseModel<JSONObject> alertUnitBarChartForDP(DPFilterParamForDetailDto detailDto) throws Exception {
        JSONObject res = new JSONObject();
        JSONArray legendData = new JSONArray();
        legendData.add(new JSONObject()
                .fluentPut("dataKey", "alertUnitTotal")
                .fluentPut("value", "故障高发企业总数")
                .fluentPut("chartType", "bar"));

        List<RegionModel> regionList = stCommonService.setRegionIfRootParentAndNoAccessIf3Level(ValidationUtil.isEmpty(detailDto.getCityCode()) ? "610000" : detailDto.getCityCode());
        List<String> xData = regionList.stream()
                .map(RegionModel::getRegionName)
                .filter(regionName -> !"西咸新区".equals(regionName))
                .collect(Collectors.toList());
        String date = DateUtil.formatDate(DateTimeUtil.addMonths(new Date(), -1), "yyyy-MM");
        List<? extends Number> alertUnitTotal = regionList.stream()
                .map(region -> {
                    String orgCode = stCommonService.getAndSetOrgCode(String.valueOf(region.getRegionCode()));
                    if (ValidationUtil.isEmpty(orgCode)) {
                        return 0L;
                    }
                    return alertUseUnitStatisticsMapper.selectCount(new QueryWrapper<AlertUseUnitStatistics>().lambda()
                            .likeRight(AlertUseUnitStatistics::getSupervisoryUnitOrgCode, orgCode)
                            .eq(AlertUseUnitStatistics::getStatisticsDate,date)
                            .isNotNull(AlertUseUnitStatistics::getUseUnitCode));
                }).collect(Collectors.toList());
        res.put("legendData", legendData);
        res.put("xdata", xData);
        res.put("alertUnitTotal", alertUnitTotal);
        return ResponseHelper.buildResponse(res);
    }

    public ResponseModel<IPage<Map<String,Object>>> alertUseUnitTableForDP(DPFilterParamForDetailDto detailDto) throws Exception{
        Page<AlertUseUnitStatistics> page = new Page<>();
        page.setCurrent(detailDto.getCurrent());
        page.setSize(detailDto.getSize());

        String orgCode = stCommonService.getAndSetOrgCode(ValidationUtil.isEmpty(detailDto.getCityCode()) ? "610000" : detailDto.getCityCode());
        if (orgCode == null) {
            return ResponseHelper.buildResponse(new Page<>());
        }

        LambdaQueryWrapper<AlertUseUnitStatistics> lambda = new QueryWrapper<AlertUseUnitStatistics>().lambda();

        lambda.isNotNull(AlertUseUnitStatistics::getUseUnitCode);
        // 地市搜索
        if (!ValidationUtil.isEmpty(detailDto.getRegionName())) {
            List<RegionModel> regionList = stCommonService.setRegionIfRootParentAndNoAccessIf3Level(
                    ValidationUtil.isEmpty(detailDto.getCityCode()) ? "610000" : detailDto.getCityCode()
            );
            RegionModel matchedRegion = regionList.stream()
                    .filter(region -> detailDto.getRegionName().equals(region.getRegionName()))
                    .findFirst()
                    .orElseThrow(() -> new IllegalArgumentException("Region not found"));
            String cityOrgCode = stCommonService.getAndSetOrgCode(String.valueOf(matchedRegion.getRegionCode()));
            lambda.likeRight(AlertUseUnitStatistics::getSupervisoryUnitOrgCode, cityOrgCode);
        }else {
            lambda.likeRight(AlertUseUnitStatistics::getSupervisoryUnitOrgCode, orgCode);
        }
        String date = DateUtil.formatDate(DateTimeUtil.addMonths(new Date(), -1), "yyyy-MM");
        lambda.eq(AlertUseUnitStatistics::getStatisticsDate, date);
        // 使用单位
        if (!ValidationUtil.isEmpty(detailDto.getCompanyName())){
            lambda.like(AlertUseUnitStatistics::getUseUnit, detailDto.getCompanyName().trim());
        }
        // 维保单位
        if (!ValidationUtil.isEmpty(detailDto.getMaintenanceCompanyName())){
            lambda.like(AlertUseUnitStatistics::getMaintenanceUnit, detailDto.getMaintenanceCompanyName().trim());
        }
        if(!ValidationUtil.isEmpty(detailDto.getTimeSearchOne())) {
            // 开始时间
            if (!ValidationUtil.isEmpty(detailDto.getTimeSearchOne().getBeginDate())) {
                lambda.ge(AlertUseUnitStatistics::getStartDate, detailDto.getTimeSearchOne().getBeginDate());
            }
            // 结束时间
            if (!ValidationUtil.isEmpty(detailDto.getTimeSearchOne().getEndDate())) {
                lambda.le(AlertUseUnitStatistics::getEndDate, detailDto.getTimeSearchOne().getEndDate());
            }
        }
        // 设备类型
        if (!ValidationUtil.isEmpty(detailDto.getEquListCode())){
            lambda.le(AlertUseUnitStatistics::getEquipmentClassificationCode, detailDto.getEquListCode());
        }
        IPage<AlertUseUnitStatistics> alertUseUnitStatistics = alertUseUnitStatisticsMapper.selectPage(page, lambda);
        List<AlertUseUnitStatistics> records = alertUseUnitStatistics.getRecords();
        List<String> useUnitCodeList = records.stream().map(AlertUseUnitStatistics::getUseUnitCode).collect(Collectors.toList());
        Map<String,Map<String,Object>> useUnitMap = new HashMap<>();
        List<Map<String,Object>> resultList = new ArrayList<>();
        if(!CollectionUtils.isEmpty(useUnitCodeList)){
            List<Map<String, Object>> list = alertUseUnitStatisticsMapper.countByUseUnitCode(useUnitCodeList);
            if(!CollectionUtils.isEmpty(list)){
                list.forEach(map -> {
                    useUnitMap.put(map.get("useUnitCode").toString(),map);
                });

            }
        }
        records.forEach(t->{
            Map<String, Object> map = BeanUtil.beanToMap(t);
            map.putAll(useUnitMap.get(t.getUseUnitCode()));
            resultList.add(map);
        });
        Page<Map<String,Object>> resultPage = new Page<>();
        resultPage.setCurrent(page.getCurrent());
        resultPage.setSize(page.getSize());
        resultPage.setTotal(alertUseUnitStatistics.getTotal());
        resultPage.setRecords(resultList);
        return ResponseHelper.buildResponse(resultPage);
    }

    public List<JSONObject> getKeyPositionMonitor(DPFilterParamForDetailDto filterParamDto) {
        return getKeyPositionMonitorByES(filterParamDto);
    }

    private List<JSONObject> getKeyPositionMonitorByES(DPFilterParamForDetailDto filterParamDto) {
        return alertStatisticsMapper.getKeyMonitorUseUnitByCityCode(filterParamDto.getCityCode());
    }

}
