package com.zehong.system.service.impl;

import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.zehong.common.core.domain.AjaxResult;
import com.zehong.common.utils.DateUtils;
import com.zehong.common.utils.StringUtils;
import com.zehong.system.domain.TEquipmentAlarmData;
import com.zehong.system.domain.TEquipmentInfo;
import com.zehong.system.domain.TStoreyInfo;
import com.zehong.system.domain.TTrayInfo;
import com.zehong.system.mapper.TEquipmentInfoMapper;
import com.zehong.system.mapper.TStoreyInfoMapper;
import com.zehong.system.mapper.TTrayInfoMapper;
import com.zehong.system.modbus.util.Modbus4jUtils;
import com.zehong.system.service.IRobotArmCommandService;
import com.zehong.system.service.ITEquipmentAlarmDataService;
import com.zehong.system.service.ITEquipmentInfoService;
import com.zehong.system.service.ITStoreyInfoService;
import com.zehong.system.task.CheckPowerOnCommandEvent;
import com.zehong.system.task.DeviceTaskScheduler;
import com.zehong.system.task.RealTimeReadAgingDataFunction;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import static com.zehong.system.task.DeviceTaskScheduler.JOB_GROUP;
import static com.zehong.system.task.DeviceTaskScheduler.TRIGGER_GROUP;

/**
 * 老化层信息Service业务层处理
 *
 * @author zehong
 * @date 2025-05-28
 */
@Service
public class TStoreyInfoServiceImpl implements ITStoreyInfoService
{
    public static final Logger log = LoggerFactory.getLogger(TStoreyInfoServiceImpl.class);
    @Resource
    private TStoreyInfoMapper tStoreyInfoMapper;

    @Resource
    private TTrayInfoMapper tTrayInfoMapper;

    @Resource
    private TEquipmentInfoMapper equipmentInfoMapper;

    @Resource
    private IRobotArmCommandService robotArmCommandService;

    @Resource
    private DeviceTaskScheduler deviceTaskScheduler;

    @Resource
    private ITEquipmentAlarmDataService tEquipmentAlarmDataService;
    @Resource
    private Scheduler scheduler;
    @Resource
    private ITEquipmentInfoService tEquipmentInfoService;
    private final ExecutorService executor = Executors.newFixedThreadPool(10);
    @Resource
    private ApplicationEventPublisher eventPublisher; // 新增事件发布器

    @Resource
    private RealTimeReadAgingDataFunction realTimeReadAgingDataFunction;



    private final ExecutorService executorService = Executors.newFixedThreadPool(10);

    /**
     * 查询老化层信息
     *
     * @param fStoreyId 老化层信息ID
     * @return 老化层信息
     */
    @Override
    public TStoreyInfo selectTStoreyInfoById(Long fStoreyId)
    {
        return tStoreyInfoMapper.selectTStoreyInfoById(fStoreyId);
    }

    /**
     * 指定设备断电
     *
     * @param equipmentCode aging cabinet
     * @return aging cabinet
     */
    @Override
    public AjaxResult designatedDevicePowerOff(String equipmentCode) {

        // 1.1 校验参数
        List<TEquipmentInfo> equipmentInfos = checkEquipmentCodesReturnEquipmentInfos(equipmentCode);

        // 1.2 批量上电
        powerOffToEquipments(equipmentInfos);
        return AjaxResult.success();
    }

    /**
     * 指定设备上电
     * @param equipmentCode e
     * @return r
     */
    @Override
    public AjaxResult designatedDevicePowerOn(String equipmentCode) {

        // 1.1 校验参数
        List<TEquipmentInfo> equipmentInfos = checkEquipmentCodesReturnEquipmentInfos(equipmentCode);

        // 1.2 批量上电
        powerOnToEquipments(equipmentInfos);

        return AjaxResult.success();
    }


