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

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.annotation.TechnicalParameter;
import com.yeejoin.amos.boot.biz.common.entity.BaseEntity;
import com.yeejoin.amos.boot.biz.common.entity.DataDictionary;
import com.yeejoin.amos.boot.biz.common.excel.ExcelUtil;
import com.yeejoin.amos.boot.biz.common.service.impl.DataDictionaryServiceImpl;
import com.yeejoin.amos.boot.biz.common.utils.DateUtils;
import com.yeejoin.amos.boot.module.common.api.dto.TechParamItem;
import com.yeejoin.amos.boot.module.common.biz.utils.TechParamUtil;
import com.yeejoin.amos.boot.module.jg.api.enums.DPMapStatisticsItemEnum;
import com.yeejoin.amos.boot.module.statistcs.biz.utils.JsonUtils;
import com.yeejoin.amos.boot.module.statistcs.biz.utils.MinioUtils;
import com.yeejoin.amos.boot.module.statistics.api.enums.EquipAdvanceSearchEnum;
import com.yeejoin.amos.boot.module.statistics.api.enums.ConditionEnum;
import com.yeejoin.amos.boot.module.statistics.api.enums.StatisticalAnalysisEnum;
import com.yeejoin.amos.boot.module.statistics.api.enums.UnitTypeEnum;
import com.yeejoin.amos.boot.module.statistics.api.mapper.TzsCustomFilterMapper;
import com.yeejoin.amos.boot.module.statistics.api.vo.EquipInfoVo;
import com.yeejoin.amos.boot.module.ymt.api.dto.EquipmentCategoryDto;
import com.yeejoin.amos.boot.module.ymt.api.enums.EquipmentClassifityEnum;
import com.yeejoin.amos.boot.module.ymt.api.mapper.EquipmentCategoryMapper;
import com.yeejoin.amos.feign.systemctl.Systemctl;
import com.yeejoin.amos.feign.systemctl.model.DictionarieValueModel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.join.ScoreMode;
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.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermsQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;
import org.typroject.tyboot.component.emq.EmqKeeper;
import org.typroject.tyboot.core.foundation.context.RequestContext;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 综合统计分析服务实现类
 *
 * @author system_generator
 * @date 2025-06-24
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class ComprehensiveStatisticalAnalysisServiceImpl {

    final static String EQU_LIST = "EQU_LIST";

    @Value("classpath:/json/equipCategory.json")
    private Resource equipCategory;
    private final TzsCustomFilterMapper tzsCustomFilterMapper;
    private final DataDictionaryServiceImpl dataDictionaryService;
    private final EmqKeeper emqKeeper;

    private final StCommonServiceImpl stCommonService;

    private final RestHighLevelClient restHighLevelClient;
    private final String DOWN_LOAD_START_TEMP = "{\"id\":\"%s\",\"status\":\"starting\",\"fileName\":\"%s\",\"time\":\"%s\"}";
    private final String DOWNLOAD_TOPIC = "/topic/download/excel/%s";
    private final String BUCKET_NAME = "upload";
    private final String UPLOAD_PATH = "/tzs/excelTempFile";

    @Autowired
    EquipmentCategoryMapper equipmentCategoryMapper;

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

    public List<Map<String, Object>> queryEquipmentCategory(String key) {
        List<Map<String, Object>> list;
        Map<String, List<Map<String, Object>>> resourceJson = JsonUtils.getResourceJson(equipCategory);
        if (key == null) {
            list = resourceJson.get(EquipmentClassifityEnum.ZHTJFX.getCode());
        } else {
            list = tzsCustomFilterMapper.selectEquipmentCategoryByParentId(key);
        }

        return list;
    }

    public JSONArray queryEquipmentSearchData(String value) {
        List<TechParamItem> paramMetaList = TechParamUtil.getParamMetaList(value);
        JSONArray list = new JSONArray();
        for (int i = 0; i < paramMetaList.size(); i++) {
            JSONObject object = new JSONObject();
            object.put("key", paramMetaList.get(i).getParamKey());
            object.put("value", paramMetaList.get(i).getParamKey());
            object.put("label", paramMetaList.get(i).getParamLabel());
            object.put("unit", paramMetaList.get(i).getUnit());
            JSONObject skillConfig = new JSONObject();
            skillConfig.put("conditions", getConditionList(paramMetaList.get(i).getParamType(), paramMetaList.get(i).getDictCode()));
            if (!ValidationUtil.isEmpty(paramMetaList.get(i).getDictCode())) {
                skillConfig.put("type", "select");
                skillConfig.put("data", getData(paramMetaList.get(i).getDictCode()));
            } else if (TechnicalParameter.ParamType.BIG_DECIMAL.equals(paramMetaList.get(i).getParamType())) {
                skillConfig.put("type", "inputNumber");
            } else if (TechnicalParameter.ParamType.STRING.equals(paramMetaList.get(i).getParamType())) {
                skillConfig.put("type", "input");
            } else if (TechnicalParameter.ParamType.DATE.equals(paramMetaList.get(i).getParamType())) {
                skillConfig.put("type", "date");
            }
            skillConfig.put("isMulti", false);
            object.put("skillConfig", skillConfig);
            list.add(object);
        }
        return list;
    }

    private JSONArray getData(String dictCode) {
        JSONArray jsonArray = new JSONArray();
        //根据dictCode查询数据字典
        List<DataDictionary> dictionaries = dataDictionaryService.getByType(dictCode);
        for (DataDictionary dictionary : dictionaries) {
            JSONObject object = new JSONObject();
            object.put("label", dictionary.getName());
            object.put("value", dictionary.getCode());
            object.put("key", dictionary.getCode());
            jsonArray.add(object);
        }
        return jsonArray;
    }

    private JSONArray getConditionList(TechnicalParameter.ParamType value, String dictCode) {
        return ConditionEnum.getByCode(ValidationUtil.isEmpty(dictCode) ? value : null);
    }

    public JSONArray queryAdvancedSearch(String type) {
        JSONArray all = new JSONArray();
        if("equip".equals(type)) {
            all = EquipAdvanceSearchEnum.getAll();
        }else if("company".equals(type)){

        } else if ("person".equals(type)) {

        }
        return all;
    }

    public JSONObject queryForPage(JSONObject filter) {
        JSONObject result = new JSONObject();
        Integer current = ObjectUtils.isEmpty(filter.getInteger("current")) ? 1 : filter.getInteger("current");
        Integer size = ObjectUtils.isEmpty(filter.getInteger("size")) ? 20 : filter.getInteger("size");

        Page<JSONObject> page = new Page<>(current, size);
        String businessType = filter.getString("businessType");
        if (ObjectUtils.isEmpty(businessType)) {
            JSONObject statics = new JSONObject();
            statics.put("totalCount", null);
            result.put("statics", statics);
            page.setRecords(new ArrayList<>());
            page.setTotal(0);
            result.put("pageData", page);
            return result;
        }
        if (StatisticalAnalysisEnum.equip.getCode().equals(businessType)) {
            result = queryEquipmentPage(filter, page, current, size);
        } else if (StatisticalAnalysisEnum.company.getCode().equals(businessType)) {
            result = queryCompanyPage(filter, page, current, size);
        } else {
            result = queryPersonPage(filter, page, current, size);
        }
        return result;
    }

    private JSONObject queryPersonPage(JSONObject filter, Page<JSONObject> page, Integer current, Integer size) {

        JSONObject result = new JSONObject();

        SearchRequest request = new SearchRequest();
        request.indices(StatisticalAnalysisEnum.person.getKey());
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.trackTotalHits(true);
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();

        String orgCode = filter.getString("orgCode");
        boolMust.must(QueryBuilders.prefixQuery("superviseOrgCode", orgCode));

        JSONObject filterParams = null;
        if (!ObjectUtils.isEmpty(filter.get("filterParams"))) {
            filterParams = JSONObject.parseObject(JSONObject.toJSONString(filter.get("filterParams")));
            String filterType = filter.getString("filterType");
            //快捷筛选和自定义筛选解析筛选规则不一致
            if (filterType.equals("advanced")) {
                filterParams.forEach((k, v) -> {
                    if (v instanceof JSONArray) {
                        if (!((JSONArray) v).contains("all")) {
                            String field = k;
                            if (k.equals("newPost") || k.equals("subPost") || k.equals("equipType") || k.equals("unitType")) {
                                boolMust.must(QueryBuilders.existsQuery(field));
                                ((JSONArray) v).forEach(item -> boolMust.should(QueryBuilders.wildcardQuery(field + ".keyword", "*" + item + "*")));
                                boolMust.minimumShouldMatch(1);
                            } else if (k.equals("education")) {
                                boolMust.must(QueryBuilders.existsQuery(field));
                                TermsQueryBuilder termsQuery = QueryBuilders.termsQuery(field, (JSONArray) v);
                                boolMust.must(termsQuery);
                            } else if (k.equals("certNo") || k.equals("expiryDate") || k.equals("permissionLevel") || k.equals("certType") || k.equals("jobItem") || k.equals("issueDate")) {
                                String path = "licenses";
                                ((JSONArray) v).forEach(item -> {
                                    String nestedField = path + "." + k;
                                    // 根据证书编号判断有无资质
                                    if (k.equals("certNo")) {
                                        NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                                path,
                                                QueryBuilders.existsQuery(nestedField),
                                                ScoreMode.Avg
                                        );
                                        if (item.equals("1")) {
                                            boolMust.must(nestedQuery);
                                        } else {
                                            boolMust.mustNot(nestedQuery);
                                        }
                                    } else if (k.equals("expiryDate")) {
                                        if (item.equals("overdue")) {
                                            // 超期：小于当前日期
                                            NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                                    path,
                                                    QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).lt(LocalDate.now().format(formatter))),
                                                    ScoreMode.Avg
                                            );
                                            boolMust.must(nestedQuery);
                                        } else if (item.equals("near")) {
                                            // 临期：小于等于当前日期加上30天
                                            NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                                    path,
                                                    QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).lte(LocalDate.now().plusDays(30).format(formatter))),
                                                    ScoreMode.Avg
                                            );
                                            boolMust.must(nestedQuery);
                                        } else if (item.equals("normal")) {
                                            // 正常：大于当前日期加上30天
                                            NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                                    path,
                                                    QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).gt(LocalDate.now().plusDays(30).format(formatter))),
                                                    ScoreMode.Avg
                                            );
                                            boolMust.must(nestedQuery);
                                        } else {
                                            // 无资质要求
                                            NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                                    path,
                                                    QueryBuilders.existsQuery(nestedField),
                                                    ScoreMode.Avg
                                            );
                                            boolMust.mustNot(nestedQuery);
                                        }
                                    } else if (k.equals("certType") || k.equals("permissionLevel") || k.equals("jobItem")) {
                                        NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                                path,
                                                QueryBuilders.boolQuery().must(QueryBuilders.termsQuery(nestedField, (JSONArray) v)),
                                                ScoreMode.Avg
                                        );
                                        boolMust.must(nestedQuery);
                                    }
                                });
                            } else if (k.equals("issueDate")) {
                                JSONArray issueDates = (JSONArray) v;
                                String startDate = DateUtils.convertDateToString(issueDates.getDate(0), DateUtils.DATE_PATTERN);
                                String endDate = DateUtils.convertDateToString(issueDates.getDate(1), DateUtils.DATE_PATTERN);
                                NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                        "licenses",
                                        QueryBuilders.rangeQuery("issueDate").gte(startDate).lte(endDate),
                                        ScoreMode.Avg
                                );
                                boolMust.filter(nestedQuery);
                            }
                        } else {
                            //todo 高级筛选

                        }
                    }
                });
            }
        }
        // 排序
        if (!ObjectUtils.isEmpty(filter.get("sort"))) {
            JSONObject sort = JSONObject.parseObject(JSONObject.toJSONString(filter.get("sort")));
            String field = sort.getString("filed");
            SortOrder sortOrder = sort.getString("order").equals("desc") ? SortOrder.DESC : SortOrder.ASC;
            FieldSortBuilder sortBuilder = SortBuilders.fieldSort(field + ".keyword").order(sortOrder);
            builder.sort(sortBuilder);
        }
        builder.query(boolMust);
        builder.from((current - 1) * size);
        builder.size(size);
        request.source(builder);

        List<JSONObject> list = new LinkedList<>();
        long totle = 0;
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            for (SearchHit hit : response.getHits().getHits()) {
                JSONObject jsonObject = (JSONObject) JSONObject.toJSON(hit);
                JSONObject dto = jsonObject.getJSONObject("sourceAsMap");
                if (dto.containsKey("identification")) {
                    dto.put("identification", JSONObject.parseObject(JSONObject.parseArray(dto.get("identification").toString()).get(0).toString()).get("url"));
                }
                list.add(dto);
            }
            totle = Objects.requireNonNull(response.getInternalResponse().hits().getTotalHits()).value;
            page.setRecords(list);
            page.setTotal(totle);
            result.put("pageData", page);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        List<Map<String, Object>> statics = new ArrayList<>();
        Map<String, Object> sum = new HashMap<>();
        sum.put("name", "人员总数（人）");
        sum.put("value", totle);
        statics.add(sum);
        result.put("statics", statics);

        return result;
    }

    private JSONObject queryCompanyPage(JSONObject filter, Page<JSONObject> page, Integer current, Integer size) {

        JSONObject result = new JSONObject();

        SearchRequest request = new SearchRequest();
        request.indices(StatisticalAnalysisEnum.company.getKey());
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.trackTotalHits(true);
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();

        String orgCode = filter.getString("orgCode");
        boolMust.must(QueryBuilders.prefixQuery("superviseOrgCode", orgCode));
        JSONObject filterParams = null;
        if (!ObjectUtils.isEmpty(filter.get("filterParams"))) {
            filterParams = JSONObject.parseObject(JSONObject.toJSONString(filter.get("filterParams")));
            String filterType = filter.getString("filterType");
            //快捷筛选和自定义筛选解析筛选规则不一致
            if (filterType.equals("advanced")) {
                filterParams.forEach((k, v) -> {
                    if (v instanceof JSONArray) {
                        if (!((JSONArray) v).contains("all")) {
                            String field = k;
                            if (k.equals("regulatoryLabels") || k.equals("equipCategory") || k.equals("unitType")) {
                                boolMust.must(QueryBuilders.existsQuery(field));
                                ((JSONArray) v).forEach(item -> boolMust.should(QueryBuilders.wildcardQuery(field + ".keyword", "*" + item + "*")));
                                boolMust.minimumShouldMatch(1);
                            } else if (k.equals("industrySupervisor") || k.equals("operatingStatus")) {
                                boolMust.must(QueryBuilders.existsQuery(field));
                                TermsQueryBuilder termsQuery = QueryBuilders.termsQuery(field, (JSONArray) v);
                                boolMust.must(termsQuery);
                            } else if (k.equals("itemCode") || k.equals("subItemCode") || k.equals("permitStatus")) {
                                String path = "licenses";
                                ((JSONArray) v).forEach(item -> {
                                    String nestedField = path + "." + (k.equals("permitStatus") ? "expiryDate" : k + ".keyword");
                                    if (k.equals("permitStatus")) {
                                        if (item.equals("overdue")) {
                                            // 超期：小于当前日期
                                            NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                                    path,
                                                    QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).lt(LocalDate.now().format(formatter))),
                                                    ScoreMode.Avg
                                            );
                                            boolMust.must(nestedQuery);
                                        } else if (item.equals("near")) {
                                            // 临期：小于等于当前日期加上30天
                                            NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                                    path,
                                                    QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).lte(LocalDate.now().plusDays(30).format(formatter)).gte(LocalDate.now().format(formatter))),
                                                    ScoreMode.Avg
                                            );
                                            boolMust.must(nestedQuery);
                                        } else if (item.equals("normal")) {
                                            // 正常：大于当前日期加上30天
                                            NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                                    path,
                                                    QueryBuilders.boolQuery().filter(QueryBuilders.rangeQuery(nestedField).gt(LocalDate.now().plusDays(30).format(formatter))),
                                                    ScoreMode.Avg
                                            );
                                            boolMust.must(nestedQuery);
                                        }
                                    } else {
                                        // 创建嵌套查询
                                        NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery(
                                                path,
                                                QueryBuilders.termsQuery(nestedField, item),
                                                ScoreMode.Avg
                                        );
                                        boolMust.must(nestedQuery);
                                    }
                                });
                            }
                        }
                    }
                });
            }
        }


        // 排序
        if (!ObjectUtils.isEmpty(filter.get("sort"))) {
            JSONObject sort = JSONObject.parseObject(JSONObject.toJSONString(filter.get("sort")));
            String field = sort.getString("filed");
            SortOrder sortOrder = sort.getString("order").equals("desc") ? SortOrder.DESC : SortOrder.ASC;
            FieldSortBuilder sortBuilder = SortBuilders.fieldSort(field + ".keyword").order(sortOrder);
            builder.sort(sortBuilder);
        }

        builder.query(boolMust);
        builder.from((current - 1) * size);
        builder.size(size);
        request.source(builder);

        List<JSONObject> list = new LinkedList<>();
        long totle = 0;

        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            for (SearchHit hit : response.getHits().getHits()) {
                JSONObject jsonObject = (JSONObject) JSONObject.toJSON(hit);
                JSONObject dto = jsonObject.getJSONObject("sourceAsMap");
                list.add(dto);
            }
            totle = Objects.requireNonNull(response.getInternalResponse().hits().getTotalHits()).value;
            page.setRecords(list);
            page.setTotal(totle);
            result.put("pageData", page);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


        List<Map<String, Object>> statics = new ArrayList<>();
        Map<String, Object> sum = new HashMap<>();
        sum.put("name", "企业总数（个）");
        sum.put("value", totle);
        statics.add(sum);
        result.put("statics", statics);

        return result;
    }

    private JSONObject queryEquipmentPage(JSONObject filter, Page<JSONObject> page, Integer current, Integer size) {

        JSONObject result = new JSONObject();

        SearchRequest request = new SearchRequest();
        request.indices(StatisticalAnalysisEnum.equip.getKey());
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.trackTotalHits(true);
        BoolQueryBuilder boolMust = QueryBuilders.boolQuery();

        String orgCode = filter.getString("orgCode");
        boolMust.must(QueryBuilders.prefixQuery("ORG_BRANCH_CODE", orgCode));
        JSONObject filterParams;
        // 筛选
        if (!ObjectUtils.isEmpty(filter.get("filterParams"))) {
            filterParams = JSONObject.parseObject(JSONObject.toJSONString(filter.get("filterParams")));
            String filterType = filter.getString("filterType");
            //快捷筛选和自定义筛选解析筛选规则不一致
            if (filterType.equals("advanced")) {
                filterParams.forEach((k, v) -> {
                    if (k.equals("techParam")) {
                        JSONArray techParams = (JSONArray) v;
                        if (!techParams.contains("all") && techParams.size() == 1) {
                            JSONObject paramRangeJson = JSONObject.parseObject(JSONObject.toJSONString(filterParams.get("paramRange")));
                            String paramKey = techParams.getString(0);
                            String condition = paramRangeJson.getString("condition");
                            Object value = paramRangeJson.getString("value");
                            getParamQuery(paramKey, condition, value, boolMust);
                        }
                    } else if (!k.equals("paramRange")) {
                        if (v instanceof JSONArray) {
                            if (!((JSONArray) v).contains("all")) {
                                String field = k;
                                // todo 所属单位筛选争议，需确认后完成
                                if (k.equals("NEXT_INSPECT_DATE")) {
                                    String finalField = field;
                                    boolMust.must(QueryBuilders.existsQuery(finalField));
                                    ((JSONArray) v).forEach(item -> {
                                        if (item.equals("overdue")) {
                                            // 超期：小于当前日期
                                            boolMust.filter(QueryBuilders.rangeQuery(finalField).lt(LocalDate.now().format(formatter)));
                                        } else if (item.equals("near")) {
                                            // 临期：小于等于当前日期加上30天
                                            boolMust.filter(QueryBuilders.rangeQuery(finalField).lte(LocalDate.now().plusDays(30).format(formatter)));
                                        } else {
                                            // 正常：大于当前日期加上30天
                                            boolMust.filter(QueryBuilders.rangeQuery(finalField).gt(LocalDate.now().plusDays(30).format(formatter)));
                                        }
                                    });
                                } else if (k.equals("USC_DATE")) {
                                    String finalField = field;
                                    boolMust.must(QueryBuilders.existsQuery(finalField));
                                    ((JSONArray) v).forEach(item -> {
                                        if (item.equals("15")) {
                                            // 15年以上：大于当前日期减去15年
                                            boolMust.filter(QueryBuilders.rangeQuery(finalField).gt(LocalDate.now().minusYears(15).format(formatter)));
                                        } else if (item.equals("10-15")) {
                                            // 10-15年：小于当前日期减去15年，大于等于当前日期减去10年
                                            boolMust.filter(QueryBuilders.rangeQuery(finalField).lt(LocalDate.now().minusYears(15).format(formatter)));
                                            boolMust.filter(QueryBuilders.rangeQuery(finalField).gte(LocalDate.now().minusYears(10).format(formatter)));
                                        } else if (item.equals("5-10")) {
                                            // 5-10年：小于当前日期减去10年，大于等于当前日期减去5年
                                            boolMust.filter(QueryBuilders.rangeQuery(finalField).lt(LocalDate.now().minusYears(10).format(formatter)));
                                            boolMust.filter(QueryBuilders.rangeQuery(finalField).gte(LocalDate.now().minusYears(5).format(formatter)));
                                        } else if (item.equals("0-5")) {
                                            // 0-5年：小于当前日期减去5年
                                            boolMust.filter(QueryBuilders.rangeQuery(finalField).lt(LocalDate.now().minusYears(5).format(formatter)));
                                        }
                                    });
                                } else if (k.equals("IS_SUPERVISORY_CODE")) {
                                    String finalField = "IS_SUPERVISORY_CODE";
                                    ((JSONArray) v).forEach(item -> {
                                        if (item.equals("1")) {
                                            boolMust.must(QueryBuilders.existsQuery(finalField));
                                            boolMust.mustNot(QueryBuilders.termQuery(finalField, "null"));
                                        } else {
                                            boolMust.mustNot(QueryBuilders.existsQuery(finalField));
                                        }
                                    });
                                } else if (k.equals("createDate")) {
                                    JSONArray createDates = (JSONArray) v;
                                    String startDate = DateUtils.convertDateToString(createDates.getDate(0), DateUtils.DATE_TIME_PATTERN);
                                    String endDate = DateUtils.convertDateToString(createDates.getDate(1), DateUtils.DATE_TIME_PATTERN);
                                    boolMust.filter(QueryBuilders.rangeQuery("createDate").gte(startDate.replace(" ", "T")).lte(endDate.replace(" ", "T")));
                                } else if (k.equals("EQU_LIST") || k.equals("EQU_CATEGORY") || k.equals("EQU_DEFINE") || k.equals("EQU_STATE") || k.equals("DATA_QUALITY_SCORE") || k.equals("DATA_SOURCE")) {
                                    if (k.equals("EQU_LIST")) {
                                        field = "EQU_LIST_CODE";
                                    } else if (k.equals("EQU_CATEGORY")) {
                                        field = "EQU_CATEGORY_CODE";
                                    } else if (k.equals("EQU_DEFINE")) {
                                        field = "EQU_DEFINE_CODE";
                                    }
                                    boolMust.must(QueryBuilders.existsQuery(field));
                                    TermsQueryBuilder termsQuery = QueryBuilders.termsQuery(field, (JSONArray) v);
                                    boolMust.must(termsQuery);
                                }

                            }
                        }
                    }
                });
            } else {
                // todo 自定义筛选

            }
        } else {
            filterParams = null;
        }

        //  排序
        if (!ObjectUtils.isEmpty(filter.get("sort"))) {
            JSONObject sort = JSONObject.parseObject(JSONObject.toJSONString(filter.get("sort")));
            String field = sort.getString("filed");
            if (field.equals("EQU_LIST")) {
                field = "EQU_LIST_CODE";
            } else if (field.equals("EQU_CATEGORY")) {
                field = "EQU_CATEGORY_CODE";
            } else if (field.equals("EQU_DEFINE")) {
                field = "EQU_DEFINE_CODE";
            } else {
                field = field + ".keyword";
            }
            builder.sort(field, sort.getString("order").equals("desc") ? SortOrder.DESC : SortOrder.ASC);
        }

        builder.query(boolMust);

        builder.from((current - 1) * size);
        builder.size(size);
        request.source(builder);

        List<JSONObject> list = new LinkedList<>();
        long totle = 0;
        long pipeLong = 0L;
        try {
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            for (SearchHit hit : response.getHits().getHits()) {
                JSONObject jsonObject = (JSONObject) JSONObject.toJSON(hit);
                JSONObject dto = jsonObject.getJSONObject("sourceAsMap");
                dto.put("record", dto.get("SEQUENCE_NBR"));
                dto.put("equipAddress", dto.get("USE_PLACE") + "/" + dto.get("ADDRESS"));
                if (dto.get("EQU_LIST_CODE").equals("8000")) {
                    JSONArray techParams = (JSONArray) dto.get("techParams");
                    if (!ObjectUtils.isEmpty(techParams)) {
                        Object obj = techParams.stream().filter(item -> JSONObject.parseObject(JSONObject.toJSONString(item)).get("paramKey").equals("pipeLength")).findFirst().get();
                        JSONObject jsonParam = JSONObject.parseObject(JSONObject.toJSONString(obj));
                        if (jsonParam.containsKey("strValue")) {
                            String pipeLength = JSONObject.parseObject(JSONObject.toJSONString(obj)).get("strValue").toString();
                            pipeLong += Long.parseLong(pipeLength);
                        }
                    }
                }
                list.add(dto);
            }
            totle = Objects.requireNonNull(response.getInternalResponse().hits().getTotalHits()).value;
            page.setRecords(list);
            page.setTotal(totle);
            result.put("pageData", page);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        List<Map<String, Object>> statics = new ArrayList<>();
        Map<String, Object> sum = new HashMap<>();
        sum.put("name", "设备总数（台套）");
        sum.put("value", totle);
        statics.add(sum);

        if (!ObjectUtils.isEmpty(filterParams) && filterParams.containsKey("EQU_LIST")) {
            JSONArray equList = (JSONArray) filterParams.get("EQU_LIST");
            if (equList.contains("8000") || equList.contains("all")) {
                // 压力管道长度
                Map<String, Object> pipeMap = new HashMap<>();
                pipeMap.put("name", "压力管道（千米）");
                pipeMap.put("value", pipeLong);
                statics.add(pipeMap);
            }
            if (equList.contains("2000") || equList.contains("all")) {
                // 气瓶数量
                Map<String, Object> gasMap = new HashMap<>();
                gasMap.put("name", "气瓶（个）");
                Map<String, Object> gas = new HashMap<>();
                gas.put(DPMapStatisticsItemEnum.GAS.getCode(), 0);
                long cylinderNum = stCommonService.staticsCenterMapCountDataForCylinder(gas, orgCode, true, true, false);
                // 1. 8大类设备数量统计,压力容器里包括气瓶所以需要特殊处理，在统计压力容器时去掉气瓶的数量
                stCommonService.staticsCenterMapCountDataForEquip(gas, cylinderNum, orgCode, true, true, false);
                gasMap.put("value", gas.get(DPMapStatisticsItemEnum.GAS.getCode()));
                statics.add(gasMap);
            }
        }
        result.put("statics", statics);

        return result;
    }

    private void getParamQuery(String paramKey, String condition, Object value, BoolQueryBuilder boolMust) {
        String path = "techParams";
        String nestedFieldKey = path + ".paramKey";
        String nestedFieldValue = path + ".strValue";
        NestedQueryBuilder keyNestedQuery = QueryBuilders.nestedQuery(
                path,
                QueryBuilders.boolQuery().must(QueryBuilders.termsQuery(nestedFieldKey, paramKey)),
                ScoreMode.Avg
        );
        boolMust.must(keyNestedQuery);
        switch (condition) {
            case "eq":
                NestedQueryBuilder eqQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(QueryBuilders.termsQuery(nestedFieldValue, value)),
                        ScoreMode.Avg
                );
                boolMust.must(eqQuery);
                break;
            case "neq":
                boolMust.must(keyNestedQuery);
                NestedQueryBuilder neqQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().mustNot(QueryBuilders.termsQuery(nestedFieldValue, value)),
                        ScoreMode.Avg
                );
                boolMust.mustNot(neqQuery);
                break;
            case "like":
                NestedQueryBuilder likeQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().should(QueryBuilders.wildcardQuery(nestedFieldValue, "*" + value + "*")),
                        ScoreMode.Avg
                );
                boolMust.must(likeQuery);
                break;
            case "notLike":
                NestedQueryBuilder notLikeQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().should(QueryBuilders.wildcardQuery(nestedFieldValue, "*" + value + "*")),
                        ScoreMode.Avg
                );
                boolMust.mustNot(notLikeQuery);
                break;
            case "gt":
                NestedQueryBuilder gtQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery(nestedFieldValue).gt(Double.parseDouble(value.toString()))),
                        ScoreMode.Avg
                );
                boolMust.must(gtQuery);
                break;
            case "gte":
                NestedQueryBuilder gteQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery(nestedFieldValue).gte(Double.parseDouble(value.toString()))),
                        ScoreMode.Avg
                );
                boolMust.must(gteQuery);
                break;
            case "lt":
                NestedQueryBuilder ltQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery(nestedFieldValue).lt(Double.parseDouble(value.toString()))),
                        ScoreMode.Avg
                );
                boolMust.must(ltQuery);
                break;
            case "lte":
                NestedQueryBuilder lteQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery(nestedFieldValue).lte(Double.parseDouble(value.toString()))),
                        ScoreMode.Avg
                );
                boolMust.must(lteQuery);
                break;
            case "between":
                JSONArray btValues = (JSONArray) value;
                NestedQueryBuilder betweenQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery(nestedFieldValue).gte(Double.parseDouble(btValues.get(0).toString())).lte(Double.parseDouble(btValues.get(1).toString()))),
                        ScoreMode.Avg
                );
                boolMust.must(betweenQuery);
                break;
            case "in":
                JSONArray inValues = (JSONArray) value;
                NestedQueryBuilder inQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(QueryBuilders.termsQuery(nestedFieldValue, inValues)),
                        ScoreMode.Avg
                );
                boolMust.must(inQuery);
                break;
            case "notIn":
                JSONArray notInValues = (JSONArray) value;
                NestedQueryBuilder notInQuery = QueryBuilders.nestedQuery(
                        path,
                        QueryBuilders.boolQuery().must(QueryBuilders.termsQuery(nestedFieldValue, notInValues)),
                        ScoreMode.Avg
                );
                boolMust.mustNot(notInQuery);
                break;
        }
    }

    public JSONArray queryUnitType() {
        return UnitTypeEnum.getAll();
    }

    public JSONObject queryCompanySearchData() {
        JSONObject result = new JSONObject();
        //获取企业类型
        result.put("unitType", UnitTypeEnum.getAll());

        //获取企业等级
        result.put("regulatoryLabels", deployDictionary(dataDictionaryService.getByType("QYBQ")));

        //行业主管部门
        result.put("industrySupervisor", deployDictionary(dataDictionaryService.getByType("HYZGBM")));
        //经营状态
        result.put("operatingStatus", deployDictionary(dataDictionaryService.getByType("jyzt")));

        //许可状态
        JSONArray permitStatusData = new JSONArray();
        for (int i = 0; i < 3; i++) {
            JSONObject object = new JSONObject();
            if(0==i){
                object.put("key", "overdue");
                object.put("value", "overdue");
                object.put("label", "超期");
            }else if(1==i){
                object.put("key", "near");
                object.put("value", "near");
                object.put("label", "临期");
            }else{
                object.put("key", "normal");
                object.put("value", "normal");
                object.put("label", "正常");
            }
            permitStatusData.add(object);
        }
        result.put("permitStatus", permitStatusData);

        //监管设备类型
        List<EquipmentCategoryDto> equipmentCategoryDtos = equipmentCategoryMapper.selectClassify();
        JSONArray equipCategoryData = new JSONArray();
        for (int i = 0; i < equipmentCategoryDtos.size(); i++) {
            JSONObject object = new JSONObject();
            object.put("key", equipmentCategoryDtos.get(i).getCode());
            object.put("value", equipmentCategoryDtos.get(i).getCode());
            object.put("label", equipmentCategoryDtos.get(i).getName());
            equipCategoryData.add(object);
        }
        result.put("equipCategory", equipCategoryData);

        return result;
    }

    public JSONObject queryPersonSearchData() {
        JSONObject result = new JSONObject();
        //资质状态
        JSONArray permissionStatus = new JSONArray();
        for(int i=0;i<3;i++){
            JSONObject object = new JSONObject();
            if(0==i){
                object.put("key", "noLicenses");
                object.put("value", "noLicenses");
                object.put("label", "无资质要求");
            }else if(1==i){
                object.put("key", "overdue");
                object.put("value", "overdue");
                object.put("label", "资质超期");
            }else if(2==i){
                object.put("key", "near");
                object.put("value", "near");
                object.put("label", "资质临期");
            }else {
                object.put("key", "normal");
                object.put("value", "normal");
                object.put("label", "正常");
            }
            permissionStatus.add(object);
        }
        result.put("expiryDate", permissionStatus);
        //证书类型
        List<DictionarieValueModel> certType = Systemctl.dictionarieClient.dictValues("CERT_TYPE").getResult();
        JSONArray certTypeArray = new JSONArray();
        for(int i=0;i<certType.size();i++){
            JSONObject object = new JSONObject();
            object.put("key", certType.get(i).getDictDataKey());
            object.put("value", certType.get(i).getDictDataKey());
            object.put("label", certType.get(i).getDictDataValue());
            certTypeArray.add(object);
        }
        result.put("certType", certTypeArray);
        //证书级别
        List<DictionarieValueModel> RYJB_JC = Systemctl.dictionarieClient.dictValues("RYJB_JC").getResult();
        List<DictionarieValueModel> RYJB_JY = Systemctl.dictionarieClient.dictValues("RYJB_JY").getResult();
        JSONArray permissionLevelArray = new JSONArray();
        for(int i=0;i<RYJB_JC.size();i++){
            JSONObject object = new JSONObject();
            object.put("key", RYJB_JC.get(i).getDictDataKey());
            object.put("value", RYJB_JC.get(i).getDictDataKey());
            object.put("label", RYJB_JC.get(i).getDictDataValue());
            permissionLevelArray.add(object);
        }
        for(int i=0;i<RYJB_JY.size();i++){
            JSONObject object = new JSONObject();
            object.put("key", RYJB_JY.get(i).getDictDataKey());
            object.put("value", RYJB_JY.get(i).getDictDataKey());
            object.put("label", RYJB_JY.get(i).getDictDataValue());
            permissionLevelArray.add(object);
        }
        result.put("permissionLevel", permissionLevelArray);
        //学历
        result.put("education", deployDictionary(dataDictionaryService.getByType("XLLX")));
        //监管设备类型
        List<EquipmentCategoryDto> equipmentCategoryDtos = equipmentCategoryMapper.selectClassify();
        JSONArray equipCategoryData = new JSONArray();
        for(int i=0;i<equipmentCategoryDtos.size();i++){
            JSONObject object = new JSONObject();
            object.put("key", equipmentCategoryDtos.get(i).getCode());
            object.put("value", equipmentCategoryDtos.get(i).getCode());
            object.put("label", equipmentCategoryDtos.get(i).getName());
            equipCategoryData.add(object);
        }
        result.put("equipType", equipCategoryData);
        //获取企业类型
        result.put("unitType", UnitTypeEnum.getAll());
        return result;
    }

    public JSONArray deployDictionary(List<DataDictionary> list) {
        JSONArray result = new JSONArray();
        for (int i = 0; i < list.size(); i++) {
            JSONObject object = new JSONObject();
            object.put("key", list.get(i).getCode());
            object.put("value", list.get(i).getCode());
            object.put("label", list.get(i).getName());
            result.add(object);
        }

        return result;
    }

    public JSONArray queryXK(String type) {
        JSONArray result = new JSONArray();
        if (ValidationUtil.isEmpty(type)) {
            List<DataDictionary> xkxm = dataDictionaryService.lambdaQuery().like(DataDictionary::getType, "XKXM").eq(BaseEntity::getIsDelete, false).list();
            result = deployDictionary(xkxm);
        } else {
            List<DataDictionary> childrenxkxm = dataDictionaryService.lambdaQuery().eq(DataDictionary::getTypeDesc, type).eq(BaseEntity::getIsDelete, false).list();
            result = deployDictionary(childrenxkxm);
        }
        return result;
    }


    public JSONArray queryRYLX(String type) {
        JSONArray result = new JSONArray();
        if (ValidationUtil.isEmpty(type)) {
            List<String> typeList = new ArrayList<>(Arrays.asList(
                    "QYRYGW",
                    "QYRYGW-SYDW",
                    "QYRYGW-SCDW",
                    "QYRYGW-INSTALL",
                    "QYRYGW-INSPECTION"
            ));
            result = deployDictionary(dataDictionaryService.lambdaQuery()
                    .select(DataDictionary::getName, DataDictionary::getCode)
                    .eq(DataDictionary::getIsDelete, false)
                    .isNull(DataDictionary::getParent)
                    .in(DataDictionary::getType, typeList)
                    .list());
        } else {
            List<DataDictionary> childrenrylx = dataDictionaryService.lambdaQuery()
                    .in(DataDictionary::getParent, type)
                    .like(DataDictionary::getType, "QYRYGW")
                    .orderByAsc(DataDictionary::getSortNum)
                    .list();
            ;
            result = deployDictionary(childrenrylx);
        }
        return result;
    }

    /**
     * 开始下载 发送消息
     */
    public void startDownLoadMsg(String fileName, String uuid) {
        try {
            emqKeeper.getMqttClient().publish(String.format(DOWNLOAD_TOPIC, RequestContext.getToken()),
                    String.format(DOWN_LOAD_START_TEMP, uuid, fileName, new Date().getTime()).getBytes(StandardCharsets.UTF_8),
                    2, false);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    /**
     * 发送主题消息，给企业推送excel 结束下载提醒
     *
     * @param topic      主体格式为： /download/excel/${token}
     * @param jsonObject 文件名称 + excel文件路径（minio）
     */
    public void sendDownLoadExcelMsg(String topic, JSONObject jsonObject) {
        try {
            emqKeeper.getMqttClient().publish(topic, JSONObject.toJSONString(jsonObject).getBytes(StandardCharsets.UTF_8), 2, false);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    /**
     * 综合统计分析接口-导出
     *
     * @param uuid   uuid
     * @param filter 过滤条件
     */
    public void export(String uuid, JSONObject filter) {
        // 查询数据
        JSONObject jsonData = this.queryForPage(filter);
        // 类型转化
        List<EquipInfoVo> exportData = JSONArray.parseArray(JSON.toJSONString(jsonData.get("pageData")), EquipInfoVo.class);
        // 转化附件
        MultipartFile templateExcelFile = ExcelUtil.createTemplateExcelFile("综合统计分析设备列表数据",
                "综合统计分析设备列表", exportData, EquipInfoVo.class, null, false);
        // 上传minio服务器
        String urlString = MinioUtils.uploadExcelFile(templateExcelFile, BUCKET_NAME, UPLOAD_PATH);
        // 提醒下载
        this.sendDownLoadExcelMsg(String.format(DOWNLOAD_TOPIC, RequestContext.getToken()), new JSONObject()
                .fluentPut("id", uuid)
                .fluentPut("status", "done")
                .fluentPut("fileName", "综合统计分析设备列表")
                .fluentPut("url", urlString)
                .fluentPut("time", new Date().getTime()));
    }

    public JSONArray queryZYXM(String type) {
        JSONArray result = new JSONArray();
        if("特种设备安全管理和作业人员证".equals(type)){
            List<DictionarieValueModel> certType = Systemctl.dictionarieClient.dictValues("JOB_ITEM").getResult();
            for (DictionarieValueModel certTypeModel : certType) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("key", certTypeModel.getDictDataKey());
                jsonObject.put("value", certTypeModel.getDictDataKey());
                jsonObject.put("label", certTypeModel.getDictDataValue());
                result.add(jsonObject);
            }
        }else {
            List<DictionarieValueModel> certType = Systemctl.dictionarieClient.dictValues("ZZXM_"+type).getResult();
            for (DictionarieValueModel certTypeModel : certType) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("key", certTypeModel.getDictDataKey());
                jsonObject.put("value", certTypeModel.getDictDataKey());
                jsonObject.put("label", certTypeModel.getDictDataValue());
                result.add(jsonObject);
            }
        }
        return result;
    }

    public JSONArray queryUnitByOrgCode(String orgCode) {
        SearchRequest searchRequest = new SearchRequest("idx_biz_enterprise_info");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.wildcardQuery("superviseOrgCode.keyword",  QueryParser.escape(orgCode) + "*"));
        searchSourceBuilder.query(boolQueryBuilder);
        searchRequest.source(searchSourceBuilder);

        JSONArray result = new JSONArray();
        try {
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            for (org.elasticsearch.search.SearchHit hit : searchResponse.getHits().getHits()) {
                JSONObject jsonObject = ((JSONObject) JSONObject.toJSON(hit)).getJSONObject("sourceAsMap");
                JSONObject dto = new JSONObject();
                dto.put("key",jsonObject.getString("useCode"));
                dto.put("value",jsonObject.getString("useCode"));
                dto.put("label",jsonObject.getString("useUnit"));
                result.add(dto);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return result;
    }
}