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.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.module.common.api.dto.TechParamItem;
import com.yeejoin.amos.boot.module.common.biz.utils.TechParamUtil;
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.AdvanceSearchEnum;
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.mapper.TzsCustomFilterMapper;
import com.yeejoin.amos.boot.module.statistics.api.vo.EquipInfoVo;
import com.yeejoin.amos.boot.module.ymt.api.enums.EquipmentClassifityEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.QueryBuilders;
import org.elasticsearch.index.query.TermsQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
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 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";
    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 JSONObject queryEquipmentSearchData(String value) {
        List<TechParamItem> paramMetaList = TechParamUtil.getParamMetaList(value);
        ArrayList<JSONObject> list = new ArrayList<>();
        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);
        }
        JSONObject result = new JSONObject();
        result.put("techParam", list);
        return result;
    }

    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());
            jsonArray.add(object);
        }
        return jsonArray;
    }

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

    public JSONArray queryAdvancedSearch() {
        JSONArray all = AdvanceSearchEnum.getAll();
        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("pageSize")) ? 20 : filter.getInteger("pageSize");

        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();
        // 排序
        if (!ObjectUtils.isEmpty(filter.get("sort"))) {
            JSONObject sort = JSONObject.parseObject(JSONObject.toJSONString(filter.get("sort")));
            builder.sort(sort.getString("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;
        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 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();

        // 排序
        if (!ObjectUtils.isEmpty(filter.get("sort"))) {
            JSONObject sort = JSONObject.parseObject(JSONObject.toJSONString(filter.get("sort")));
            builder.sort(sort.getString("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;

        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();

        // 筛选
        if (!ObjectUtils.isEmpty(filter.get("filterParams"))) {
            JSONObject 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")) {

                    } else {
                        if (v instanceof JSONArray) {
                            if (!((JSONArray) v).contains("all")) {
                                String field = k;
                                // todo 所属单位筛选争议，需确认后完成
                                if (k.equals("NEXT_INSPECT_DATE")) {
                                    String finalField = field;
                                    ((JSONArray) v).forEach(item -> {
                                        boolMust.must(QueryBuilders.existsQuery(finalField));
                                        if (item.equals("overdue")) {
                                            // 超期：小于当前日期
                                            boolMust.must(QueryBuilders.rangeQuery(finalField).lt(LocalDate.now().format(formatter)));
                                        } else if (item.equals("near")) {
                                            // 临期：小于等于当前日期加上30天
                                            boolMust.must(QueryBuilders.rangeQuery(finalField).lte(LocalDate.now().plusDays(30).format(formatter)));
                                        } else {
                                            // 正常：大于当前日期加上30天
                                            boolMust.must(QueryBuilders.rangeQuery(finalField).gt(LocalDate.now().plusDays(30).format(formatter)));
                                        }
                                    });
                                } else if (k.equals("USC_DATE")) {
                                    String finalField = field;
                                    ((JSONArray) v).forEach(item -> {
                                        boolMust.must(QueryBuilders.existsQuery(finalField));
                                        if (item.equals("15")) {
                                            // 15年以上：大于当前日期减去15年
                                            boolMust.must(QueryBuilders.rangeQuery(finalField).gt(LocalDate.now().minusYears(15).format(formatter)));
                                        } else if (item.equals("10-15")) {
                                            // 10-15年：小于当前日期减去15年，大于等于当前日期减去10年
                                            boolMust.must(QueryBuilders.rangeQuery(finalField).lt(LocalDate.now().minusYears(15).format(formatter)));
                                            boolMust.must(QueryBuilders.rangeQuery(finalField).gte(LocalDate.now().minusYears(10).format(formatter)));
                                        } else if (item.equals("5-10")) {
                                            // 5-10年：小于当前日期减去10年，大于等于当前日期减去5年
                                            boolMust.must(QueryBuilders.rangeQuery(finalField).lt(LocalDate.now().minusYears(10).format(formatter)));
                                            boolMust.must(QueryBuilders.rangeQuery(finalField).gte(LocalDate.now().minusYears(5).format(formatter)));
                                        } else if (item.equals("0-5")) {
                                            // 0-5年：小于当前日期减去5年
                                            boolMust.must(QueryBuilders.rangeQuery(finalField).lt(LocalDate.now().minusYears(5).format(formatter)));
                                        }
                                    });
                                } 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 {


            }


            JSONArray equList = JSONObject.parseArray(JSONObject.toJSONString(filterParams.get(EQU_LIST)));
            if (!ObjectUtils.isEmpty(equList)) {

                if (equList.contains("8000")) {
                    // 压力管道长度
                    Map<String, Object> pipeLong = new HashMap<>();
                    pipeLong.put("name", "压力管道（千米）");
                    // todo 调用大屏总览接口获取压力管道长度
                    pipeLong.put("value", 1000000);
                }
                if (equList.contains("2000")) {
                    // 气瓶数量
                    Map<String, Object> gasTank = new HashMap<>();
                    gasTank.put("name", "气瓶（个）");
                    // todo 调用大屏总览接口获取气瓶数量
                    gasTank.put("value", 1000000);
                }
            }


        }

        // 排序
        if (!ObjectUtils.isEmpty(filter.get("sort"))) {
            JSONObject sort = JSONObject.parseObject(JSONObject.toJSONString(filter.get("sort")));
            builder.sort(sort.getString("field"), sort.getString("order").equals("desc") ? SortOrder.DESC : SortOrder.ASC);
        }

        builder.query(boolMust);
//        builder.sort("REC_DATE", SortOrder.DESC);
        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");
                dto.put("record", dto.get("SEQUENCE_NBR"));
                dto.put("equipAddress", dto.get("USE_PLACE") + "/" + dto.get("ADDRESS"));
                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;
    }

    /**
     * 开始下载 发送消息
     */
    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()));
    }
}