    /**
     * 校验参数
     * @return r r
     */
    private List<TEquipmentInfo> checkEquipmentCodesReturnEquipmentInfos(String equipmentCodes) {

        if(StringUtils.isBlank(equipmentCodes)) {
            throw new RuntimeException("设备编号不能为空");
        }

        String[] split = equipmentCodes.split("[,，]");
        if(split.length == 0) {
            throw new RuntimeException("设备编号格式错误");
        }

        List<String> equipmentCodeList = Arrays.stream(split).filter(StringUtils::isNotBlank).collect(Collectors.toList());

        List<TEquipmentInfo> equipmentInfos = equipmentInfoMapper.getAllByEquipmentCodeList(equipmentCodeList);
        if(equipmentInfos.size() == 0) {
            throw new RuntimeException("设备不存在");
        }

        return equipmentInfos;
    }

    /**
     * 批量断电
     * @param equipmentInfos e
     * @return r r
     */
    private void powerOffToEquipments(List<TEquipmentInfo> equipmentInfos) {
        // 收集所有异步任务
        List<CompletableFuture<TEquipmentInfo>> futures = equipmentInfos.stream()
                .map(equipmentInfo -> CompletableFuture.supplyAsync(() -> {
                    ModbusMaster master = null;
                    List<Integer> registerOffsets = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
                    try {
                        master = Modbus4jUtils.createModbusMaster(equipmentInfo.getfPowerOutageIp(), equipmentInfo.getfPowerOutagePort());

                        for (Integer registerOffset : registerOffsets) {
                            Boolean aBoolean = Modbus4jUtils.readCoilStatus(master, 1, registerOffset);
                            if (aBoolean) {
                                Modbus4jUtils.writeCoil(master, 1, registerOffset, false);
                            }
                        }
                    } catch (ModbusInitException | ModbusTransportException | ErrorResponseException e) {
                        log.info("equipmentinfo -> ip = {} port = {}" + equipmentInfo.getfPowerOutageIp(), equipmentInfo.getfPowerOutagePort());
                        throw new RuntimeException(e);
                    } finally {
                        // 建议在这里关闭master连接，避免资源泄露
                        if (master != null) {
                            try {
                                master.destroy();
                            } catch (Exception e) {
                                // 处理关闭异常
                            }
                        }
                    }
                    return equipmentInfo;
                }, executorService))
                .collect(Collectors.toList());

        // 等待所有异步任务完成
        CompletableFuture<Void> allFutures = CompletableFuture.allOf(
                futures.toArray(new CompletableFuture[0])
        );

        // 所有任务完成后执行数据库更新
        allFutures.thenRun(() -> {
            TStoreyInfo tStoreyInfo = new TStoreyInfo();
            tStoreyInfo.setfStatus("0");
            tStoreyInfo.setfAgingStartTime(null);
            tStoreyInfoMapper.updateAllStatusAndAgingStartTime(tStoreyInfo);
        }).join(); // 阻塞等待所有操作完成
    }

    /**
     * 批量上电
     * @return r r
     */
    private void powerOnToEquipments(List<TEquipmentInfo> equipmentInfos) {
        // 收集所有异步任务
        List<CompletableFuture<TEquipmentInfo>> futures = equipmentInfos.stream()
                .map(equipmentInfo -> CompletableFuture.supplyAsync(() -> {
                    ModbusMaster master = null;
                    List<Integer> registerOffsets = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
                    try {
                        master = Modbus4jUtils.createModbusMaster(equipmentInfo.getfPowerOutageIp(), equipmentInfo.getfPowerOutagePort());

                        for (Integer registerOffset : registerOffsets) {
                            Boolean aBoolean = Modbus4jUtils.readCoilStatus(master, 1, registerOffset);
                            if (!aBoolean) {
                                Modbus4jUtils.writeCoil(master, 1, registerOffset, true);
                            }
                        }
                    } catch (ModbusInitException | ModbusTransportException | ErrorResponseException e) {
                        log.info("equipmentinfo -> ip = {} port = {}" + equipmentInfo.getfPowerOutageIp(), equipmentInfo.getfPowerOutagePort());
                        throw new RuntimeException(e);
                    } finally {
                        // 建议在这里关闭master连接，避免资源泄露
                        if (master != null) {
                            try {
                                master.destroy();
                            } catch (Exception e) {
                                // 处理关闭异常
                            }
                        }
                    }
                    return equipmentInfo;
                }, executorService))
                .collect(Collectors.toList());

        // 等待所有异步任务完成
        CompletableFuture<Void> allFutures = CompletableFuture.allOf(
                futures.toArray(new CompletableFuture[0])
        );

        // 所有任务完成后执行数据库更新
        allFutures.thenRun(() -> {
            TStoreyInfo tStoreyInfo = new TStoreyInfo();
            tStoreyInfo.setfStatus("1");
            // 先不给 老化开始时间  只 上电
//            tStoreyInfo.setfAgingStartTime(DateUtils.getNowDate());
            tStoreyInfoMapper.updateAllStatusAndAgingStartTime(tStoreyInfo);
        }).join(); // 阻塞等待所有操作完成

    }

