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

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yeejoin.amos.boot.module.common.api.dto.DPFilterParamForDetailDto;
import com.yeejoin.amos.boot.module.jg.api.mapper.SafetyProblemTracingMapper;
import com.yeejoin.amos.boot.module.ymt.api.dto.EquipmentCategoryDto;
import com.yeejoin.amos.boot.module.ymt.api.enums.EquimentEnum;
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.action.search.ShardSearchFailure;
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.builder.SearchSourceBuilder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class EquipmentStaticsServiceImpl {

    @Autowired
    private StCommonServiceImpl stCommonService;

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    private static final String EQUSTATE = "EQU_STATE";
    private static final String SUPERVISORYCODE = "SUPERVISORY_CODE";

    @Resource
    private SafetyProblemTracingMapper safetyProblemTracingMapper;

    public Map<String, Object> normalChart(DPFilterParamForDetailDto dpFilterParamForDetailDto) {
        List<RegionModel> regionModels = stCommonService.setRegionIfRootParent(dpFilterParamForDetailDto.getCityCode());
        List<Map<String,Object>> result =  regionModels.parallelStream().map(r -> {
            String orgCode = stCommonService.getAndSetOrgCode(r.getRegionCode()+"");
            DPFilterParamForDetailDto dpFilterParamForDetailDtoForSearch = new DPFilterParamForDetailDto();
            BeanUtils.copyProperties(dpFilterParamForDetailDto,dpFilterParamForDetailDtoForSearch);
            dpFilterParamForDetailDtoForSearch.setOrgCode(orgCode);
            dpFilterParamForDetailDtoForSearch.setCityCode(r.getRegionCode()+"");
            Map<String, Object> itemResult = new HashMap<>();
            itemResult.put("xdata",r.getRegionName());
            getNormalChartData(itemResult,dpFilterParamForDetailDtoForSearch);
            return itemResult;
        }).collect(Collectors.toList());

        Map<String,Object> returnMap = new HashMap<>();
        List<Object> legendData = new ArrayList<>();
        for(int i = 0; i < 4; i++){
            Map<String,Object> map = new HashMap<>();
            if(i == 0){
                map.put("dataKey", "fmCount");
                map.put("value", "赋码设备");
                map.put("chartType", "bar");
            }else if(i == 1){
                map.put("dataKey", "lqCount");
                map.put("value", "临期数量");
                map.put("chartType", "bar");
            }else if(i == 2){
                map.put("dataKey", "cqCount");
                map.put("value", "超期数量");
                map.put("chartType", "bar");
            }else{
                map.put("dataKey", "stationRate");
                map.put("value", "纳管率");
                map.put("chartType", "line");
            }
            legendData.add(map);
        }
        returnMap.put("legendData",legendData);

        List xdata = new ArrayList();
        List fmCount = new ArrayList();
        List lqCount = new ArrayList();
        List cqCount = new ArrayList();
        List stationRate = new ArrayList();

        for(int i = 0;i<result.size();i++){
            xdata.add(result.get(i).get("xdata"));
            fmCount.add(result.get(i).get("fmCount") == null ? "0" : result.get(i).get("fmCount"));
            lqCount.add(result.get(i).get("lqCount") == null ? "0" : result.get(i).get("lqCount"));
            cqCount.add(result.get(i).get("cqCount") == null ? "0" : result.get(i).get("cqCount"));
            stationRate.add(result.get(i).get("stationRate") == null ? "0" : result.get(i).get("stationRate"));
        }

        returnMap.put("xdata",xdata);
        returnMap.put("fmCount",fmCount);
        returnMap.put("lqCount",lqCount);
        returnMap.put("cqCount",cqCount);
        returnMap.put("stationRate",stationRate);

        return returnMap;
    }

    private void getNormalChartData(Map<String, Object> itemResult, DPFilterParamForDetailDto dpFilterParamForDetailDto) {
        //赋码数量
        Long fmCount = null == dpFilterParamForDetailDto.getOrgCode() ? null : getFMEquipmentCount(dpFilterParamForDetailDto);
        //临期数量
        Long lqCount = null == dpFilterParamForDetailDto.getOrgCode() ? null :getLQEquipmentCount(dpFilterParamForDetailDto);
        //超期数量
        Long cqCount = null == dpFilterParamForDetailDto.getOrgCode() ? null :getCQEquipmentCount(dpFilterParamForDetailDto);
        //纳管数量
        Long ngCount = null == dpFilterParamForDetailDto.getOrgCode() ? null :getNGEquipmentCount(dpFilterParamForDetailDto);
        //所有设备数量
        Long allCount = getAllEquipmentCount(dpFilterParamForDetailDto);

        if (allCount != null && ngCount != null && allCount > 0 ) {
            BigDecimal percent = (new BigDecimal(ngCount.doubleValue()).divide(new BigDecimal(allCount.doubleValue()), 2, RoundingMode.HALF_UP));
            itemResult.put("stationRate", Double.valueOf(percent.toString()));
        } else {
            itemResult.put("stationRate", 0.0);
        }
        itemResult.put("fmCount", fmCount);
        itemResult.put("lqCount", lqCount);
        itemResult.put("cqCount", cqCount);
    }

    private Long getFMEquipmentCount(DPFilterParamForDetailDto dpFilterParamForDetailDto) {
        long num = 0;
        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(dpFilterParamForDetailDto.getOrgCode()) + "*"));

        if (StringUtils.isNotEmpty(dpFilterParamForDetailDto.getTreeValue())) {
            if ("2300".equals(dpFilterParamForDetailDto.getTreeValue())){
                boolMust.must(QueryBuilders.termQuery("EQU_CATEGORY_CODE", QueryParser.escape(dpFilterParamForDetailDto.getTreeValue().toLowerCase())));
            }else {
                boolMust.must(QueryBuilders.termQuery("EQU_LIST_CODE", QueryParser.escape(dpFilterParamForDetailDto.getTreeValue().toLowerCase())));
            }
        }
        // 且8大类，目的去掉脏数据
        boolMust.must(QueryBuilders.termsQuery("EQU_LIST_CODE", StCommonServiceImpl.getEquipmentCategory().stream().map(EquipmentCategoryDto::getCode).collect(Collectors.toList())));
        boolMust.must(QueryBuilders.existsQuery("SUPERVISORY_CODE"));
        boolMust.mustNot(QueryBuilders.termQuery("SUPERVISORY_CODE","null"));
        String[] status = {"草稿","已拒领","待认领"};
        boolMust.mustNot(QueryBuilders.termsQuery("STATUS",Arrays.asList(status)));
        request.query(boolMust);
        try {
            CountResponse response = restHighLevelClient.count(request, RequestOptions.DEFAULT);
            num = response.getCount();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return num;
    }

    private Long getAllEquipmentCount(DPFilterParamForDetailDto dpFilterParamForDetailDto) {
        long num = 0;
        CountRequest request = new CountRequest();
        request.indices("idx_biz_view_jg_all");
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        // 按照管辖机构区域信息模糊查询
        if (StringUtils.isNotEmpty(dpFilterParamForDetailDto.getOrgCode())) {
            boolMust.must(QueryBuilders.wildcardQuery("ORG_BRANCH_CODE.keyword", QueryParser.escape(dpFilterParamForDetailDto.getOrgCode()) + "*"));
        }
        if (StringUtils.isNotEmpty(dpFilterParamForDetailDto.getTreeValue())) {
            if ("2300".equals(dpFilterParamForDetailDto.getTreeValue())){
                boolMust.must(QueryBuilders.termQuery("EQU_CATEGORY_CODE", QueryParser.escape(dpFilterParamForDetailDto.getTreeValue().toLowerCase())));
            }else {
                boolMust.must(QueryBuilders.termQuery("EQU_LIST_CODE", QueryParser.escape(dpFilterParamForDetailDto.getTreeValue().toLowerCase())));
            }
        }
        // 且8大类，目的去掉脏数据
        boolMust.must(QueryBuilders.termsQuery("EQU_LIST_CODE", StCommonServiceImpl.getEquipmentCategory().stream().map(EquipmentCategoryDto::getCode).collect(Collectors.toList())));
        String[] status = {"草稿","已拒领","待认领"};
        boolMust.mustNot(QueryBuilders.termsQuery("STATUS",Arrays.asList(status)));
        request.query(boolMust);
        try {
            CountResponse response = restHighLevelClient.count(request, RequestOptions.DEFAULT);
            num = response.getCount();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return num;
    }

    private Long getNGEquipmentCount(DPFilterParamForDetailDto dpFilterParamForDetailDto) {
        long num = 0;
        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(dpFilterParamForDetailDto.getOrgCode()) + "*"));
        boolMust.must(QueryBuilders.termQuery("IS_INTO_MANAGEMENT", true));
        if (StringUtils.isNotEmpty(dpFilterParamForDetailDto.getTreeValue())) {
            if ("2300".equals(dpFilterParamForDetailDto.getTreeValue())){
                boolMust.must(QueryBuilders.termQuery("EQU_CATEGORY_CODE", QueryParser.escape(dpFilterParamForDetailDto.getTreeValue().toLowerCase())));
            }else {
                boolMust.must(QueryBuilders.termQuery("EQU_LIST_CODE", QueryParser.escape(dpFilterParamForDetailDto.getTreeValue().toLowerCase())));
            }
        }
        // 且8大类，目的去掉脏数据
        boolMust.must(QueryBuilders.termsQuery("EQU_LIST_CODE", StCommonServiceImpl.getEquipmentCategory().stream().map(EquipmentCategoryDto::getCode).collect(Collectors.toList())));
        String[] status = {"草稿","已拒领","待认领"};
        boolMust.mustNot(QueryBuilders.termsQuery("STATUS",Arrays.asList(status)));
        request.query(boolMust);
        try {
            CountResponse response = restHighLevelClient.count(request, RequestOptions.DEFAULT);
            num = response.getCount();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return num;
    }

    private Long getLQEquipmentCount(DPFilterParamForDetailDto dpFilterParamForDetailDto) {
        long num = 0;
        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(dpFilterParamForDetailDto.getOrgCode()) + "*"));
        // 且下次检验日期大于等于当天 且查询 下次检验日期 <= 当前天+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));
        if (StringUtils.isNotEmpty(dpFilterParamForDetailDto.getTreeValue())) {
            if ("2300".equals(dpFilterParamForDetailDto.getTreeValue())){
                boolMust.must(QueryBuilders.termQuery("EQU_CATEGORY_CODE", QueryParser.escape(dpFilterParamForDetailDto.getTreeValue().toLowerCase())));
            }else {
                boolMust.must(QueryBuilders.termQuery("EQU_LIST_CODE", QueryParser.escape(dpFilterParamForDetailDto.getTreeValue().toLowerCase())));
            }
        }
        // 且8大类，目的去掉脏数据
        boolMust.must(QueryBuilders.termsQuery("EQU_LIST_CODE", StCommonServiceImpl.getEquipmentCategory().stream().map(EquipmentCategoryDto::getCode).collect(Collectors.toList())));
        String[] status = {"草稿","已拒领","待认领"};
        boolMust.mustNot(QueryBuilders.termsQuery("STATUS",Arrays.asList(status)));
        request.query(boolMust);
        try {
            CountResponse response = restHighLevelClient.count(request, RequestOptions.DEFAULT);
            num = response.getCount();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return num;
    }

    private Long getCQEquipmentCount(DPFilterParamForDetailDto dpFilterParamForDetailDto) {
        long num = 0;
        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(dpFilterParamForDetailDto.getOrgCode()) + "*"));

        // 查询下次检验日期小于当前天的设备，即为超期检验超期设备
        long currentDayTime = DateUtil.parse(DateUtil.now(), "yyy-MM-dd").getTime();
        boolMust.must(QueryBuilders.rangeQuery("NEXT_INSPECT_DATE").lt(currentDayTime));

        if (StringUtils.isNotEmpty(dpFilterParamForDetailDto.getTreeValue())) {
            if ("2300".equals(dpFilterParamForDetailDto.getTreeValue())){
                boolMust.must(QueryBuilders.termQuery("EQU_CATEGORY_CODE", QueryParser.escape(dpFilterParamForDetailDto.getTreeValue().toLowerCase())));
            }else {
                boolMust.must(QueryBuilders.termQuery("EQU_LIST_CODE", QueryParser.escape(dpFilterParamForDetailDto.getTreeValue().toLowerCase())));
            }
        }
        // 且8大类，目的去掉脏数据
        boolMust.must(QueryBuilders.termsQuery("EQU_LIST_CODE", StCommonServiceImpl.getEquipmentCategory().stream().map(EquipmentCategoryDto::getCode).collect(Collectors.toList())));
        String[] status = {"草稿","已拒领","待认领"};
        boolMust.mustNot(QueryBuilders.termsQuery("STATUS",Arrays.asList(status)));
        request.query(boolMust);
        try {
            CountResponse response = restHighLevelClient.count(request, RequestOptions.DEFAULT);
            num = response.getCount();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return num;
    }

    public Page<Map<String, Object>> normalPage(Integer current, Integer size, DPFilterParamForDetailDto dpFilterParamForDetailDto) {

        String orgCode = stCommonService.getAndSetOrgCode(dpFilterParamForDetailDto.getCityCode());
        if(StringUtils.isEmpty(orgCode)){
            return new Page<>(current,size);
        }
        SearchRequest request = new SearchRequest();
        request.indices("idx_biz_view_jg_all");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        // 按照管辖机构区域信息模糊查询
        boolMust.must(QueryBuilders.wildcardQuery("ORG_BRANCH_CODE.keyword", QueryParser.escape(orgCode) + "*"));

        if (StringUtils.isNotEmpty(dpFilterParamForDetailDto.getTreeValue())) {
            if ("2300".equals(dpFilterParamForDetailDto.getTreeValue())){
                boolMust.must(QueryBuilders.termQuery("EQU_CATEGORY_CODE", QueryParser.escape(dpFilterParamForDetailDto.getTreeValue().toLowerCase())));
            }else {
                boolMust.must(QueryBuilders.termQuery("EQU_LIST_CODE", QueryParser.escape(dpFilterParamForDetailDto.getTreeValue().toLowerCase())));
            }
        }
        // 且8大类，目的去掉脏数据
        boolMust.must(QueryBuilders.termsQuery("EQU_LIST_CODE", StCommonServiceImpl.getEquipmentCategory().stream().map(EquipmentCategoryDto::getCode).collect(Collectors.toList())));
        String[] status = {"草稿","已拒领","待认领"};
        boolMust.mustNot(QueryBuilders.termsQuery("STATUS",Arrays.asList(status)));
        //检验状态0临期1超期
        if(StringUtils.isNotEmpty(dpFilterParamForDetailDto.getInspectionStatus())){
            if(StringUtils.equals("0",dpFilterParamForDetailDto.getInspectionStatus())){
                // 且下次检验日期大于等于当天 且查询 下次检验日期 <= 当前天+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));
            }else{
                // 查询下次检验日期小于当前天的设备，即为超期检验超期设备
                List<String> typeList = new ArrayList<>();
                typeList.add("维保超期");
                typeList.add("检验超期");
                List<String> sourceIds = safetyProblemTracingMapper.getSourceId(orgCode,typeList);
                boolMust.must(QueryBuilders.termsQuery("SEQUENCE_NBR.keyword",sourceIds));
            }
        }
        /**
         * 使用单位
         */
        if(StringUtils.isNotEmpty(dpFilterParamForDetailDto.getUseUnitName())){
            boolMust.must(QueryBuilders.matchPhraseQuery("USE_UNIT_NAME", "*" + dpFilterParamForDetailDto.getUseUnitName() + "*"));
        }
        /**
         * 使用登记编号
         */
        if(StringUtils.isNotEmpty(dpFilterParamForDetailDto.getUseOrgCode())){
            boolMust.must(QueryBuilders.wildcardQuery("USE_ORG_CODE", "*" + dpFilterParamForDetailDto.getUseOrgCode() + "*"));
        }
        /**
         * 96333
         */
        if(StringUtils.isNotEmpty(dpFilterParamForDetailDto.getCode96333())){
            boolMust.must(QueryBuilders.matchPhraseQuery("CODE96333", "*" + dpFilterParamForDetailDto.getCode96333() + "*"));
        }
        /**
         * 监管码
         */
        if(StringUtils.isNotEmpty(dpFilterParamForDetailDto.getSupervisoryCode())){
            boolMust.must(QueryBuilders.matchPhraseQuery("SUPERVISORY_CODE", "*" + dpFilterParamForDetailDto.getSupervisoryCode() + "*"));
        }
        /**
         * 所属地区
         */
        if(StringUtils.isNotEmpty(dpFilterParamForDetailDto.getUsePlace())){
            boolMust.must(QueryBuilders.matchPhraseQuery("USE_PLACE", "*" + dpFilterParamForDetailDto.getUsePlace() + "*"));
        }
        /**
         * 设备状态
         */
        if(StringUtils.isNotEmpty(dpFilterParamForDetailDto.getEquState())){
            boolMust.must(QueryBuilders.matchPhraseQuery("EQU_STATE", dpFilterParamForDetailDto.getEquState()));
        }
        /**
         * 信息化
         */
        if(StringUtils.isNotEmpty(dpFilterParamForDetailDto.getInformationSituation())){
            boolMust.must(QueryBuilders.matchPhraseQuery("INFORMATION_SITUATION","*" + dpFilterParamForDetailDto.getInformationSituation() + "*"));
        }
        /**
         * 设备类别
         */
        if(StrUtil.isNotEmpty(dpFilterParamForDetailDto.getEquCategory())){
            boolMust.must(QueryBuilders.matchPhraseQuery("EQU_CATEGORY", "*" + dpFilterParamForDetailDto.getEquCategory() + "*"));
        }
        //监管码状态0已赋码1未赋码
        if (StringUtils.isNotEmpty(dpFilterParamForDetailDto.getSupervisionCodeStatus())){
            if(StringUtils.equals("0",dpFilterParamForDetailDto.getSupervisionCodeStatus())){
                boolMust.must(QueryBuilders.existsQuery("SUPERVISORY_CODE"));
                boolMust.mustNot(QueryBuilders.termQuery("SUPERVISORY_CODE","null"));
            }else{
                boolMust.mustNot(QueryBuilders.existsQuery("SUPERVISORY_CODE"));
            }
        }

        if(StringUtils.isNotEmpty(dpFilterParamForDetailDto.getNextInspectionDate())){
            boolMust.must(QueryBuilders.rangeQuery("NEXT_INSPECT_DATE").gte(DateUtil.parse(dpFilterParamForDetailDto.getNextInspectionDate()).getTime()));
        }

        searchSourceBuilder.query(boolMust);
        searchSourceBuilder.from(current - 1);
        searchSourceBuilder.size(size);
        searchSourceBuilder.trackTotalHits(true);
        request.source(searchSourceBuilder);

        // 创建查询构造器
        NativeSearchQuery query = new NativeSearchQueryBuilder()
                // 分页
                .withPageable(PageRequest.of(current - 1, size))
                //过滤条件
                .withQuery(boolMust).build();
        query.setTrackTotalHits(true);
        query.setMaxResults(size);
        List<Map<String,Object>> list = new LinkedList<>();
        long total = 0;
        Page<Map<String,Object>> result = new Page<>(current,size);
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            for (org.elasticsearch.search.SearchHit hit : response.getHits().getHits()) {
                System.out.println(hit);
                JSONObject jsonObject = (JSONObject) JSONObject.toJSON(hit);
                JSONObject dto2 = jsonObject.getJSONObject("sourceAsMap");
                if (!ValidationUtil.isEmpty(dto2.get(EQUSTATE))) {
                    Integer integer = Integer.valueOf(dto2.get(EQUSTATE).toString());
                    String equStatus = EquimentEnum.getName.get(integer);
                    dto2.put(EQUSTATE, equStatus);
                }
                if(!ValidationUtil.isEmpty(dto2.get(SUPERVISORYCODE)) && dto2.get(SUPERVISORYCODE) != "null"){
                    dto2.put("IS_SUPERVISORY_CODE","已赋码");
                }else{
                    dto2.put("IS_SUPERVISORY_CODE","未赋码");
                }
                list.add(dto2);
            }
            total = response.getInternalResponse().hits().getTotalHits().value;
            result.setRecords(list);
            result.setTotal(total);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return result;
    }
}
