package com.yeejoin.amos.fas.business.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yeejoin.amos.component.rule.config.ClazzUtils;
import com.yeejoin.amos.fas.business.action.CustomerAction;
import com.yeejoin.amos.fas.business.dao.mapper.*;
import com.yeejoin.amos.fas.business.dao.repository.*;
import com.yeejoin.amos.fas.business.param.AlarmParam;
import com.yeejoin.amos.fas.business.service.intfc.*;
import com.yeejoin.amos.fas.business.util.TreeUtil;
import com.yeejoin.amos.fas.business.vo.*;
import com.yeejoin.amos.fas.common.enums.ContingencyPlanStatusEnum;
import com.yeejoin.amos.fas.common.enums.EquipmentRiskTypeEnum;
import com.yeejoin.amos.fas.common.enums.ExecutionTypeEnum;
import com.yeejoin.amos.fas.common.enums.PlanRecordStatusEnum;
import com.yeejoin.amos.fas.core.enums.NumberEnum;
import com.yeejoin.amos.fas.core.enums.ReserveEnum;
import com.yeejoin.amos.fas.core.util.DateUtil;
import com.yeejoin.amos.fas.dao.entity.*;
import com.yeejoin.amos.fas.exception.YeeException;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.typroject.tyboot.component.emq.EmqKeeper;
import org.typroject.tyboot.core.foundation.utils.Bean;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;

import java.util.*;

/**
 * @program: YeeAmosFireAutoSysRoot
 * @description: 预案实现类
 * @author: wujunkai
 * @create: 2021-01-14 14:59
 */
@Service
public class ContingencyPlanServiceImpl implements IContingencyPlanService {

    private final Logger logger = LogManager.getLogger(ContingencyPlanServiceImpl.class);