    /**
     * 更新南边指令
     */
    private void updateNCommand() {
        List<Long> equipmentIds = Arrays.asList(18L, 19L, 20L, 21L, 22L, 23L, 24L, 25L, 26L, 27L, 28L, 29L, 30L, 31L, 32L);
        List<TStoreyInfo> tStoreyInfos = tStoreyInfoMapper.selectByEquipmentIds(equipmentIds);
        if(tStoreyInfos.size() > 0) {
            for (TStoreyInfo tStoreyInfo : tStoreyInfos) {
                String s = tStoreyInfo.getfStoreyCode();
                Long aLong = tStoreyInfo.getfEquipmentId();
                String[] split = s.split("-");
                String feedingCommand = "NSL" + (aLong - 17L) + split[1];
                String blankingCommand = "NXL" + (aLong - 17L) + split[1];
                tStoreyInfo.setFeedingCommand(feedingCommand);
                tStoreyInfo.setBlankingCommand(blankingCommand);
            }
            tStoreyInfoMapper.updateBatch(tStoreyInfos);
        }
    }
    /**
     * 更新北边指令
     */
    private void updateBCommand(){
        List<Long> equipmentIds = Arrays.asList(3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L);
        List<TStoreyInfo> tStoreyInfos = tStoreyInfoMapper.selectByEquipmentIds(equipmentIds);
        if(tStoreyInfos.size() > 0) {
            for (TStoreyInfo tStoreyInfo : tStoreyInfos) {
                String s = tStoreyInfo.getfStoreyCode();
                String[] split = s.split("-");
                String feedingCommand = "BSL" + split[0] + split[1];
                String blankingCommand = "BXL" + split[0] + split[1];
                tStoreyInfo.setFeedingCommand(feedingCommand);
                tStoreyInfo.setBlankingCommand(blankingCommand);
            }
            tStoreyInfoMapper.updateBatch(tStoreyInfos);
        }
    }

    private void initStoreyInfo() {
        List<TEquipmentInfo> equipmentInfos1 = equipmentInfoMapper.selectTEquipmentInfoList(new TEquipmentInfo());
        List<TStoreyInfo> tStoreyInfos = tStoreyInfoMapper.selectTStoreyInfoList(new TStoreyInfo());

        if (tStoreyInfos.size() < 16) {
            TStoreyInfo storeyInfo;
            List<TStoreyInfo> storeyInfoList = new ArrayList<>();

            for (TEquipmentInfo tEquipmentInfo : equipmentInfos1) {
                String ip = tEquipmentInfo.getfIp();
                if (ip == null || !ip.matches("\\d+\\.\\d+\\.\\d+\\.\\d+")) {
                    continue;
                }

                String[] split = ip.split("\\.");
                if (split.length != 4) {
                    continue;
                }

                try {
                    int start = Integer.parseInt(split[3]) + 9; // 起始值（如IP最后一段为81，则start=90）
                    String baseIp = split[0] + "." + split[1] + "." + split[2] + ".";
                    int code = 1;

                    // 核心修改：循环10次（i从start递减到start-9，共10个值）
                    for (int i = start; i >= start - 9; i--) {
                        storeyInfo = new TStoreyInfo();
                        storeyInfo.setfEquipmentId(tEquipmentInfo.getfEquipmentId());
                        storeyInfo.setfStoreyCode(tEquipmentInfo.getfEquipmentCode() + "-" + code);
                        storeyInfo.setfIp(baseIp + i); // 生成IP：如192.168.2.90、192.168.2.89...192.168.2.81
                        storeyInfo.setfPort("501,502,503");
                        storeyInfo.setfStatus("0");
                        storeyInfo.setfCreateTime(new Date());
                        storeyInfoList.add(storeyInfo);
                        code++;
                    }
                } catch (NumberFormatException e) {
                    continue;
                }
            }

            if (!storeyInfoList.isEmpty()) {
                tStoreyInfoMapper.insertBatch(storeyInfoList);
            }
        }
    }

