package com.njcn.process.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.csb.sdk.*;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.oss.utils.FileStorageUtil;
import com.njcn.process.mapper.SupvPlanMapper;
import com.njcn.process.mapper.SupvPlanRelMapper;
import com.njcn.process.mapper.SupvProblemMapper;
import com.njcn.process.mapper.SupvReportMMapper;
import com.njcn.process.pojo.param.SendParam;
import com.njcn.process.pojo.po.*;
import com.njcn.process.pojo.vo.gw.*;
import com.njcn.process.service.*;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.enums.DicDataTypeEnum;
import com.njcn.system.pojo.po.DictData;
import com.njcn.user.api.DeptFeignClient;
import com.njcn.user.api.UserFeignClient;
import com.njcn.user.pojo.po.Dept;
import com.njcn.user.pojo.po.User;
import com.njcn.user.pojo.vo.PvTerminalTreeVO;
import com.njcn.web.utils.GwSendUtil;
import com.njcn.web.utils.RestTemplateUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * pqs
 *
 * @author cdf
 * @date 2023/6/28
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class SupvPushGwServiceImpl implements SupvPushGwService {

    private final SupvPlanMapper supvPlanMapper;
    private final ISupvPlanService iSupvPlanService;

    private final SupvProblemMapper supvProblemMapper;

    private final ISupvFileService supvFileService;

    private final SupvReportMMapper supvReportMMapper;

    private final DicDataFeignClient dicDataFeignClient;

    private final DeptFeignClient deptFeignClient;

    private final FileStorageUtil fileStorageUtil;

    private final UserFeignClient userFeignClient;

    private final ISupvPlanHisService supvPlanHisService;
    private final ISupvAlarmService supvAlarmService;
    private final ISupvAlarmBackService supvAlarmBackService;
    private final SupvProblemServiceImpl supvProblemService;

    private final SupvPlanRelMapper supvPlanRelMapper;


    @Value("${gw.url}")
    private String gwUrl;

    @Value("${gw.code}")
    private String code;

    @Override
    public String pushPlan(List<String> planIds) {
        LambdaQueryWrapper<SupvPlan> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(SupvPlan::getPlanId, planIds);
        List<SupvPlan> supvPlanList = supvPlanMapper.selectList(lambdaQueryWrapper);
        if (CollUtil.isEmpty(supvPlanList)) {
            return "为查询数据,请查询数据是否存在!";
        }
        List<PvTerminalTreeVO> deptList = deptFeignClient.allDeptList().getData();
        Map<String, PvTerminalTreeVO> mapCode = deptList.stream().collect(Collectors.toMap(PvTerminalTreeVO::getCode, Function.identity()));
        Map<String, PvTerminalTreeVO> mapList = deptList.stream().collect(Collectors.toMap(PvTerminalTreeVO::getId, Function.identity()));

        List<DictData> supvDicList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.SUPV_TYPE.getCode()).getData();
        Map<String, DictData> mapType = supvDicList.stream().collect(Collectors.toMap(DictData::getId, Function.identity()));

        List<DictData> supvStateDicList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.SUPV_STAGE.getCode()).getData();
        Map<String, DictData> mapSupvState = supvStateDicList.stream().collect(Collectors.toMap(DictData::getId, Function.identity()));

        List<DictData> supveffectDicList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.EFFECT_STATUS.getCode()).getData();
        Map<String, DictData> mapSupvEffect = supveffectDicList.stream().collect(Collectors.toMap(DictData::getId, Function.identity()));

        List<DictData> supvObjTypeDicList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.SUPV_OBJ_TYPE.getCode()).getData();
        Map<String, DictData> mapSubvObjType = supvObjTypeDicList.stream().collect(Collectors.toMap(DictData::getId, Function.identity()));


        List<DictData> supvEvaluationReportList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.evaluation_report.getCode()).getData();
        Map<String, DictData> mapSupvEvaluationReport = supvEvaluationReportList.stream().collect(Collectors.toMap(DictData::getId, Function.identity()));

        List<DictData> supvUserClassList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.user_class.getCode()).getData();
        Map<String, DictData> mapSupvUserClass = supvUserClassList.stream().collect(Collectors.toMap(DictData::getId, Function.identity()));


        List<DictData> supvVoltageDicList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.DEV_VOLTAGE.getCode()).getData();
        Map<String, DictData> mapVoltage = supvVoltageDicList.stream().collect(Collectors.toMap(DictData::getId, Function.identity()));

        List<DictData> planList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.PLAN_STATUS.getCode()).getData();
        Map<String, DictData> mapPlan = planList.stream().collect(Collectors.toMap(DictData::getId, Function.identity()));

        List<String> userIds = supvPlanList.stream().map(SupvPlan::getPlanUserId).distinct().collect(Collectors.toList());
        List<User> userList = userFeignClient.getUserByIdList(userIds).getData();
        Map<String, User> map = userList.stream().collect(Collectors.toMap(User::getId, Function.identity()));


        for (SupvPlan supvPlan : supvPlanList) {
            checkParam(supvPlan);
            PvTerminalTreeVO pvTerminalTreeVO = null;
            if (mapCode.containsKey(supvPlan.getPlanOrgId())) {
                pvTerminalTreeVO = mapCode.get(supvPlan.getPlanOrgId());
                supvPlan.setSupvOrgName(pvTerminalTreeVO.getName());
                int deptLevel = pvTerminalTreeVO.getPids().split(StrUtil.COMMA).length;
                if (deptLevel == 2) {
                    //省
                    supvPlan.setProvinceName(pvTerminalTreeVO.getName());
                    supvPlan.setProvinceId(pvTerminalTreeVO.getCode());
                } else if (deptLevel == 3) {
                    //市
                    supvPlan.setCityName(pvTerminalTreeVO.getName());
                    supvPlan.setCityId(pvTerminalTreeVO.getCode());
                    if (mapList.containsKey(pvTerminalTreeVO.getPid())) {
                        PvTerminalTreeVO pvTerminalTreeOne = mapList.get(pvTerminalTreeVO.getPid());
                        supvPlan.setProvinceName(pvTerminalTreeOne.getName());
                        supvPlan.setProvinceId(pvTerminalTreeOne.getCode());
                    }
                } else if (deptLevel == 4) {
                    //县
                    if (mapList.containsKey(pvTerminalTreeVO.getPid())) {
                        supvPlan.setCountyName(pvTerminalTreeVO.getName());
                        supvPlan.setCountyId(pvTerminalTreeVO.getCode());
                        PvTerminalTreeVO pvTerminalTreeOne = mapList.get(pvTerminalTreeVO.getPid());
                        if (Objects.nonNull(pvTerminalTreeOne)) {
                            supvPlan.setCityName(pvTerminalTreeOne.getName());
                            supvPlan.setCityId(pvTerminalTreeOne.getCode());
                            if (mapList.containsKey(pvTerminalTreeOne.getPid())) {
                                PvTerminalTreeVO pvTerminalTreeTwo = mapList.get(pvTerminalTreeOne.getPid());
                                if (Objects.nonNull(pvTerminalTreeTwo)) {
                                    supvPlan.setProvinceName(pvTerminalTreeTwo.getName());
                                    supvPlan.setProvinceId(pvTerminalTreeTwo.getCode());
                                }
                            }
                        }
                    }
                }
            }

            //处理字典
            //监督类型编码
            if (mapType.containsKey(supvPlan.getSupvType())) {
                supvPlan.setSupvType(String.format("%02d", mapType.get(supvPlan.getSupvType()).getAlgoDescribe()));
            }


            if (supvPlan.getSupvType().equals("05")) {
                //电容器组需要上送对象
                List<SupvPlanRel> supvPlanRelList = supvPlanRelMapper.selectList(new LambdaQueryWrapper<SupvPlanRel>().eq(SupvPlanRel::getPlanId, supvPlan.getPlanId()));
                if (CollUtil.isNotEmpty(supvPlanRelList)) {
                    supvPlanRelList.forEach(SupvPlanRel::prepareForSerialization);
                    supvPlan.setPlanRel(supvPlanRelList);
                }
            }

            //监督类型编码
            if (mapSupvState.containsKey(supvPlan.getSupvStage())) {
                supvPlan.setSupvStage(String.format("%02d", mapSupvState.get(supvPlan.getSupvStage()).getAlgoDescribe()));
            }

            //监督阶段
            if (mapSupvEffect.containsKey(supvPlan.getEffectStatus())) {
                supvPlan.setEffectStatus(String.format("%02d", mapSupvEffect.get(supvPlan.getEffectStatus()).getAlgoDescribe()));
            }

            //监督对象类型
            if (StrUtil.isNotBlank(supvPlan.getSupvObjType())) {
                if (supvPlan.getSupvType().equals("01")) {

                } else if (supvPlan.getSupvType().equals("02")) {
                    supvPlan.setSupvObjType(mapSubvObjType.get(supvPlan.getSupvObjType()).getValue());
                } else if (supvPlan.getSupvType().equals("03")) {
                    supvPlan.setSupvObjType(mapSupvUserClass.get(supvPlan.getSupvObjType()).getValue());
                } else if (supvPlan.getSupvType().equals("04")) {

                } else if (supvPlan.getSupvType().equals("05")) {

                } else if (supvPlan.getSupvType().equals("06")) {
                    supvPlan.setSupvObjType(mapSupvEvaluationReport.get(supvPlan.getSupvObjType()).getValue());
                }
                if (mapSubvObjType.containsKey(supvPlan.getSupvObjType())) {
                    supvPlan.setSupvObjType(String.format("%02d", mapSubvObjType.get(supvPlan.getSupvObjType()).getAlgoDescribe()));
                }
            }


            //电站等级
            if (mapVoltage.containsKey(supvPlan.getSubstationVoltageLevel())) {
                supvPlan.setSubstationVoltageLevelName(mapVoltage.get(supvPlan.getSubstationVoltageLevel()).getName());
                supvPlan.setSubstationVoltageLevel(String.format("%02d", mapVoltage.get(supvPlan.getSubstationVoltageLevel()).getAlgoDescribe()));

            }

            if (mapVoltage.containsKey(supvPlan.getObjVoltageLevel())) {
                DictData dictData = mapVoltage.get(supvPlan.getObjVoltageLevel());
                supvPlan.setObjVoltageLevel(String.format("%02d", dictData.getAlgoDescribe()));
                supvPlan.setObjVoltageLevelName(dictData.getName());
            }

            //计划状态
            if (mapPlan.containsKey(supvPlan.getPlanStatus())) {
                DictData dictData = mapPlan.get(supvPlan.getPlanStatus());
                supvPlan.setPlanStatus(String.format("%02d", dictData.getAlgoDescribe()));
            }

            //判断用户是否存在
            if (map.containsKey(supvPlan.getPlanUserId())) {
                supvPlan.setPlanUserName(map.get(supvPlan.getPlanUserId()).getName());
            }
            //添加计划单位名称
            if (mapCode.containsKey(supvPlan.getPlanOrgId())) {
                pvTerminalTreeVO = mapCode.get(supvPlan.getPlanOrgId());
                supvPlan.setPlanOrgName(pvTerminalTreeVO.getName());
            }
        }
        if (supvPlanList.size() > 100) {
            throw new BusinessException("一次最多上送100条数据");
        }
        List<PlanVO> planVOS = BeanUtil.copyToList(supvPlanList, PlanVO.class);
        SendParam param = new SendParam();
        param.setStats(planVOS);
        param.setProvinceId(code);

        String s = JSONObject.toJSONStringWithDateFormat(param, JSON.DEFFAULT_DATE_FORMAT);
        log.info(Thread.currentThread().getName() + "获取返回体 接收电能质量技术监督工作计划数据接口数据：" + s + "结束----！");
        Map<String, String> send = send(param, getUrl(1), "pqPlanCreate");
        log.info(Thread.currentThread().getName() + "获取返回体 接收电能质量技术监督工作计划数据接口响应结果：" + send + "结束----！");
        if (send.containsKey("succeed")) {
            String succeed = send.get("succeed");
            if (succeed.indexOf("\\\"") != -1) {
                succeed = succeed.replace("\\\"", "\"");
            }
            Map mapData = JSON.parseObject(succeed, Map.class);
            String status = mapData.get("status").toString();
            if ("000000".equals(status)) {
                for (SupvPlan supvPlan : supvPlanList) {
                    supvPlanMapper.updateId(1, supvPlan.getPlanId());
                }
                String result = mapData.get("result").toString();
                Map mapCount = JSON.parseObject(result, Map.class);
                String count = mapCount.get("count").toString();
                return "操作成功:成功数据" + count + "条";
            } else {
                String errors = mapData.get("errors").toString();
                throw new BusinessException("操作失败:" + status + "_" + errors);
            }
        } else {
            throw new BusinessException("当前时间段国网上送请求过多，请稍后再试");
        }
    }

    @Override
    public String pushQuestion(List<String> problemIds, Integer type) {
        LambdaQueryWrapper<SupvProblem> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(SupvProblem::getProblemId, problemIds);
        List<SupvProblem> supvProblemList = supvProblemMapper.selectList(lambdaQueryWrapper);

        List<DictData> monitorTypeList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.MONITOR_TYPE.getCode()).getData();
        Map<String, DictData> mapMonitorType = monitorTypeList.stream().collect(Collectors.toMap(DictData::getId, Function.identity()));

        List<DictData> problemTypeList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.SUPV_PROBLEM_TYPE.getCode()).getData();
        Map<String, DictData> mapProblemType = problemTypeList.stream().collect(Collectors.toMap(DictData::getId, Function.identity()));

        List<DictData> reList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.RECTIFICATION_MEASURE.getCode()).getData();
        Map<String, DictData> mapRe = reList.stream().collect(Collectors.toMap(DictData::getId, Function.identity()));


        for (SupvProblem supvProblem : supvProblemList) {
            supvProblemService.checkParam(supvProblem.getPlanId(), DateUtil.formatLocalDateTime(supvProblem.getDiscoveryTime()));
            Dept dept = deptFeignClient.getDeptByCode(supvProblem.getDutyOrgId()).getData();
            supvProblem.setDutyOrgName(dept.getName());


            if (mapMonitorType.containsKey(supvProblem.getMonitorType())) {
                supvProblem.setMonitorType(String.format("%02d", mapMonitorType.get(supvProblem.getMonitorType()).getAlgoDescribe()));
            }
            if (mapProblemType.containsKey(supvProblem.getProblemType())) {
                supvProblem.setProblemType(String.format("%02d", mapProblemType.get(supvProblem.getProblemType()).getAlgoDescribe()));
            }
            if (mapRe.containsKey(supvProblem.getRectificationMeasure())) {
                supvProblem.setRectificationMeasure(String.format("%02d", mapRe.get(supvProblem.getRectificationMeasure()).getAlgoDescribe()));
            }
            supvProblem.setProvinceId(code);
        }

        if (supvProblemList.size() > 100) {
            throw new BusinessException("一次最多上送100条数据");
        }

        //TODO
        // 目前一个问题对应一个措施，上送一个问题需要调用问题接口和整改措施接口
        List<ProblemVO> list = BeanUtil.copyToList(supvProblemList, ProblemVO.class);

        SendParam param = new SendParam();
        param.setStats(list);
        param.setProvinceId(code);
        String s = JSONObject.toJSONStringWithDateFormat(param, JSON.DEFFAULT_DATE_FORMAT);
        log.info(Thread.currentThread().getName() + "获取返回体 删除电能质量技术监督工作计划接口数据：" + s + "结束----！");
        Map<String, String> send;
        if (type == 0) {
            send = send(param, getUrl(2), "pqProblemCreate");
            log.info(Thread.currentThread().getName() + "获取返回体 接收电能质量技术监督实施问题数据接口响应结果：" + send + "结束----！");
        } else {
            send = send(param, getUrl(3), "pqProblemUpdate");
            log.info(Thread.currentThread().getName() + "获取返回体 接收电能质量技术监督实施问题整改数据接口响应结果：" + send + "结束----！");
        }
        if (send.containsKey("succeed")) {
            String succeed = send.get("succeed");
            if (succeed.indexOf("\\\"") != -1) {
                succeed = succeed.replace("\\\"", "\"");
            }
            Map map = JSON.parseObject(succeed, Map.class);
            String status = map.get("status").toString();
            if ("000000".equals(status)) {
                for (SupvProblem supvProblem : supvProblemList) {
                    supvProblemMapper.updateId(1, supvProblem.getProblemId());
                }
                String result = map.get("result").toString();
                Map mapCount = JSON.parseObject(result, Map.class);
                String count = mapCount.get("count").toString();
                return "操作成功:成功数据" + count + "条";
            } else {
                String errors = map.get("errors").toString();
                throw new BusinessException("操作失败:" + status + "_" + errors);
            }
        } else {
            throw new BusinessException("当前时间段国网上送请求过多，请稍后再试");
        }

    }

    @Override
    public String pushFile(List<String> busIds) throws IOException {
        StringBuilder stringBuilder = new StringBuilder();
        LambdaQueryWrapper<SupvFile> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(SupvFile::getUuid, busIds);
        List<SupvFile> supvFiles = supvFileService.list(lambdaQueryWrapper);
        if (supvFiles.size() > 100) {
            throw new BusinessException("一次最多上送100条数据");
        }
        List<DictData> fileList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.file_type.getCode().trim()).getData();
        Map<String, DictData> mapFile = fileList.stream().collect(Collectors.toMap(DictData::getId, Function.identity()));
        DictData dictData;
        //TODO 调用上送接口
        for (int i = 0; i < supvFiles.size(); i++) {
            if (mapFile.containsKey(supvFiles.get(i).getAttachmentType())) {
                dictData = mapFile.get(supvFiles.get(i).getAttachmentType());
                supvFiles.get(i).setAttachmentType(dictData.getValue());
            } else {
                stringBuilder.append("第" + (i + 1) + "行文件上送失败: 请检查上送附件类型是否正确;</br>");
                continue;
            }
            log.info(Thread.currentThread().getName() + "获取返回体 推送附件接口：" + supvFiles.get(i) + "结束----！");
            Map<String, String> sendFile = sendFile(getUrl(4), supvFiles.get(i));
            log.info(Thread.currentThread().getName() + "获取返回体 总部提供附件接收接口,省公司调用此接口,完成附件上报响应结果：" + sendFile + "结束----！");
            if (sendFile.containsKey("succeed")) {
                supvFileService.update(new LambdaUpdateWrapper<SupvFile>()
                        .eq(SupvFile::getUuid, supvFiles.get(i).getUuid())
                        .set(SupvFile::getIsUploadHead, 1)
                );
                stringBuilder.append("第" + (i + 1) + "行文件上送成功:成功数据" + sendFile.get("succeed") + "条;</br>");
            } else {
                stringBuilder.append("第" + (i + 1) + "次行文件上送失败:" + sendFile.get("error") + ";</br>");
            }

        }
        return stringBuilder.toString();
    }

    @Override
    public String pushMonthReportStatistic(List<String> monthReportId) {
        LambdaQueryWrapper<SupvReportM> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(SupvReportM::getMonthReportId, monthReportId);
        List<SupvReportM> supvReportMList = supvReportMMapper.selectList(lambdaQueryWrapper);

        if (supvReportMList.size() > 100) {
            throw new BusinessException("一次最多上送100条数据");
        }
        //TODO 调用上送接口
        SendParam param = new SendParam();
        param.setStats(supvReportMList);
        param.setProvinceId(code);
        String s = JSONObject.toJSONStringWithDateFormat(param, JSON.DEFFAULT_DATE_FORMAT);
        log.info(Thread.currentThread().getName() + "获取返回体 取消电能质量技术监督工作计划接口数据：" + s + "结束----！");
        Map<String, String> send = send(param, getUrl(5), "pqMonthReportCreate");
        log.info(Thread.currentThread().getName() + "获取返回体 取消电能质量技术监督工作计划接口响应结果：" + send + "结束----！");
        if (send.containsKey("succeed")) {
            String succeed = send.get("succeed");
            if (succeed.indexOf("\\\"") != -1) {
                succeed = succeed.replace("\\\"", "\"");
            }
            Map map = JSON.parseObject(succeed, Map.class);
            String status = map.get("status").toString();
            if ("000000".equals(status)) {
                for (SupvReportM supvReportM : supvReportMList) {
                    supvReportMMapper.updateId(1, supvReportM.getMonthReportId());
                }
                String result = map.get("result").toString();
                Map mapCount = JSON.parseObject(result, Map.class);
                String count = mapCount.get("count").toString();
                return "操作成功:成功数据" + count + "条";
            } else {
                String errors = map.get("errors").toString();
                throw new BusinessException("操作失败:" + status + "_" + errors);
            }
        } else {
            throw new BusinessException("当前时间段国网上送请求过多，请稍后再试");
        }
    }

    @Override
    public String deletePlan(List<String> planIds) {
        //判断是否已经取消上送
        LambdaQueryWrapper<SupvPlan> supvPlanLambdaQueryWrapper = new LambdaQueryWrapper<>();
        supvPlanLambdaQueryWrapper.in(SupvPlan::getIsUploadHead, Stream.of(0, 2).collect(Collectors.toList())).in(SupvPlan::getPlanId, planIds);
        int count = supvPlanMapper.selectCount(supvPlanLambdaQueryWrapper);
        if (count > 0) {
            throw new BusinessException("请选择已上送计划");
        }
        iSupvPlanService.update(new LambdaUpdateWrapper<SupvPlan>()
                .set(SupvPlan::getDeleteFlag, 1)
                .set(SupvPlan::getDeleteTime, LocalDateTime.now())
                .in(SupvPlan::getPlanId, planIds)
        );
        return this.pushPlan(planIds);
    }

    @Override
    public String pushPlanHis(List<String> ids) {
        List<SupvPlanHis> supvPlanHis = supvPlanHisService.listByIds(ids);
        if (supvPlanHis.size() > 100) {
            throw new BusinessException("一次最多上送100条数据");
        }
        //计划状态
        List<DictData> planList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.PLAN_STATUS.getCode()).getData();
        Map<String, DictData> mapPlan = planList.stream().collect(Collectors.toMap(DictData::getId, Function.identity()));

        for (SupvPlanHis supvPlanHi : supvPlanHis) {
            //计划状态
            if (mapPlan.containsKey(supvPlanHi.getPlanStatus())) {
                DictData dictData = mapPlan.get(supvPlanHi.getPlanStatus());
                supvPlanHi.setPlanStatus(String.format("%02d", dictData.getAlgoDescribe()));
            }
        }
        List<PlanHisVO> list = BeanUtil.copyToList(supvPlanHis, PlanHisVO.class);
        SendParam param = new SendParam();
        param.setStats(list);
        param.setProvinceId(code);
        String s = JSONObject.toJSONStringWithDateFormat(param, JSON.DEFFAULT_DATE_FORMAT);
        log.info(Thread.currentThread().getName() + "获取返回体 预告警单数据接口：" + s + "结束----！");
        Map<String, String> send = send(param, getUrl(7), "pqPlanCreateHis");
        log.info(Thread.currentThread().getName() + "获取返回体 预告警单数据接口：" + send + "结束----！");
        if (send.containsKey("succeed")) {
            String succeed = send.get("succeed");
            if (succeed.indexOf("\\\"") != -1) {
                succeed = succeed.replace("\\\"", "\"");
            }
            Map map = JSON.parseObject(succeed, Map.class);
            String status = map.get("status").toString();
            if ("000000".equals(status)) {
                List<String> hisIds = supvPlanHis.stream().map(SupvPlanHis::getId).collect(Collectors.toList());

                supvPlanHisService.update(new LambdaUpdateWrapper<SupvPlanHis>()
                        .set(SupvPlanHis::getIsUploadHead, 1)
                        .in(SupvPlanHis::getId, hisIds)
                );

                String result = map.get("result").toString();
                Map mapCount = JSON.parseObject(result, Map.class);
                String countNum = mapCount.get("count").toString();
                return "操作成功:成功数据" + countNum + "条";
            } else {
                String errors = map.get("errors").toString();
                throw new BusinessException("操作失败:" + status + "_" + errors);
            }
        } else {
            throw new BusinessException("当前时间段国网上送请求过多，请稍后再试");
        }
    }

    @Override
    public String pushAlarm(List<String> ids) {
        List<SupvAlarm> supvAlarms = supvAlarmService.listByIds(ids);
        if (supvAlarms.size() > 100) {
            throw new BusinessException("一次最多上送100条数据");
        }
        //单据类型
        List<DictData> billList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.BILL_TYPE.getCode()).getData();
        Map<String, DictData> mapBill = billList.stream().collect(Collectors.toMap(DictData::getId, Function.identity()));

        //所属专业
        List<DictData> specialityList = dicDataFeignClient.getDicDataByTypeCode(DicDataTypeEnum.SPECIALITY_TYPE.getCode()).getData();
        Map<String, DictData> mapSpeciality = specialityList.stream().collect(Collectors.toMap(DictData::getId, Function.identity()));
        DictData dictData;

        List<AlarmVO> alarmVOList = new ArrayList<>();
        for (SupvAlarm supvAlarm : supvAlarms) {
            AlarmVO alarmVO = new AlarmVO();

            //单据类型
            if (mapBill.containsKey(supvAlarm.getBillType())) {
                dictData = mapBill.get(supvAlarm.getBillType());
                supvAlarm.setBillType(String.format("%02d", dictData.getAlgoDescribe()));
            }

            //所属专业
            if (mapSpeciality.containsKey(supvAlarm.getSpecialityType())) {
                dictData = mapSpeciality.get(supvAlarm.getSpecialityType());
                supvAlarm.setSpecialityType(String.format("%02d", dictData.getAlgoDescribe()));
            }

            BeanUtil.copyProperties(supvAlarm,alarmVO);
            alarmVO.setCreaterTime(supvAlarm.getCreaterTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());

            alarmVOList.add(alarmVO);
        }


        SendParam param = new SendParam();
        param.setStats(alarmVOList);
        param.setProvinceId(code);
        String s = JSONObject.toJSONStringWithDateFormat(param, JSON.DEFFAULT_DATE_FORMAT);
        //log.info(Thread.currentThread().getName() + "获取返回体 工作计划变更历史数据接口：" + s + "结束----！");
        Map<String, String> send = send(param, getUrl(8), "pqAlarmCreate");
        //log.info(Thread.currentThread().getName() + "获取返回体 工作计划变更历史数据接口：" + send + "结束----！");
        if (send.containsKey("succeed")) {
            String succeed = send.get("succeed");
            if (succeed.indexOf("\\\"") != -1) {
                succeed = succeed.replace("\\\"", "\"");
            }
            Map map = JSON.parseObject(succeed, Map.class);
            String status = map.get("status").toString();
            if ("000000".equals(status)) {
                List<String> hisIds = supvAlarms.stream().map(SupvAlarm::getAlarmId).collect(Collectors.toList());
                supvAlarmService.update(new LambdaUpdateWrapper<SupvAlarm>()
                        .set(SupvAlarm::getIsUploadHead, 1)
                        .in(SupvAlarm::getAlarmId, hisIds)
                );

                String result = map.get("result").toString();
                Map mapCount = JSON.parseObject(result, Map.class);
                String countNum = mapCount.get("count").toString();
                return "操作成功:成功数据" + countNum + "条";
            } else {
                String errors = map.get("errors").toString();
                throw new BusinessException("操作失败:" + status + "_" + errors);
            }
        } else {
            throw new BusinessException("当前时间段国网上送请求过多，请稍后再试");
        }
    }

    @Override
    public String pushAlarmHis(List<String> ids) {
        List<SupvAlarmBack> supvAlarmBacks = supvAlarmBackService.listByIds(ids);
        if (supvAlarmBacks.size() > 100) {
            throw new BusinessException("一次最多上送100条数据");
        }
        List<AlarmBackVO> list = BeanUtil.copyToList(supvAlarmBacks, AlarmBackVO.class);
        SendParam param = new SendParam();
        param.setStats(list);
        param.setProvinceId(code);
        String s = JSONObject.toJSONStringWithDateFormat(param, JSON.DEFFAULT_DATE_FORMAT);
        log.info(Thread.currentThread().getName() + "获取返回体 工作计划变更历史数据接口：" + s + "结束----！");
        Map<String, String> send = send(param, getUrl(9), "pqAlarmBackCreate");
        log.info(Thread.currentThread().getName() + "获取返回体 工作计划变更历史数据接口：" + send + "结束----！");
        if (send.containsKey("succeed")) {
            String succeed = send.get("succeed");
            if (succeed.indexOf("\\\"") != -1) {
                succeed = succeed.replace("\\\"", "\"");
            }
            Map map = JSON.parseObject(succeed, Map.class);
            String status = map.get("status").toString();
            if ("000000".equals(status)) {
                List<String> hisIds = supvAlarmBacks.stream().map(SupvAlarmBack::getAlarmBackId).collect(Collectors.toList());

                supvAlarmBackService.update(new LambdaUpdateWrapper<SupvAlarmBack>()
                        .set(SupvAlarmBack::getIsUploadHead, 1)
                        .in(SupvAlarmBack::getAlarmBackId, hisIds)
                );

                String result = map.get("result").toString();
                Map mapCount = JSON.parseObject(result, Map.class);
                String countNum = mapCount.get("count").toString();
                return "操作成功:成功数据" + countNum + "条";
            } else {
                String errors = map.get("errors").toString();
                throw new BusinessException("操作失败:" + status + "_" + errors);
            }
        } else {
            throw new BusinessException("当前时间段国网上送请求过多，请稍后再试");
        }

    }

    @Override
    public String reject(SendParam.Extend param) {
        try {
            String s = JSONObject.toJSONStringWithDateFormat(param, JSON.DEFFAULT_DATE_FORMAT);
            log.info(Thread.currentThread().getName() + "1.信息:" + s);
            ContentBody cb = new ContentBody(s);
            //如果需要传递请求参数 可以拼接到请求URL中，或者设置paramsMap参数由SDK内部进行拼接
            HttpParameters.Builder builder = HttpParameters.newBuilder();
            builder.requestURL(getUrl(10)) // 设置请求的URL,可以拼接URL请求参数
                    .api("zongbuSync") // 设置服务名
                    .version("1.0.0") // 设置版本号
                    .method("post") // 设置调用方式, 必须为 post
                    .contentType("application/json; charset=UTF-8") //设置请求content-type
                    .accessKey("7d4cb2c0afb5468ca56e0654b1a442ef").secretKey("lW2xr6zKjbaqVDOSgQpcGrM6Rg0=");// 设置accessKey 和 设置secretKey
            builder.contentBody(cb);
            String token = GwSendUtil.LoginToken();
            builder.putHeaderParamsMap("x-token", token);
            builder.putHeaderParamsMap("serviceName", "pqSupervisionReject");
            //进行调用，返回结果
            try {
                HttpReturn ret = HttpCaller.invokeReturn(builder.build());
                String responseStr = ret.getResponseStr();//获取响应的文本串
                log.info(Thread.currentThread().getName() + "返回信息:" + responseStr);
                if (responseStr.indexOf("\\\"") != -1) {
                    responseStr = responseStr.replace("\\\"", "\"");
                }
                Map map = JSON.parseObject(responseStr, Map.class);
                String status = map.get("code").toString();
                if ("0".equals(status)) {
                    String result = map.get("data").toString();
                    return "操作成功:成功数据" + result + "条";
                } else {
                    String errors = map.get("msg").toString();
                    throw new BusinessException("操作失败:" + status + "_" + errors);
                }
            } catch (HttpCallerException e) {
                log.info(Thread.currentThread().getName() + "错误信息:" + e);
            }
        } catch (Exception e) {
            throw new BusinessException("当前时间段国网上送请求过多，请稍后再试");
        }
        return "接收总部技术监督工作计划数据回退接口,推送失败！";
    }

    public Map<String, String> send(SendParam param, String url, String serviceName) {
        Map<String, String> map = new LinkedHashMap<>();
        try {
            ContentBody cb;
            if (ObjectUtil.isNull(param)) {
                cb = new ContentBody("");
            } else {
                String s = JSONObject.toJSONStringWithDateFormat(param, JSON.DEFFAULT_DATE_FORMAT);
                log.info(Thread.currentThread().getName() + "1.信息:" + s);
                cb = new ContentBody(s);
            }
            //ContentBody传递，要求使用post方式进行调用
            //如果需要传递请求参数 可以拼接到请求URL中，或者设置paramsMap参数由SDK内部进行拼接
            HttpParameters.Builder builder = HttpParameters.newBuilder();

            builder.requestURL(url) // 设置请求的URL,可以拼接URL请求参数
                    .api("zongbuSync") // 设置服务名
                    .version("1.0.0") // 设置版本号
                    .method("post") // 设置调用方式, 必须为 post
                    .contentType("application/json; charset=UTF-8") //设置请求content-type
                    .accessKey("7d4cb2c0afb5468ca56e0654b1a442ef").secretKey("lW2xr6zKjbaqVDOSgQpcGrM6Rg0=");// 设置accessKey 和 设置secretKey


            builder.contentBody(cb);
            String token = GwSendUtil.LoginToken();
            builder.putHeaderParamsMap("x-token", token);
            builder.putHeaderParamsMap("serviceName", serviceName);
            //进行调用，返回结果
            try {
                HttpReturn ret = HttpCaller.invokeReturn(builder.build());
                String responseStr = ret.getResponseStr();//获取响应的文本串
                map.put("succeed", responseStr);
            } catch (HttpCallerException e) {
                // error process
                log.info(Thread.currentThread().getName() + "错误信息:" + e);
                map.put("error", e.toString());
            }
        } catch (Exception e) {
            map.put("error", "当前时间段国网上送请求过多，请稍后再试");
        }
        return map;
    }


    /**
     * 附件推送
     *
     * @param url
     * @param supvFile
     * @return
     * @throws IOException
     */
    public Map<String, String> sendFile(String url, SupvFile supvFile) throws IOException {
        //获取文件服务器地址
        Map<String, String> maps = new HashMap<>();
        String path = supvFile.getFileUrl();
        if (StrUtil.isBlank(path)) {
            maps.put("error", "获取文件上传路径为空！请检查原始路径是否存在");
            return maps;
        }

        InputStream in = fileStorageUtil.getFileStream(path);
        if (ObjectUtil.isNull(in)) {
            maps.put("error", "文件服务器，文件不存在");
            return maps;
        }

        Map<String, String> otherParams = new HashMap<>();
        otherParams.put("provinceId", code);
        otherParams.put("secretKey", GwSendUtil.secretKey);
        otherParams.put("uuid", supvFile.getUuid());
        otherParams.put("attachmentName", supvFile.getAttachmentName());
        otherParams.put("attachmentType", supvFile.getAttachmentType());
        otherParams.put("busiId", supvFile.getBusiId());
        otherParams.put("uploaderName", supvFile.getUploaderName());
        String uploadTime = supvFile.getUploadTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        otherParams.put("uploadTime", uploadTime);
        otherParams.put("uploaderId", supvFile.getUploaderId());


        byte[] bytes = IOUtils.toByteArray(in);
        String s = Base64.encodeStr(bytes, false, false);

        int m = 1;
        String str = "";
        log.info("文件上报接口发送:{}", JSONObject.toJSONString(otherParams));
        for (int i = 0; i < s.length(); i += 1365000) {

            otherParams.put("fileCount", (int) Math.ceil(s.length() / (1365000 * 1.0)) + "");
            otherParams.put("fileCurrentNum", m + "");
            otherParams.put("fileByte", s.substring(i, Math.min(i + 1365000, s.length())));
            str = requestCommon("pqFileFromHyCreate", url, otherParams);
            m++;

        }
        if (StrUtil.isNotBlank(str)) {
            String[] split = str.split("_");
            if ("succeed".equals(split[0])) {
                maps.put("succeed", "1");
            } else {
                maps.put("error", split[1]);
            }
        } else {
            maps.put("error", "国网文件上传失败");
        }
        in.close();
        return maps;
    }


    /**
     * 文件上传请求
     *
     * @param serviceName
     * @param url
     * @param param
     * @return
     */
    public String requestCommon(String serviceName, String url, Map<String, String> param) {
        String str;
        HttpParameters.Builder builder = new HttpParameters.Builder();
        String token = GwSendUtil.LoginToken();

        builder.putHeaderParamsMap("x-token", token);
        builder.requestURL(url) // 设置请求的URL,可以拼接URL请求参数
                .api("zongbuSync") // 设置服务名
                .version("1.0.0") // 设置版本号
                .method("post") // 设置调用方式, 必须为 post
                .accessKey("7d4cb2c0afb5468ca56e0654b1a442ef")
                .secretKey("lW2xr6zKjbaqVDOSgQpcGrM6Rg0=") // 设置accessKey 和 设置secretKey
                .contentType("application/x-www-form-urlencoded;charset=utf-8") //设置请求content-type
                .putHeaderParamsMap("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
                .putHeaderParamsMap("serviceName", serviceName)
                .putHeaderParamsMap("secretKey", "lW2xr6zKjbaqVDOSgQpcGrM6Rg0=")
                .putParamsMapAll(param);
        try {
            HttpReturn ret = HttpCaller.invokeReturn(builder.build());
            String responseStr = ret.getResponseStr();//获取响应的文本串
            log.info(Thread.currentThread().getName() + "附件返回响应:" + responseStr);
            if (responseStr.indexOf("\\\"") != -1) {
                responseStr = responseStr.replace("\\\"", "\"");
            }
            Map map = JSON.parseObject(responseStr, Map.class);
            String status = map.get("status").toString();
            String errors = map.get("errors").toString();
            if ("000000".equals(status)) {
                str = "succeed_" + errors;
            } else {
                str = "error_" + errors;
            }
        } catch (HttpCallerException e) {
            // error process
            log.info(Thread.currentThread().getName() + "附件错误信息:" + e);
            str = "error_" + "国网附件服务器内部错误";
        }
        return str;
    }

    /**
     * 根据type获取上送地址
     *
     * @param type
     * @return
     */
    public String getUrl(Integer type) {
        String url = "http://" + gwUrl + "/CSB";

        switch (type) {
            case 1:
                /**
                 * 接收电能质量技术监督工作计划数据接口
                 */
                url += "/WMCenter/powerQuality/plan/create";
                break;
            case 2:
                /**
                 * 接收电能质量技术监督实施问题数据接口
                 */
                url += "/WMCenter/powerQuality/problem/create";
                break;
            case 3:
                /**
                 * 接收电能质量技术监督实施问题整改数据接口
                 */
                url += "/WMCenter/powerQuality/problem/update";
                break;
            case 4:
                /**
                 * 总部提供附件接收接口,省公司调用此接口,完成附件上报
                 */
                url += "/WMCenter/powerQuality/file/createFromHy";
                break;
            case 5:
                /**
                 * 接收电能质量技术监督月报统计数据接口
                 */
                url += "/WMCenter/powerQuality/monthReport/create";
                break;
            case 6:
                /**
                 * 删除电能质量技术监督工作计划接口
                 */
                url += "/WMCenter/powerQuality/plan/delete";
                break;
            case 7:
                /**
                 * 接收电能质量技术监督工作计划变更历史数据接口
                 */
                url += "/WMCenter/powerQuality/plan/createHis";
                break;
            case 8:
                /**
                 * 接收电能质量技术监督预告警单数据接口
                 */
                url += "/WMCenter/powerQuality/alarm/create";
                break;
            case 9:
                /**
                 * 接收电能质量技术监督预告警单反馈数据接口
                 */
                url += "/WMCenter/powerQuality/alarm/backCreate";
                break;
            case 10:
                /**
                 * 接收电能质量技术监督预告警单反馈数据接口
                 */
                url += "/WMCenter/powerQuality/supervision/reject";
                break;
        }
        return url;
    }

    private void checkParam(SupvPlan supvPlan) {
        //判断时间范围
        if (ObjectUtil.isAllNotEmpty(supvPlan.getEffectStartTime(), supvPlan.getEffectEndTime()) ||
                ObjectUtil.isAllNotEmpty(supvPlan.getEffectStartTime(), supvPlan.getReportIssueTime())
        ) {
            LocalDateTime problemOcTime1 = supvPlan.getProblemOcTime();
            if (ObjectUtil.isNotNull(problemOcTime1)) {
                //实施开始时间
                DateTime effectStartTime = DateUtil.parse(DateUtil.formatLocalDateTime(supvPlan.getEffectStartTime()), "yyyy-MM-dd HH:mm:ss");
                //问题发现时间
                DateTime problemOcTime = DateUtil.parse(DateUtil.formatLocalDateTime(problemOcTime1), "yyyy-MM-dd HH:mm:ss");
                Boolean fly = false;
                if (ObjectUtil.isNotNull(supvPlan.getEffectEndTime())) {
                    //实施结束时间
                    DateTime effectEndTime = DateUtil.parse(DateUtil.formatLocalDateTime(supvPlan.getEffectEndTime()), "yyyy-MM-dd HH:mm:ss");
                    if (DateUtil.isIn(problemOcTime, effectStartTime, effectEndTime)) {
                        fly = true;
                    }
                }
                if (ObjectUtil.isNotNull(supvPlan.getReportIssueTime())) {
                    //报告出具时间
                    DateTime reportIssueTime = DateUtil.parse(DateUtil.formatLocalDateTime(supvPlan.getReportIssueTime()), "yyyy-MM-dd HH:mm:ss");
                    if (DateUtil.isIn(problemOcTime, effectStartTime, reportIssueTime)) {
                        fly = true;
                    }
                }
                if (!fly) {
                    throw new BusinessException("问题发现时时间，不在实施开始时间到（实施结束时间/报告出具时间）范围内");

                }
            }
        }
    }
}