    @Autowired
    private IEquipmentService equipmentService;
    @Autowired
    private IRiskSourceService riskSourceService;
    @Autowired
    private IPlanOperationRecordDao planOperationRecordDao;
    @Autowired
    private IEquipmentFireEquipmentDao equipmentFireEquipmentDao;
    @Qualifier("iEquipmentDao")
    @Autowired
    private IEquipmentDao equipmentDao;
    @Autowired
    private EquipmentSpecificMapper equipmentSpecificMapper;
    @Autowired
    private IEquipmentHandlerService equipmentHandlerService;
    @Autowired
    private IContingencyPlanInstanceRepository repository;
    @Qualifier("contingencyAction")
    @Autowired
    private CustomerAction customerAction;
//    @Value("${now.gateway.address}")
//    private String gateWayAddress;
//    @Value("${number.plan.projectName}")
//    private String projectName;
    private final PlanOperationRecordMapper planOperationRecordMapper;
    private final IPlanDetailDao planDetailDao;
    private final IPlanDocDao planDocDao;
    private final IPlanEquipmentDao planEquipmentDao;
    private final IPlanRuleDao planRuleDao;
    private final IPlanClassifyTreeDao classifyTreeDao;
    private final PlanDetailMapper planDetailMapper;
    private final PlanEquipmentMapper planEquipmentMapper;
    private final PlanRuleMapper planRuleMapper;
    private final PlanDocMapper planDocMapper;
    private final EmqKeeper emqKeeper;
    private final IPlanClassifyTreeService planClassifyTreeService;
    @Autowired
    IContingencyInstance iContingencyInstance;
    @Autowired
    public ContingencyPlanServiceImpl(IPlanDetailDao planDetailDao, IPlanDocDao planDocDao, IPlanEquipmentDao planEquipmentDao,
                                      IPlanRuleDao planRuleDao, IPlanClassifyTreeDao classifyTreeDao, PlanDetailMapper planDetailMapper,
                                      PlanEquipmentMapper planEquipmentMapper, PlanRuleMapper planRuleMapper, PlanDocMapper planDocMapper,
                                      PlanOperationRecordMapper planOperationRecordMapper, IPlanClassifyTreeService planClassifyTreeService,
                                      EmqKeeper emqKeeper) {
        this.planDetailDao = planDetailDao;
        this.planDocDao = planDocDao;
        this.planEquipmentDao = planEquipmentDao;
        this.planRuleDao = planRuleDao;
        this.classifyTreeDao = classifyTreeDao;
        this.planDetailMapper = planDetailMapper;
        this.planEquipmentMapper = planEquipmentMapper;
        this.planRuleMapper = planRuleMapper;
        this.planDocMapper = planDocMapper;
        this.planOperationRecordMapper = planOperationRecordMapper;
        this.planClassifyTreeService = planClassifyTreeService;
        this.emqKeeper = emqKeeper;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ContingencyPlanResponseVo planStart(ContingencyPlanParamVo vo, Toke toke) throws Exception {
        ContingencyPlanResponseVo result = new ContingencyPlanResponseVo();
        //状态校验
        ReserveEnum reserveEnum = this.runCheck(vo);
        result.setMessage(reserveEnum.getText());
        if (ReserveEnum.THISRUNNING.getStatus().equals(reserveEnum.getStatus())) {
            List<PlanOperationRecord> recordList = planOperationRecordDao.findByPlanId1(Long.valueOf(vo.getPlanId()));
            result.setMessage(ReserveEnum.THISRUNNING.getText());
            result.setBatchNo(recordList.get(0).getBatchNo());
            return result;
        } else if (ReserveEnum.RUN.getStatus().equals(reserveEnum.getStatus())) {
            Optional<PlanDetail> PlanDetailOp = planDetailDao.findById(Long.valueOf(vo.getPlanId()));
            List<PlanEquipment> equipmentList = planEquipmentDao.findByPlanId(PlanDetailOp.get().getId());
            //预案启动
            if (PlanDetailOp.get() != null) {
                //获取规则名称
                List<PlanRule> planRuleList = planRuleDao.getPlanDocsByPlanId(Long.valueOf(vo.getPlanId()));
                if (planRuleList.size() == 0) {
                    result.setMessage(ReserveEnum.NOPLAN.getText());
                    return result;
                }
                //电力设备
                Equipment equipment = equipmentService.queryOne(equipmentList.get(0).getFireEquipmentId());
                if (equipment == null) {
                    result.setMessage(ReserveEnum.NOEQUIP.getText());
                    return result;
                }
                equipment.setReservePlan("换流站消防专项预案" + "/" + planRuleList.get(0).getRuleId());

                //电力设备绑定装备
                List<EquipmentFireEquipment> equipmentFireEquipmentList = equipmentFireEquipmentDao.findAllByEquipmentId(equipmentList.get(0).getFireEquipmentId());
                if (equipmentFireEquipmentList.size() == 0) {
                    result.setMessage("该预案保护的电力设备尚未绑定配套的火灾报警设备");
                    return result;
                }
                //查询设备
                EquipmentSpecificForRiskVo equipmentSpecific = equipmentSpecificMapper.getOneById(equipmentFireEquipmentList.get(0).getFireEquipmentId());
                if (equipmentSpecific == null) {
                    result.setMessage("该预案保护的电力设备尚未绑定配套的火灾报警设备");
                    return result;
                }

                //插入运行记录表
                PlanOperationRecord planOperationRecord = new PlanOperationRecord();
                planOperationRecord.setStatus(PlanRecordStatusEnum.OPERATION.getCode());
                planOperationRecord.setPlanId(PlanDetailOp.get().getId());
                planOperationRecord.setIsDelete(false);
                planOperationRecord.setStartTime(new Date());
                planOperationRecord.setPlanPattern(vo.getStatus());
                planOperationRecord.setStartUserId(vo.getUserId());
                planOperationRecord.setStartUserName(vo.getUserName());
                planOperationRecord.setEquipmentCode(equipmentSpecific.getCode());
                planOperationRecord.setEquipmentName(equipmentSpecific.getName());
                planOperationRecord.setEquipmentId(equipmentSpecific.getId());
                planOperationRecord.setFireEquipmentId(equipment.getId());
                if (ContingencyPlanStatusEnum.SIMULATION_START.getCode().equals(vo.getStatus())) {
                    planOperationRecord.setExecutionType(ExecutionTypeEnum.PLANCHECK.getCode());
                } else {
                    planOperationRecord.setExecutionType(ExecutionTypeEnum.FIREMANAGEMENT.getCode());
                }
                PlanOperationRecord operationRecord = planOperationRecordDao.save(planOperationRecord);
                //预案启动
                AlarmParam deviceData = new AlarmParam();
                deviceData.setMonitor(equipment != null ? equipment.getName() : "");
                deviceData.setId(String.valueOf(equipmentSpecific.getId()));
                deviceData.setCode(equipmentSpecific.getCode());
                String batchNo = equipmentHandlerService.executeDynamicPlan(deviceData, equipment, equipmentSpecific, toke, operationRecord.getId());
                //更新模型状态
                PlanDetail planDetail = PlanDetailOp.get();
                planDetail.setStatus(vo.getStatus());
                planDetailDao.save(planDetail);
                //更新预案执行记录表的批次号
                operationRecord.setBatchNo(batchNo);
                planOperationRecordDao.save(operationRecord);
                result.setMessage(ReserveEnum.RUN.getText());
                result.setBatchNo(batchNo);
            }
        }
        return result;
    }

    @Override
    public Map<String, Object> firstGetRecord(String batchNo) {
        Map<String, Object> map = new HashMap<>();
        PlanOperationRecord planOperationRecord = planOperationRecordDao.findByBatchNo(batchNo);
        if (planOperationRecord == null) {
            throw new YeeException("执行记录不存在");
        } else {
            PlanDetail planDetail = planDetailDao.getOne(planOperationRecord.getPlanId());
            if (planDetail == null) {
                throw new YeeException("数字预案模型被删除");
            }
            map.put("status", planOperationRecord.getStatus());
            if (PlanRecordStatusEnum.OPERATION == PlanRecordStatusEnum.getEnum(planOperationRecord.getStatus())) {
                map.put("executionTime", (System.currentTimeMillis() - planOperationRecord.getStartTime().getTime()) / 1000);
            } else {
                map.put("executionTime", (planOperationRecord.getEndTime().getTime() - planOperationRecord.getStartTime().getTime()) / 1000);
            }
            map.put("crateDate", planOperationRecord.getStartTime());
            if (ContingencyPlanStatusEnum.getEnum(planOperationRecord.getPlanPattern()) == ContingencyPlanStatusEnum.SIMULATION_START) {
                map.put("userName", planOperationRecord.getStartUserName());
                map.put("startType", "手动");
            } else {
                map.put("userName", "系统");
                map.put("startType", "自动");
            }
            map.put("executionType", planOperationRecord.getExecutionType());
            map.put("equipmentName", planOperationRecord.getEquipmentName());
            map.put("PlanName", planDetail.getPlanName());
        }
        return map;
    }

    @Override
    public List<HashMap<String, Object>> getRecordList(String batchNo) {
        List<HashMap<String, Object>> list = new ArrayList<>();
        List<ContingencyPlanInstance> instancesList = repository.queryForCategory(batchNo, "MESSAGE");
        instancesList.forEach(contingencyPlanInstance -> {
            HashMap<String, Object> map = new HashMap<>();
            map.put("crateDate", contingencyPlanInstance.getCreateDate());
            map.put("content", contingencyPlanInstance.getContent());
            list.add(map);
        });
        return list;
    }


    //启动状态校验
    public ReserveEnum runCheck(ContingencyPlanParamVo vo) throws Exception {
        if (EquipmentRiskTypeEnum.HZGJ.getCode().equals(vo.getRiskType()) || StringUtils.isBlank(vo.getRiskType())) {

            List<PlanDoc>  planDocs =  planDocDao.findAllByPlanId(Long.valueOf(vo.getPlanId()));
            if(planDocs.size()==0){
                return ReserveEnum.PLAN_DOC_IS_DELETE;
            }
            //判断预案文档是否删除
            List<PlanRule>  planRules =  planRuleDao.findAllByPlanId(Long.valueOf(vo.getPlanId()));
            if(planRules.size()==0){
                return ReserveEnum.PLAN_RULE_IS_DELETE;
            }
            //判断预案装备是否删除
            List<PlanEquipment>  planEquipments =  planEquipmentDao.findByPlanId(Long.valueOf(vo.getPlanId()));
            if(planEquipments.isEmpty()){
                return ReserveEnum.PLAN_EQUIP_IS_DELETE;
            }
            List<PlanOperationRecord> recordList = planOperationRecordDao.findByPlanId1(Long.valueOf(vo.getPlanId()));
            if (recordList.size() > 0 && !vo.getStatus().equals(ContingencyPlanStatusEnum.ONGOING.getCode())) {
                return ReserveEnum.THISRUNNING;
            }
            if (ContingencyPlanStatusEnum.SIMULATION_START.getCode().equals(vo.getStatus())) {
                Integer[] statusArray = (Integer[]) Arrays.asList(ContingencyPlanStatusEnum.SIMULATION_START.getCode(), ContingencyPlanStatusEnum.ONGOING.getCode()).toArray();
                List<PlanDetail> count = planDetailDao.findByStatus(statusArray);
                if (count.size() > NumberEnum.ZERO.getValue()) {
                    return ReserveEnum.RUNNING;
                }

            } else if (ContingencyPlanStatusEnum.ONGOING.getCode().equals(vo.getStatus())) {
                //自动启动
                List<PlanDetail>  countZd = planDetailDao.findByStatus((Integer[]) Arrays.asList(ContingencyPlanStatusEnum.ONGOING.getCode()).toArray());
                if (countZd.size() > NumberEnum.ZERO.getValue()) {
                    return ReserveEnum.RUNNING;
                }
                List<PlanDetail> countMn = planDetailDao.findByStatus((Integer[]) Arrays.asList(ContingencyPlanStatusEnum.SIMULATION_START.getCode()).toArray());
                if (countMn.size() > NumberEnum.ZERO.getValue()) {
                    List<PlanOperationRecord>   planOperationRecordList =   planOperationRecordDao.findByPlanId1(countMn.get(0).getId());
                    if(planOperationRecordList.size()>0){
                        Optional<Equipment> equipment = iContingencyInstance.fire(planOperationRecordList.get(0).getBatchNo(),"0","","FIRE_CANCEL","CONFIRM","B");
                        //  结束预案，更新设备重点设备参数
                        equipment.ifPresent(equip -> {
                            equip.setStartTime(DateUtil.getDateNow());
                            equip.setEndTime(null);
                            equip.setReserveSource(NumberEnum.ONE.getValue());
                            equip.setStatus(NumberEnum.ONE.getValue());
                            equipmentService.save(equip);
                        });
                        customerAction.intreeuptPlan(planOperationRecordList.get(0).getBatchNo());
                    }
                }

            } else {
                return ReserveEnum.PLANSTATUSERROR;
            }
        } else {

        }
        return ReserveEnum.RUN;
    }

    @Override
    public ContingencyPlanParamVo equipmentScene(Long equipmentId, String riskType) {
        ContingencyPlanParamVo vo = null;
        if (EquipmentRiskTypeEnum.HZGJ.getCode().equals(riskType)) {
            List<EquipmentFireEquipment> equipmentFireEquipmentList = equipmentFireEquipmentDao.findAllByFireEquipmentId(equipmentId);
            if (!equipmentFireEquipmentList.isEmpty()) {
                List<Long> ids = new ArrayList<>();
                equipmentFireEquipmentList.forEach(e -> ids.add(e.getEquipmentId()));
                List<PlanEquipment> all = planEquipmentDao.findAllByFireEquipmentIdIn(ids);
                PlanEquipment planEquipment = all.isEmpty() ? null : all.get(0);
                if (planEquipment != null) {
                    vo = new ContingencyPlanParamVo();
                    vo.setPlanId(planEquipment.getPlanId().toString());
                    vo.setStatus(ContingencyPlanStatusEnum.ONGOING.getCode());
                    vo.setRiskType(riskType);
                    return vo;
                }
            }
        }
        return vo;
    }

    @Override
    public Page recordListByPage(Page page, Long planId, String planName, List<Long> classifyId, Date
            startTimeLeft, Date startTimeRight, Integer executionType, Integer planPattern) {
        Map<String, Object> params = new HashMap<>();
        params.put("planName", planName);
        params.put("planId", planId);
        params.put("start", (int) ((page.getCurrent() - 1) * page.getSize()));
        params.put("size", (int) page.getSize());
        params.put("classifyId", classifyId);
        params.put("startTimeLeft", startTimeLeft);
        params.put("startTimeRight", startTimeRight);
        params.put("executionType", executionType);
        params.put("planPattern", planPattern);

        int total = planOperationRecordMapper.filterCount(params);
        page.setTotal(total);
        long start = (page.getCurrent() - 1) * page.getSize();
        if (total == 0) {
            page.setCurrent(1);
        } else {
            if (total < start) {
                page.setCurrent(1);
                params.put("start", 0);
            }
            List<Map<String, Object>> planList = planOperationRecordMapper.filterList(params);
            page.setRecords(planList);
        }
        return page;
    }

    @Override
    public PlanDetailVo createPlan(PlanDetailVo planDetail) {
        PlanDoc planDoc = planDetail.getPlanDoc();
        PlanRule planRule = planDetail.getPlanRule();
        List<PlanEquipment> planEquipment = planDetail.getPlanEquipment();
        if (StringUtils.isBlank(planDetail.getPlanName()) || null == planDetail.getClassifyId()
                || null == planDoc || null == planDoc.getDocId()
                || null == planRule || null == planRule.getRuleId()
                || null == planEquipment || planEquipment.isEmpty()) {
            throw new YeeException("参数错误");
        }
        planEquipment.forEach(equipment -> {
            if (null == equipment || null == equipment.getFireEquipmentId()) {
                throw new YeeException("参数错误");
            }
        });
        // 状态为草稿
        planDetail.setStatus(ContingencyPlanStatusEnum.DRAFT.getCode());
        planDetail.setIsDelete(false);
        PlanDetail planEntity = new PlanDetail();
        BeanUtils.copyProperties(planDetail, planEntity);
        long planId = planDetailDao.save(planEntity).getId();
        planDetail.setId(planId);
        planDoc.setPlanId(planId);
        planDoc.setIsDelete(false);
        planDocDao.save(planDoc);
        planRule.setPlanId(planId);
        planRule.setIsDelete(false);
        planRuleDao.save(planRule);
        planEquipment.forEach(equipment -> {
            equipment.setPlanId(planId);
            equipment.setIsDelete(false);
        });
        planEquipmentDao.saveAll(planEquipment);
        return planDetail;
    }

    @Override
    public PlanDetailVo editPlan(PlanDetailVo planDetail) {
        PlanDoc planDoc = planDetail.getPlanDoc();
        PlanRule planRule = planDetail.getPlanRule();
        List<PlanEquipment> planEquipment = planDetail.getPlanEquipment();
        if (StringUtils.isBlank(planDetail.getPlanName()) || null == planDetail.getClassifyId()
                || null == planDoc || null == planDoc.getDocId()
                || null == planRule || null == planRule.getRuleId()
                || null == planEquipment || planEquipment.isEmpty()) {
            throw new YeeException("参数错误");
        }
        planEquipment.forEach(equipment -> {
            if (null == equipment || null == equipment.getFireEquipmentId()) {
                throw new YeeException("参数错误");
            }
        });
        long planId = planDetail.getId();
        PlanDetail oldPlan = planDetailDao.findById(planId).orElse(null);
        if (null == oldPlan) {
            throw new YeeException("数据不存在");
        }
        if (ContingencyPlanStatusEnum.getEnum(oldPlan.getStatus()) == ContingencyPlanStatusEnum.DRAFT
                || ContingencyPlanStatusEnum.getEnum(oldPlan.getStatus()) == ContingencyPlanStatusEnum.NOAVAILABLE) {
            // 状态设置为草稿
            planDetail.setStatus(ContingencyPlanStatusEnum.DRAFT.getCode());
        } else {
            throw new YeeException("不可编辑的状态");
        }
        if (planDetail.getIsDelete() == null) {
            planDetail.setIsDelete(false);
        }
        PlanDetail planEntity = new PlanDetail();
        BeanUtils.copyProperties(planDetail, planEntity);
        planEntity.setOrgCode(oldPlan.getOrgCode());
        planEntity.setCreator(oldPlan.getCreator());
        planDetailDao.saveAndFlush(planEntity);

        planDoc.setPlanId(planId);
        planDoc.setIsDelete(false);
        planDocDao.deleteByPlanId(planId);
        planDocDao.save(planDoc);

        planRule.setPlanId(planId);
        planRule.setIsDelete(false);
        planRuleDao.deleteByPlanId(planId);
        planRuleDao.save(planRule);

        planEquipment.forEach(equipment -> {
            equipment.setPlanId(planId);
            equipment.setIsDelete(false);
        });
        planEquipmentDao.deleteByPlanId(planId);
        planEquipmentDao.saveAll(planEquipment);
        return planDetail;
    }

    @Override
    public PlanDetailVo detail(Long id) {
        PlanDetail detail = planDetailDao.findById(id).orElse(null);
        if (null == detail) {
            throw new YeeException("数据不存在");
        }
        PlanDetailVo detailVo = new PlanDetailVo();
        BeanUtils.copyProperties(detail, detailVo);
        List<PlanDoc> docs = planDocDao.getPlanDocsByPlanId(id);
        if (!docs.isEmpty()) {
            detailVo.setPlanDoc(docs.get(0));
        }
        List<PlanRule> rules = planRuleDao.getPlanDocsByPlanId(id);
        if (!rules.isEmpty()) {
            detailVo.setPlanRule(rules.get(0));
        }
        List<PlanEquipment> equipments = planEquipmentDao.getPlanDocsByPlanId(id);
        detailVo.setPlanEquipment(equipments);
        // 设置执行次数
        detailVo.setExecutionTimes(planOperationRecordDao.countByPlanId(id));
        PlanClassifyTree classifyTree = classifyTreeDao.findById(detailVo.getClassifyId()).orElse(null);
        if (null != classifyTree) {
            detailVo.setClassifyName(classifyTree.getClassifyName());
        }
        return detailVo;
    }

    @Override
    public List<PlanDetail> activatePlan(List<Long> idList) {
        List<PlanDetail> planDetailList = planDetailDao.getPlanDetailsByIdInAndIsDelete(idList, false);
        if (!planDetailList.isEmpty()) {
            planDetailList.forEach(plan -> {
                ContingencyPlanStatusEnum status = ContingencyPlanStatusEnum.getEnum(plan.getStatus());
                if (status != ContingencyPlanStatusEnum.DRAFT
                        && status != ContingencyPlanStatusEnum.AVAILABLE
                        && status != ContingencyPlanStatusEnum.NOAVAILABLE) {
                    throw new YeeException("包含不可启用的状态");
                }
                plan.setStatus(ContingencyPlanStatusEnum.AVAILABLE.getCode());
            });
            planDetailMapper.updatePlanStatusByIdList(idList, ContingencyPlanStatusEnum.AVAILABLE.getCode());
        }
        return planDetailList;
    }

    @Override
    public List<PlanDetail> deactivatePlan(List<Long> idList) {
        List<PlanDetail> planDetailList = planDetailDao.getPlanDetailsByIdInAndIsDelete(idList, false);
        if (!planDetailList.isEmpty()) {
            planDetailList.forEach(plan -> {
                if (ContingencyPlanStatusEnum.getEnum(plan.getStatus()) != ContingencyPlanStatusEnum.AVAILABLE
                        && ContingencyPlanStatusEnum.getEnum(plan.getStatus()) != ContingencyPlanStatusEnum.NOAVAILABLE) {
                    throw new YeeException("包含不可禁用的状态");
                }
                plan.setStatus(ContingencyPlanStatusEnum.NOAVAILABLE.getCode());
            });
            planDetailMapper.updatePlanStatusByIdList(idList, ContingencyPlanStatusEnum.NOAVAILABLE.getCode());
        }
        return planDetailList;
    }

    @Override
    public Boolean delete(List<Long> idList) {
        planDetailMapper.updateIsDeleteByIdList(idList, true);
        planDocMapper.updateIsDeleteByPlanIdList(idList, true);
        planEquipmentMapper.updateIsDeleteByPlanIdList(idList, true);
        planRuleMapper.updateIsDeleteByPlanIdList(idList, true);
        return true;
    }

    @Override
    public Page<PlanDetailVo> pageFilter(Page page, String planName, Long
            classifyId, List<String> planRange, String editOrgName, Date implementationTimeLeft, Date
                                                 implementationTimeRight) {
        List<Long> classifyIdList = new ArrayList<>();
        if (classifyId != null) {
            Collection<PlanClassifyTreeVo> classifyTreeList = planClassifyTreeService.getAllChildIncludeMe(classifyId);
            if (!classifyTreeList.isEmpty()) {
                List<PlanClassifyTreeVo> allChildren = TreeUtil.getAllChildren(classifyTreeList);
                allChildren.forEach(e -> classifyIdList.add(e.getId()));
            }
        }
        int total = planDetailMapper.filterCount(planName, classifyIdList, planRange, editOrgName, implementationTimeLeft, implementationTimeRight);
        page.setTotal(total);
        long start = (page.getCurrent() - 1) * page.getSize();
        if (total == 0) {
            page.setCurrent(1);
        } else {
            if (total < start) {
                page.setCurrent(1);
                start = 0;
            }
            List<PlanDetailVo> planList = planDetailMapper.filterList(planName, classifyIdList, planRange, editOrgName, implementationTimeLeft, implementationTimeRight, (int) start, (int) page.getSize());
            // 查询并插入绑定数据的信息
            fillBindingInfo(planList);
            page.setRecords(planList);
        }
        return page;
    }

    private void fillBindingInfo(List<PlanDetailVo> planList) {
        if (ValidationUtil.isEmpty(planList)) {
            return;
        }
//        planList.forEach(x->{
//            String picture = x.getPicture();
//            if (StringUtils.isNotEmpty(picture)) {
//                x.setPicture(gateWayAddress+picture);
//            }
//
//        });
        List<Long> idList = new ArrayList<>();
        planList.forEach(e -> idList.add(e.getId()));
        Map<Object, List<PlanDoc>> docMapList = null;
        Map<Object, List<PlanRule>> ruleMapList = null;
        Map<Object, List<PlanEquipment>> equipMapList = null;
        List<PlanDoc> docs = planDocDao.findAllByPlanIdIn(idList);
        if (!docs.isEmpty()) {
            docMapList = Bean.list2MapList(docs, "planId");
        }
        List<PlanRule> rules = planRuleDao.findAllByPlanIdIn(idList);
        if (!rules.isEmpty()) {
            ruleMapList = Bean.list2MapList(rules, "planId");
        }
        List<PlanEquipment> equips = planEquipmentDao.findAllByPlanIdIn(idList);
        if (!equips.isEmpty()) {
            equipMapList = Bean.list2MapList(equips, "planId");
        }
        Map<Object, List<PlanDoc>> finalDocMapList = docMapList;
        Map<Object, List<PlanRule>> finalRuleMapList = ruleMapList;
        Map<Object, List<PlanEquipment>> finalEquipMapList = equipMapList;
        planList.forEach(plan -> {
            if (finalDocMapList != null && finalDocMapList.get(plan.getId()) != null) {
                plan.setPlanDoc(finalDocMapList.get(plan.getId()).get(0));
            }
            if (finalRuleMapList != null && finalRuleMapList.get(plan.getId()) != null) {
                plan.setPlanRule(finalRuleMapList.get(plan.getId()).get(0));
            }
            if (finalEquipMapList != null && finalEquipMapList.get(plan.getId()) != null) {
                plan.setPlanEquipment(finalEquipMapList.get(plan.getId()));
            }
        });
    }

    @Override
    public Map<Long, Long> getPlanUsedDocs() {
        Map<Long, Long> resMap = new HashMap<>(64);
        List<PlanDoc> usedList = planDocDao.findAllByIsDelete(false);
        if (!usedList.isEmpty()) {
            usedList.forEach(planDoc -> resMap.put(planDoc.getDocId(), planDoc.getPlanId()));
        }
        return resMap;
    }

    @Override
    public Map<String, Long> getPlanUsedRules() {
        Map<String, Long> resMap = new HashMap<>(64);
        List<PlanRule> usedList = planRuleDao.findAllByIsDelete(false);
        if (!usedList.isEmpty()) {
            usedList.forEach(planRule -> resMap.put(planRule.getRuleId(), planRule.getPlanId()));
        }
        return resMap;
    }

    @Override
    public Map<Long, Long> getPlanUsedEquipments() {
        Map<Long, Long> resMap = new HashMap<>(64);
        List<PlanEquipment> usedList = planEquipmentDao.findAllByIsDelete(false);
        if (!usedList.isEmpty()) {
            usedList.forEach(planEquipment -> resMap.put(planEquipment.getFireEquipmentId(), planEquipment.getPlanId()));
        }
        return resMap;
    }

    @Override
    public void subscribeTopic() {
        try {
            emqKeeper.getMqttClient().subscribe(DELETE_SYNC_PLAN_DOC, (s, mqttMessage) -> {
                byte[] payload = mqttMessage.getPayload();
                try {
                    List<Long> ids = (List<Long>) ClazzUtils.deserializableObject(payload);
                    if (!ValidationUtil.isEmpty(ids)) {
                        planDocMapper.logicDeleteByDocIdList(ids);
                    }
                } catch (Exception e) {
                    logger.error("预案文档删除同步出错", e);
                }
            });
        } catch (MqttException e) {
            logger.fatal("订阅文档删除同步消息失败，资源删除或取消无法同步", e);
        }
        try {
            emqKeeper.getMqttClient().subscribe(DELETE_SYNC_PLAN_RULE, (s, mqttMessage) -> {
                byte[] payload = mqttMessage.getPayload();
                try {
                    String[] ids = new String(payload).split(",");
                    if (!ValidationUtil.isEmpty(ids)) {
                        planRuleMapper.logicDeleteByRuleIdList(Arrays.asList(ids));
                    }
                } catch (Exception e) {
                    logger.error("预案规则删除同步出错", e);
                }
            });
        } catch (MqttException e) {
            logger.fatal("订阅规则删除同步消息失败，资源删除或取消无法同步", e);
        }
        /*try {
            emqKeeper.getMqttClient().subscribe(DELETE_SYNC_PLAN_EQUIP, (s, mqttMessage) -> {
                byte[] payload = mqttMessage.getPayload();
                try {
                    List<Long> ids = (List<Long>) ClazzUtils.deserializableObject(payload);
                    if (!ValidationUtil.isEmpty(ids)) {
                        planEquipmentMapper.logicDeleteByEquipIdList(ids);
                    }
                } catch (Exception e) {
                    logger.error("预案保护对象删除同步出错", e);
                }
            });
        } catch (MqttException e) {
            logger.fatal("订阅保护对象删除同步消息失败，资源删除或取消无法同步", e);
        }*/
    }

}