package com.zehong.system.task;

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.utils.DateUtils;
import com.zehong.system.domain.SysConfig;
import com.zehong.system.domain.TEquipmentAlarmData;
import com.zehong.system.domain.TStoreyInfo;
import com.zehong.system.domain.TTrayInfo;
import com.zehong.system.mapper.RobotArmCommandMapper;
import com.zehong.system.mapper.TStoreyInfoMapper;
import com.zehong.system.mapper.TTrayInfoMapper;
import com.zehong.system.modbus.util.Modbus4jUtils;
import com.zehong.system.service.*;
import com.zehong.system.service.websocket.RobotArmWebSocketHandler;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * @author lenovo
 * @date 2025/6/17
 * @description 事件接收器
 */
@Component
public class AllCommandHandler {
    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AllCommandHandler.class);

    @Resource
    private ITEquipmentAlarmDataService alarmDataService;

    @Resource
    private TStoreyInfoMapper tStoreyInfoMapper;

    @Resource
    private TTrayInfoMapper tTrayInfoMapper;

    @Resource
    private ITTrayInfoService trayInfoService;

    @Resource
    private DeviceTaskScheduler deviceTaskScheduler;

    @Autowired
    private ISysConfigService configService;

    @Resource
    private RobotArmCommandMapper robotArmCommandMapper;
    @Resource
    private RobotArmWebSocketHandler robotArmWebSocketHandler;

    // 使用常量定义索引，避免魔法数字
    private static final int AGING_STAGE_INDEX = 3;
    private static final int DEFAULT_HOURS = 72;
    /**
     * check是否启动 ，没启动就启动下 开始老化
     *
     * @param event event
     */
    @Async
    @EventListener(CheckPowerOnCommandEvent.class)
    public void handleCheckPowerOnCommand(CheckPowerOnCommandEvent event) {

        log.info("handleCheckPowerOnCommand 方法开始处理");

        String fip = event.getIp();
        int fport = event.getPort();
        int registerOffset = event.getRegisterOffset();
        int layer = event.getLayer();

        String storeyCode = event.getDeviceCode() + "-" + event.getLayer();

        log.info("需要发送上电指令 - 设备:{} 层:{} ip:{} 端口号:{}", event.getDeviceCode(), layer, fip, fport);
        ModbusMaster master;
        try {
            master = Modbus4jUtils.createModbusMaster(fip, fport);
            Boolean aBoolean = Modbus4jUtils.readCoilStatus(master, 1, registerOffset);

            log.info("当前 - 设备:{} 层:{} -的 状态是:{}", event.getDeviceCode(), event.getLayer(), aBoolean);
            if (!aBoolean) {
                Modbus4jUtils.writeCoil(master, 1, registerOffset, true);

                // 把预计老化结束时间保存到数据库中，因为可能会不同的老化时间
                Date estimatedEndTime = getAgingEndTime();

                log.info("预计老化结束时间:{}", estimatedEndTime);
                TStoreyInfo tStoreyInfo = tStoreyInfoMapper.selectTStoreyInfoByCode(storeyCode);
                tStoreyInfo.setfStatus("1");
                tStoreyInfo.setfAgingStartTime(new Date());
                tStoreyInfo.setEstimatedEndTime(estimatedEndTime);
                tStoreyInfoMapper.updateTStoreyInfo(tStoreyInfo);

                // 同时 把 托盘的 状态更新
                TTrayInfo tTrayInfo = new TTrayInfo();
                tTrayInfo.setfStatus("1");
                tTrayInfo.setfStoreyCode(storeyCode);
                trayInfoService.updateStatusByStoreCode(tTrayInfo);

                deviceTaskScheduler.scheduleDeviceMonitoring(tStoreyInfo.getfStoreyId(), fip, fport);
            }

        } catch (ModbusInitException | ModbusTransportException | ErrorResponseException e) {
            // 记录异常
            TEquipmentAlarmData alarmData = new TEquipmentAlarmData();
            alarmData.setfAlarmType("03"); // 老化层
            alarmData.setfEquipmentCode(event.getDeviceCode());
            alarmData.setfAlarmData("上电或者是启动任务检测时异常: " + e.getMessage());
            alarmDataService.insertTEquipmentAlarmData(alarmData);
        }

    }
    public Date getAgingEndTime() {
        List<SysConfig> sysConfigs = configService.selectAgingStageTime();
        int milliseconds = getAgingMilliseconds(sysConfigs);
        return DateUtils.addMinutes(new Date(), milliseconds);
    }

    private int getAgingMilliseconds(List<SysConfig> sysConfigs) {
        try {
            if (CollectionUtils.isNotEmpty(sysConfigs) &&
                    sysConfigs.size() > AGING_STAGE_INDEX) {

                SysConfig config = sysConfigs.get(AGING_STAGE_INDEX);
                if (config != null && StringUtils.isNotBlank(config.getConfigValue())) {
                    return Integer.parseInt(config.getConfigValue());
                }
            }
        } catch (NumberFormatException e) {
            log.warn("老化时间配置解析异常，使用默认值", e);
        }

        // 返回默认值（72小时转换为毫秒）
        return DEFAULT_HOURS * 60 * 60 * 1000;
    }
    @Async  // 异步执行
    @EventListener(PowerOffCommandEvent.class)
    public void handlePowerOffCommand(PowerOffCommandEvent event) {
        String storeyCode = event.getDeviceCode() + "-" + event.getLayer();
        try {
            String ip = event.getIp();
            int port = event.getPort();
            int registerOffset = event.getRegisterOffset();
            log.info("需要发送断电指令 - 设备:{} 层:{}", event.getDeviceCode(), event.getLayer());
            TStoreyInfo tStoreyInfo = tStoreyInfoMapper.selectTStoreyInfoByCode(storeyCode);
            if (tStoreyInfo == null) {
                TEquipmentAlarmData alarmData = new TEquipmentAlarmData();
                // 记录异常数据
                alarmData.setfAlarmType("01"); //01.老化柜 02.机械臂 03.老化层 04.点位
                alarmData.setfEquipmentCode(event.getDeviceCode());
                alarmData.setfAlarmData("下属" + storeyCode + "号老化层不存在");
                alarmDataService.insertTEquipmentAlarmData(alarmData);
            } else {
                // 下料后断电
                ModbusMaster master = Modbus4jUtils.createModbusMaster(ip, port);
                Modbus4jUtils.writeCoil(master, 1, registerOffset, false);
                log.info("已发送断电指令 - 设备:{} 层:{}", event.getDeviceCode(), event.getLayer());
                master.destroy();

                tStoreyInfoMapper.unbindByCode(storeyCode);

                // 清理 托盘 和 层的关联关系
                tTrayInfoMapper.clearStoreyCodeByStoreyCode(storeyCode);
            }
        } catch (ModbusInitException | ModbusTransportException e) {
            log.error("断电指令执行失败 - 设备:{} 层:{}", event.getDeviceCode(), event.getLayer(), e);

            //把这个指令状态 改成 断电失败，不影响下面的指令执行
            robotArmCommandMapper.updateStatusPowerOffFailed(storeyCode);
            // 通过WebSocket广播更新
            robotArmWebSocketHandler.broadcastCommandUpdate();

            // 记录异常
            TEquipmentAlarmData alarmData = new TEquipmentAlarmData();
            alarmData.setfAlarmType("03"); // 老化层
            alarmData.setfEquipmentCode(event.getDeviceCode());
            alarmData.setfAlarmData("断电指令执行失败: " + e.getMessage());
            alarmDataService.insertTEquipmentAlarmData(alarmData);
        }
    }
}
