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

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.statistics.api.enums.StatisticalAnalysisEnum;
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.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.CollectionUtils;
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.time.LocalDate;
import java.time.format.DateTimeFormatter;
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";

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    @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(StatisticalAnalysisEnum.equip.getKey());
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();

        createBoolQueryBuilder(boolMust, dpFilterParamForDetailDto, dpFilterParamForDetailDto.getOrgCode());
        // 且8大类，目的去掉脏数据
        boolMust.must(QueryBuilders.existsQuery("SUPERVISORY_CODE"));
        boolMust.mustNot(QueryBuilders.termQuery("SUPERVISORY_CODE", "null"));
        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(StatisticalAnalysisEnum.equip.getKey());
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        createBoolQueryBuilder(boolMust, dpFilterParamForDetailDto, dpFilterParamForDetailDto.getOrgCode());
        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(StatisticalAnalysisEnum.equip.getKey());
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        createBoolQueryBuilder(boolMust, dpFilterParamForDetailDto, dpFilterParamForDetailDto.getOrgCode());
        boolMust.must(QueryBuilders.termQuery("IS_INTO_MANAGEMENT", true));
        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(StatisticalAnalysisEnum.equip.getKey());
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        createBoolQueryBuilder(boolMust, dpFilterParamForDetailDto, dpFilterParamForDetailDto.getOrgCode());
        boolMust.filter(QueryBuilders.rangeQuery("NEXT_INSPECT_DATE").gte(LocalDate.now().format(formatter)).lte(LocalDate.now().plusDays(30).format(formatter)));
        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(StatisticalAnalysisEnum.equip.getKey());
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        createBoolQueryBuilder(boolMust, dpFilterParamForDetailDto, dpFilterParamForDetailDto.getOrgCode());
        boolMust.filter(QueryBuilders.rangeQuery("NEXT_INSPECT_DATE").lt(LocalDate.now().format(formatter)));
        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(StatisticalAnalysisEnum.equip.getKey());
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();
        createBoolQueryBuilder(boolMust, dpFilterParamForDetailDto, orgCode);
        //监管码状态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"));
            }
        }
        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;
    }

    private void createBoolQueryBuilder(BoolQueryBuilder boolMust, DPFilterParamForDetailDto dpFilterParamForDetailDto, String orgCode) {

        String orgBranchCode = null;
        if (dpFilterParamForDetailDto.getOrgBranchCode() != null) {
            if (dpFilterParamForDetailDto.getOrgBranchCode().contains("_")) {
                String code = dpFilterParamForDetailDto.getOrgBranchCode().split("_")[0];
                orgBranchCode = stCommonService.getAndSetOrgCode(code);
            }
        }
        // 按照管辖机构区域信息模糊查询
        boolMust.must(QueryBuilders.prefixQuery("ORG_BRANCH_CODE", orgCode));
        if (orgBranchCode != null) {
            boolMust.must(QueryBuilders.prefixQuery("ORG_BRANCH_CODE", orgBranchCode));
        }

        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())));
            }
        }
        String[] status = {"草稿", "已拒领", "待认领"};
        boolMust.mustNot(QueryBuilders.termsQuery("STATUS", Arrays.asList(status)));
        // 检验状态: 0:临期,1:超期
        if (StringUtils.isNotEmpty(dpFilterParamForDetailDto.getInspectionStatus())) {
            if (StringUtils.equals("0", dpFilterParamForDetailDto.getInspectionStatus())) {
                boolMust.filter(QueryBuilders.rangeQuery("NEXT_INSPECT_DATE").gte(LocalDate.now().format(formatter)).lte(LocalDate.now().plusDays(30).format(formatter)));
            } else {
                boolMust.filter(QueryBuilders.rangeQuery("NEXT_INSPECT_DATE").lt(LocalDate.now().format(formatter)));
            }
        }
        /**
         * 使用单位
         */
        if (StringUtils.isNotEmpty(dpFilterParamForDetailDto.getUseUnitName())) {
            boolMust.must(QueryBuilders.wildcardQuery("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.wildcardQuery("CODE96333", "*" + dpFilterParamForDetailDto.getCode96333() + "*"));
        }
        /**
         * 监管码
         */
        if (StringUtils.isNotEmpty(dpFilterParamForDetailDto.getSupervisoryCode())) {
            boolMust.must(QueryBuilders.wildcardQuery("SUPERVISORY_CODE", "*" + dpFilterParamForDetailDto.getSupervisoryCode() + "*"));
        }
        /**
         * 所属地区
         */
        if (StringUtils.isNotEmpty(dpFilterParamForDetailDto.getUsePlace())) {
            boolMust.must(QueryBuilders.wildcardQuery("USE_PLACE", "*" + dpFilterParamForDetailDto.getUsePlace().replace(",", "/") + "*"));
        }
        /**
         * 设备状态
         */
        if (StringUtils.isNotEmpty(dpFilterParamForDetailDto.getEquState())) {
            boolMust.must(QueryBuilders.matchPhraseQuery("EQU_STATE", EquimentEnum.getCode.get(dpFilterParamForDetailDto.getEquState())));
        }
        /**
         * 信息化
         */
        if (StringUtils.isNotEmpty(dpFilterParamForDetailDto.getInformationSituation())) {
            boolMust.must(QueryBuilders.matchQuery("INFORMATION_SITUATION", dpFilterParamForDetailDto.getInformationSituation()));
        }
        /**
         * 设备类别
         */
        if (StrUtil.isNotEmpty(dpFilterParamForDetailDto.getEquCategory())) {
            boolMust.must(QueryBuilders.wildcardQuery("EQU_CATEGORY", "*" + dpFilterParamForDetailDto.getEquCategory() + "*"));
        }

        if (!CollectionUtils.isEmpty(dpFilterParamForDetailDto.getNextInspectionDate())) {
            String startDate = dpFilterParamForDetailDto.getNextInspectionDate().get(0);
            String endDate = dpFilterParamForDetailDto.getNextInspectionDate().get(1);
            if (startDate != null && endDate != null) {
                boolMust.filter(QueryBuilders.rangeQuery("NEXT_INSPECT_DATE").gte(startDate).lte(endDate));
            } else if (startDate != null) {
                boolMust.filter(QueryBuilders.rangeQuery("NEXT_INSPECT_DATE").gte(startDate));
            } else if (endDate != null) {
                boolMust.filter(QueryBuilders.rangeQuery("NEXT_INSPECT_DATE").lte(endDate));
            }
        }
    }
}