    /**
     * 查询老化层信息
     *
     * @param fStoreyCode 老化层信息Code
     * @return 老化层信息
     */
    @Override
    public TStoreyInfo selectTStoreyInfoByCode(String fStoreyCode)
    {
        return tStoreyInfoMapper.selectTStoreyInfoByCode(fStoreyCode);
    }

    /**
     * 查询老化层信息列表
     *
     * @param tStoreyInfo 老化层信息
     * @return 老化层信息
     */
    @Override
    public List<TStoreyInfo> selectTStoreyInfoList(TStoreyInfo tStoreyInfo)
    {
        return tStoreyInfoMapper.selectTStoreyInfoList(tStoreyInfo);
    }

    /**
     * 根据设备id 查询层信息
     * @param fEquipmentId f
     * @return r
     */
    @Override
    public List<TStoreyInfo> queryByDepartmentId(Long fEquipmentId) {
        return tStoreyInfoMapper.queryByDepartmentId(fEquipmentId);
    }

    /**
     * 批量扫描所有老化柜的层数据记录系统开始老化
     * @return r
     */
    @Override
    public AjaxResult scanAndStartAgingAllCabinetLayers() {

        List<TEquipmentInfo> equipmentInfos = equipmentInfoMapper.getAll();

        if (equipmentInfos.size() == 0) {
            return AjaxResult.error("无设备信息！！！");
        }

        try {
            // 先清理所有定时任务和触发器
            Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(JOB_GROUP));
            List<JobKey> jobKeysList = new ArrayList<>(jobKeys);
            // 清理触发器
            Set<TriggerKey> triggerKeys = scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(TRIGGER_GROUP));
            List<TriggerKey> triggerKeysList = new ArrayList<>(triggerKeys);
            scheduler.deleteJobs(jobKeysList);
            scheduler.unscheduleJobs(triggerKeysList);

            startScanAllCabinetLayers(equipmentInfos);
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }

        return null;
    }

    /**
     * 开始扫描所有老化柜的层数据记录系统开始老化
     */
    private void startScanAllCabinetLayers(List<TEquipmentInfo> equipmentInfos) {
        TEquipmentAlarmData alarmData = new TEquipmentAlarmData();
        List<CompletableFuture<TEquipmentInfo>> futures = equipmentInfos.stream().map(equipmentInfo -> CompletableFuture.supplyAsync(() -> {
            ModbusMaster master = null;
            // 10 层
            List<Integer> registerOffsets = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
            try {
                master = Modbus4jUtils.createModbusMaster(equipmentInfo.getfIp(), equipmentInfo.getfPort());
                Map<Integer, Object> integerObjectMap = Modbus4jUtils.batchReadAgingCabinetStatus(master, registerOffsets);

                equipmentInfo.setRegisterValues(integerObjectMap);

            } catch (ModbusInitException e) {
                // 记录异常数据
                alarmData.setfAlarmType("01"); //01.老化柜 02.机械臂 03.老化层 04.点位
                alarmData.setfEquipmentCode(equipmentInfo.getfEquipmentCode());
                alarmData.setfAlarmData("定时任务巡检:Modbus初始化失败");
                tEquipmentAlarmDataService.insertTEquipmentAlarmData(alarmData);
                // 更新老化柜状态（“0”空闲，“1”运行，“2”故障）
                equipmentInfo.setfStatus("2");
                equipmentInfo.setErrorReason("定时任务巡检:Modbus初始化失败");
                equipmentInfo.setRegisterValues(new HashMap<>());
                // 返回结果
                return equipmentInfo;
                // 层有错误返回 柜可能连不上也在这个报错里面
            } catch (ModbusTransportException e) {
                // 网线没插好通讯不上
                if (e.getMessage().equals("java.net.SocketTimeoutException: connect timed out")) {
                    // 记录异常数据
                    alarmData.setfAlarmType("01"); //01.老化柜 02.机械臂 03.老化层 04.点位
                    alarmData.setfEquipmentCode(equipmentInfo.getfEquipmentCode());
                    alarmData.setfAlarmData("定时任务巡检:老化柜网线没插好");
                    equipmentInfo.setErrorReason("定时任务巡检:老化柜网线没插好");
                    // 线接错误
                } else {
                    // 记录异常数据
                    alarmData.setfAlarmType("01"); //01.老化柜 02.机械臂 03.老化层 04.点位
                    alarmData.setfEquipmentCode(equipmentInfo.getfEquipmentCode());
                    alarmData.setfAlarmData("定时任务巡检:老化柜通信线路没接好");
                    equipmentInfo.setErrorReason("定时任务巡检:老化柜通信线路没接好");
                }
                tEquipmentAlarmDataService.insertTEquipmentAlarmData(alarmData);
                // 更新老化柜状态（“0”空闲，“1”运行，“2”故障）
                equipmentInfo.setRegisterValues(new HashMap<>());
                equipmentInfo.setfStatus("2");

                return equipmentInfo;
            } catch (ErrorResponseException e) {
                equipmentInfo.setfStatus("2");
                equipmentInfo.setRegisterValues(new HashMap<>());
                equipmentInfo.setErrorReason("定时任务巡检:ErrorResponseException");
                return equipmentInfo;
            } finally {
                if (master != null) {
                    master.destroy();
                }
            }
            return equipmentInfo;
        }, executor)).collect(Collectors.toList());

        // 等待所有任务完成并收集结果
        CompletableFuture<List<TEquipmentInfo>> listCompletableFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
                .thenApply(v -> futures.stream()
                        .map(CompletableFuture::join)
                        .collect(Collectors.toList()));
        // 处理 老化柜 是 运行 开始 空闲
        CompletableFuture<List<TEquipmentInfo>> processedFuture = listCompletableFuture.thenApply(this::processDeviceData);

        processedFuture.whenComplete((result, ex) -> {
            tEquipmentInfoService.batchUpdate(result);
            // 执行WebSocket广播，推送最新老化柜状态
//            if (result != null && !result.isEmpty()) {
//                agingCabinetWebSocketHandler.broadcastAgingCabinetData(result);
//                log.info("已通过WebSocket广播{}条老化柜状态数据", result.size());
//            }
        });
    }

    //  处理 老化柜 是 运行 开始 空闲
    private List<TEquipmentInfo> processDeviceData(List<TEquipmentInfo> deviceDataList) {

        for (TEquipmentInfo modbusDeviceData : deviceDataList) {
            Map<Integer, Object> registerValues = modbusDeviceData.getRegisterValues();
            // 大于0 说明 柜能通信；小于0 说明柜 不能通信
            if (registerValues.size() > 0) {
                boolean isRun = false;
                for (Map.Entry<Integer, Object> entry : registerValues.entrySet()) {
                    Integer registerOffset = entry.getKey();
                    Object registerValue = entry.getValue();
                    log.info("registerValue =  " + registerValue);
                    log.info("true equals  registerValue" + Boolean.TRUE.equals(registerValue));
                    if (Boolean.TRUE.equals(registerValue)) {
                        eventPublisher.publishEvent(new CheckPowerOnCommandEvent(
                                this,
                                modbusDeviceData.getfEquipmentCode(),
                                modbusDeviceData.getfPowerOutageIp(),
                                modbusDeviceData.getfPowerOutagePort(),
                                registerOffset + 1,
                                registerOffset
                        ));
                        isRun = true;
                    }
                }
                if (isRun) {
                    modbusDeviceData.setfStatus("1");
                } else {
                    modbusDeviceData.setfStatus("0");
                }
            } else {
                modbusDeviceData.setfStatus("0");
            }
        }
        return deviceDataList;
    }

    /**
     * 所有设备断电
     */
    public AjaxResult powerOffAllStore() {

        List<TEquipmentInfo> equipmentInfos = equipmentInfoMapper.getAll();

        if (equipmentInfos.size() == 0) {
            return AjaxResult.error("无设备信息！！！");
        }

        // 批量处理
        powerOffToEquipments(equipmentInfos);

        return AjaxResult.success();
    }

    /**
     * 批量处理
     * @param command c
     * @return r
     */
    @Override
    public AjaxResult handleFeeding(String command) {

        // 发送UDP指令
        robotArmCommandService.sendCommand(command);
        return AjaxResult.success();
    }

    /**
     * 批量处理
     * @param command c
     * @return r
     */
    @Override
    public AjaxResult handleDirectBlanking(String command) {
        // 发送UDP指令
        robotArmCommandService.sendCommand(command);
        return AjaxResult.success();
    }

    /**
     * 清理任务
     * @param tStoreyInfo c
     * @return r
     */
    @Override
    public AjaxResult handleClearTasks(TStoreyInfo tStoreyInfo) {

        if(tStoreyInfo.getfStoreyId() == null) {
            return AjaxResult.error("请选择老化层！！！");
        }

        try {
            deviceTaskScheduler.cleanExistingTasks(tStoreyInfo.getfStoreyId());
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }

        return AjaxResult.success();
    }

    /**
     * 重新老化
     * @param tStoreyInfo c
     * @return r
     */
    @Override
    public AjaxResult handleReAgine(TStoreyInfo tStoreyInfo) {

        // CheckPowerOnCommandEvent 方法里面 会 重新开始记录老化时间
        String storeyCode = tStoreyInfo.getfStoreyCode();
        String[] parts = storeyCode.split("-");
        String equitmentCode = parts[0];
        int registerOffset = Integer.parseInt(parts[1]);
        TEquipmentInfo tEquipmentInfo = equipmentInfoMapper.selectTEquipmentInfoByCode(equitmentCode);
        if(tEquipmentInfo == null) {
            return AjaxResult.error("无此设备信息！！！");
        }

        String powerOutageIp = tEquipmentInfo.getfPowerOutageIp();
        Integer powerOutagePort = tEquipmentInfo.getfPowerOutagePort();

        eventPublisher.publishEvent(new CheckPowerOnCommandEvent(
                this,
                equitmentCode,
                powerOutageIp,
                powerOutagePort,
                registerOffset,
                registerOffset - 1
        ));

        return AjaxResult.success();
    }

    /**
     * 发送下料指令
     * @return r
     */
    @Override
    public AjaxResult handleBlanking(String command) {
        // 发送UDP指令
        // 先不直接发送指令，而是 先生成 下料指令，去 提高 下料指令的效率
//        robotArmCommandService.sendCommand(command);
        int notCompletedCommand = robotArmCommandService.findNotCompletedCommand(command);
        if(notCompletedCommand > 0) {
            return AjaxResult.error("有未完成指令，请稍后再试");
        } else {
            // 根据指令 去查 老化层
            TStoreyInfo tStoreyInfo = tStoreyInfoMapper.selectByBlankingCommand(command);
            if(tStoreyInfo == null) {
                return AjaxResult.error("无此指令对应的老化层信息");
            }

            if(checkStoreyInfoPower(tStoreyInfo)) {
                TTrayInfo tTrayInfo = tTrayInfoMapper.selectTTrayInfoByStoreyCode(tStoreyInfo.getfStoreyCode());

                //还得去把没执行的 定时任务删掉，否则会导致 再次 发送下料指令
                try {
                    deviceTaskScheduler.cleanExistingTasks(tStoreyInfo.getfStoreyId());
                } catch (SchedulerException e) {
                    return AjaxResult.error("定时任务异常,请联系管理员");
                }

                if(tTrayInfo != null) {
                    robotArmCommandService.generateBlankingCommand(tTrayInfo.getfTrayCode(), tStoreyInfo.getfStoreyCode(), command);
                }
            } else {
                robotArmCommandService.sendCommand(command);
            }

        }
        return AjaxResult.success();
    }

    /**
     * 批量处理
     * @param tStoreyInfo c
     * @return r
     */
    private Boolean checkStoreyInfoPower(TStoreyInfo tStoreyInfo) {

        TEquipmentInfo tEquipmentInfo = equipmentInfoMapper.selectTEquipmentInfoById(tStoreyInfo.getfEquipmentId());
        String registerOffset = tStoreyInfo.getfStoreyCode().split("-")[1];

        try {
            ModbusMaster master = Modbus4jUtils.createModbusMaster(tEquipmentInfo.getfPowerOutageIp(), tEquipmentInfo.getfPowerOutagePort());

            int i = Integer.parseInt(registerOffset);
            int registerOffsetInt = i - 1;

            return Modbus4jUtils.readCoilStatus(master, 1, registerOffsetInt);
        } catch (ModbusInitException | ModbusTransportException | ErrorResponseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 批量开灯
     * @return r
     */
    @Override
    public AjaxResult powerOnAllStore() {
        List<String> types = Arrays.asList("1", "2");
        List<TEquipmentInfo> equipmentInfos = equipmentInfoMapper.selectTEquipmentList(types);

        if (equipmentInfos.size() == 0) {
            return AjaxResult.error("无设备信息！！！");
        }

        powerOnToEquipments(equipmentInfos);

        return AjaxResult.success();
    }

    @Override
    public AjaxResult handleReadingHoldingRegister(String storeyCode) {

        if(StringUtils.isBlank(storeyCode) || storeyCode.split("-").length != 2) {
            return AjaxResult.error("柜层号输入有问题！！！");
        }
        try {
            List<RealTimeReadAgingDataFunction.DeviceResult> results =
                    realTimeReadAgingDataFunction.execute(storeyCode);

            // 转换为前端需要的格式
            List<Map<String, Object>> formattedResults = results.stream()
                    .map(result -> {
                        Map<String, Object> map = new HashMap<>();
                        map.put("serpentineNumber", result.getSerpentineNumber());
                        map.put("success", result.isSuccess());
                        if (result.getModbusResult() != null) {
                            map.put("concentration", result.getModbusResult()[0]);
                            map.put("status", result.getModbusResult()[1]);
                            map.put("modbusResult", result.getModbusResult());
                        }
                        map.put("message", result.getMessage());
                        return map;
                    })
                    .collect(Collectors.toList());

            return AjaxResult.success(formattedResults);
        } catch (Exception e) {
            return AjaxResult.error("读取失败: " + e.getMessage());
        }
    }

    /**
     * 批量读取设备状态
     * @param fEquipmentCode f
     * @return r
     */
    @Override
    public AjaxResult batchReadingCabinetStatus(String fEquipmentCode) {

        TEquipmentInfo tEquipmentInfo = equipmentInfoMapper.selectTEquipmentInfoByCode(fEquipmentCode);
        if(tEquipmentInfo == null) {
            return AjaxResult.error("设备不存在！！！");
        }
        List<Integer> integers = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);

        try {
            ModbusMaster master = Modbus4jUtils.createModbusMaster(tEquipmentInfo.getfIp(), tEquipmentInfo.getfPort());

            Map<Integer, Object> integerObjectMap = Modbus4jUtils.batchReadAgingCabinetStatus(master, integers);

            return AjaxResult.success(integerObjectMap);

        } catch (ModbusInitException | ModbusTransportException | ErrorResponseException e) {
            return AjaxResult.error("设备连接异常！！！");
        }
    }

    /**
     * 给设备断电
     * @param tStoreyInfo t
     * @return r
     */
    @Override
    public AjaxResult powerOutage(TStoreyInfo tStoreyInfo) {

        if(tStoreyInfo.getfEquipmentId() == null || tStoreyInfo.getfStoreyCode() == null) {
            return AjaxResult.error("参数异常！！！");
        }
        TEquipmentInfo tEquipmentInfo = equipmentInfoMapper.selectTEquipmentInfoById(tStoreyInfo.getfEquipmentId());
        String registerOffset = tStoreyInfo.getfStoreyCode().split("-")[1];

        try {
            ModbusMaster master = Modbus4jUtils.createModbusMaster(tEquipmentInfo.getfPowerOutageIp(), tEquipmentInfo.getfPowerOutagePort());

            int i = Integer.parseInt(registerOffset);
            int registerOffsetInt = i - 1;
            Boolean aBoolean = Modbus4jUtils.readCoilStatus(master, 1, registerOffsetInt);

            if(aBoolean) {
                Modbus4jUtils.writeCoil(master, 1, registerOffsetInt, false);

                tStoreyInfo.setfStatus("0");
                tStoreyInfo.setfAgingStartTime(null);
                tStoreyInfoMapper.updateTStoreyInfo(tStoreyInfo);
            }
            return AjaxResult.success();

        } catch (ModbusInitException | ModbusTransportException | ErrorResponseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 给设备上电
     * @param tStoreyInfo t
     * @return r
     */
    @Override
    public AjaxResult powerOn(TStoreyInfo tStoreyInfo) {

        if(tStoreyInfo.getfEquipmentId() == null || tStoreyInfo.getfStoreyCode() == null) {
            return AjaxResult.error("参数异常！！！");
        }

        TEquipmentInfo tEquipmentInfo = equipmentInfoMapper.selectTEquipmentInfoById(tStoreyInfo.getfEquipmentId());
        String registerOffset = tStoreyInfo.getfStoreyCode().split("-")[1];

        try {
            ModbusMaster master = Modbus4jUtils.createModbusMaster(tEquipmentInfo.getfPowerOutageIp(), tEquipmentInfo.getfPowerOutagePort());

            int i = Integer.parseInt(registerOffset);
            int registerOffsetInt = i - 1;
            Boolean aBoolean = Modbus4jUtils.readCoilStatus(master, 1, registerOffsetInt);

            if(!aBoolean) {
                Modbus4jUtils.writeCoil(master, 1, registerOffsetInt, true);

                // 20260104 这些调整不再这儿直接设置了
//                tStoreyInfo.setfStatus("1");
//                tStoreyInfo.setfAgingStartTime(new Date());
//                tStoreyInfoMapper.updateTStoreyInfo(tStoreyInfo);
            }
            return AjaxResult.success();

        } catch (ModbusInitException | ModbusTransportException | ErrorResponseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 新增老化层信息
     *
     * @param tStoreyInfo 老化层信息
     * @return 结果
     */
    @Override
    public int insertTStoreyInfo(TStoreyInfo tStoreyInfo)
    {

        check(tStoreyInfo);
        tStoreyInfo.setfCreateTime(DateUtils.getNowDate());

        return tStoreyInfoMapper.insertTStoreyInfo(tStoreyInfo);
    }

    private void check(TStoreyInfo tStoreyInfo) {

        if(StringUtils.isBlank(tStoreyInfo.getfStoreyCode())){
            throw new RuntimeException("层编号不能为空");
        }
        if(tStoreyInfo.getfStoreyCode() != null && tStoreyInfo.getfStoreyId() ==  null) {
            TStoreyInfo storeyInfo = tStoreyInfoMapper.selectTStoreyInfoByCode(tStoreyInfo.getfStoreyCode());
            if(storeyInfo != null) {
                throw new RuntimeException("层编号已存在");
            }
        }
        if(StringUtils.isBlank(tStoreyInfo.getfEquipmentCode())){
            throw new RuntimeException("柜编号不许为空");
        }

        TEquipmentInfo tEquipmentInfo = equipmentInfoMapper.selectTEquipmentInfoByCode(tStoreyInfo.getfEquipmentCode());
        if(tEquipmentInfo == null) {
            throw new RuntimeException("柜编号不存在");
        }
        tStoreyInfo.setfEquipmentId(tEquipmentInfo.getfEquipmentId());
    }

    /**
     * 修改老化层信息
     *
     * @param tStoreyInfo 老化层信息
     * @return 结果
     */
    @Override
    public int updateTStoreyInfo(TStoreyInfo tStoreyInfo)
    {
        check(tStoreyInfo);
        tStoreyInfo.setUpdateTime(DateUtils.getNowDate());
        return tStoreyInfoMapper.updateTStoreyInfo(tStoreyInfo);
    }

    /**
     * 批量删除老化层信息
     *
     * @param fStoreyIds 需要删除的老化层信息ID
     * @return 结果
     */
    @Override
    public int deleteTStoreyInfoByIds(Long[] fStoreyIds)
    {
        return tStoreyInfoMapper.deleteTStoreyInfoByIds(fStoreyIds);
    }

    /**
     * 删除老化层信息信息
     *
     * @param fStoreyId 老化层信息ID
     * @return 结果
     */
    @Override
    public int deleteTStoreyInfoById(Long fStoreyId)
    {
        return tStoreyInfoMapper.deleteTStoreyInfoById(fStoreyId);
    }
}
