package com.zehong.system.modbus.handler;

import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.zehong.system.domain.PalletDeviceBinding;
import com.zehong.system.domain.TEquipmentAlarmData;
import com.zehong.system.mapper.PalletDeviceBindingMapper;
import com.zehong.system.modbus.business.DeviceStatusReaderAndTimeSetter;
import com.zehong.system.modbus.handler.dto.DeviceStatusReaderDto;
import com.zehong.system.modbus.util.Modbus4jUtils;
import com.zehong.system.service.ITEquipmentAlarmDataService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * @author lenovo
 * @date 2025/6/27
 * @description 读取数据后根据状态判断设置时间
 */
@Component
public class ModbusResultHandler implements Consumer<DeviceStatusReaderDto> {

    private static final Logger log = LoggerFactory.getLogger(ModbusResultHandler.class);
    @Resource
    private ITEquipmentAlarmDataService alarmDataService;

    @Resource
    private PalletDeviceBindingMapper palletDeviceBindingMapper;

    // 创建固定大小的线程池（根据实际情况调整大小）
    private static final ExecutorService executorService = Executors.newFixedThreadPool(
            Runtime.getRuntime().availableProcessors() * 2
    );
    @Override
    public void accept(DeviceStatusReaderDto deviceStatusReaderDto) {
        // 提交任务到线程池异步执行
        executorService.submit(() -> handleData(deviceStatusReaderDto));
    }

    // 实际的数据处理方法（线程安全）
    private void handleData(DeviceStatusReaderDto dto) {
        int deviceId = dto.getDeviceId();
        int[] data = dto.getRegisterData();
        String ip = dto.getIp();
        int port = dto.getPort();

        // 根据 层ip 查找 层 code  根据层code 查 托盘id  根据托盘id 和  deviceId 查 绑定的点位数据
        PalletDeviceBinding palletDeviceBinding = palletDeviceBindingMapper.selectByTrayIdAndIndex(ip, deviceId);

        TEquipmentAlarmData alarmData;

        // 1 获取 线程专有的Modbus连接
        try {
            ModbusMaster master = Modbus4jUtils.getMaster(ip, port);

            log.info(">>> 回调处理: 接收到新数据" +  Thread.currentThread().getName() + "]: 接收到新数据");
            log.info("    数据: " + Arrays.toString(data));

            if (data.length >= 2) {
                // 给点位设置状态
                palletDeviceBinding.setStatus(data[1] + "");

                log.info("    >>> 注意: 第二个寄存器值为1 或者 3 或者 4 允许写时间!");
                if(data[1] == 1 || data[1] == 3 || data[1] == 4) {

                    Calendar cal = Calendar.getInstance();
                    // 当前年
                    int y = cal.get(Calendar.YEAR);
                    // 当前月
                    int m = cal.get(Calendar.MONTH) + 1;
                    // 当前日
                    int d = cal.get(Calendar.DATE);
                    // 当前小时
                    int h = cal.get(Calendar.HOUR_OF_DAY);
                    // 当前分钟
                    int mm = cal.get(Calendar.MINUTE);

                    boolean yearResult = Modbus4jUtils.writeRegister(master,deviceId, 4, (short) y);
                    if(!yearResult) {
                        alarmData = new TEquipmentAlarmData();
                        alarmData.setfAlarmType("04");
                        alarmData.setCreateTime(new Date());
                        alarmData.setfEquipmentCode("ip:" +  ip + ",port:" +  port  + "deviceId:" + deviceId);
                        alarmData.setfAlarmData("年-日期写入失败");
                        alarmDataService.insertTEquipmentAlarmData(alarmData);
                    }else {
                        palletDeviceBinding.setRecordYear(y + "");
                    }
                    boolean mResult = Modbus4jUtils.writeRegister(master,deviceId, 5, (short) m);
                    if(!mResult) {
                        alarmData = new TEquipmentAlarmData();
                        alarmData.setfAlarmType("04");
                        alarmData.setCreateTime(new Date());
                        alarmData.setfEquipmentCode("ip:" +  ip + ",port:" +  port  + "deviceId:" + deviceId);
                        alarmData.setfAlarmData("月-日期写入失败");
                        alarmDataService.insertTEquipmentAlarmData(alarmData);
                    }else {
                        palletDeviceBinding.setRecordMonth(m + "");
                    }
                    boolean dResult = Modbus4jUtils.writeRegister(master,deviceId, 6, (short) d);

                    if(!dResult) {
                        alarmData = new TEquipmentAlarmData();
                        alarmData.setfAlarmType("04");
                        alarmData.setCreateTime(new Date());
                        alarmData.setfEquipmentCode("ip:" +  ip + ",port:" +  port  + "deviceId:" + deviceId);
                        alarmData.setfAlarmData("天-日期写入失败");
                        alarmDataService.insertTEquipmentAlarmData(alarmData);
                    }else {
                        palletDeviceBinding.setRecordDate(h + "");
                    }
                    boolean hResult = Modbus4jUtils.writeRegister(master,deviceId,  7, (short) h);

                    if(!hResult) {
                        alarmData = new TEquipmentAlarmData();
                        alarmData.setfAlarmType("04");
                        alarmData.setCreateTime(new Date());
                        alarmData.setfEquipmentCode("ip:" +  ip + ",port:" +  port  + "deviceId:" + deviceId);
                        alarmData.setfAlarmData("时-日期写入失败");
                        alarmDataService.insertTEquipmentAlarmData(alarmData);
                    }else {
                        palletDeviceBinding.setRecordHour(d + "");
                    }
                    boolean mmResult = Modbus4jUtils.writeRegister(master,deviceId,  8, (short) mm);

                    if(!mmResult) {
                        alarmData = new TEquipmentAlarmData();
                        alarmData.setfAlarmType("04");
                        alarmData.setCreateTime(new Date());
                        alarmData.setfEquipmentCode("ip:" +  ip + ",port:" +  port  + "deviceId:" + deviceId);
                        alarmData.setfAlarmData("分-日期写入失败");
                        alarmDataService.insertTEquipmentAlarmData(alarmData);
                    } else {
                        palletDeviceBinding.setRecordMinute(mm + "");
                    }
                    // 更新
                    palletDeviceBindingMapper.updatePalletDeviceBinding(palletDeviceBinding);
                } else {
                    alarmData = new TEquipmentAlarmData();
                    alarmData.setfAlarmType("04");
                    alarmData.setCreateTime(new Date());
                    alarmData.setfEquipmentCode("ip:" +  ip + ",port:" +  port  + "deviceId:" + deviceId);
                    alarmData.setfAlarmData("三次读取后 状态不是为 1 或 3 或 4");
                    alarmDataService.insertTEquipmentAlarmData(alarmData);
                }
            } else {
                alarmData = new TEquipmentAlarmData();
                alarmData.setfAlarmType("04");
                alarmData.setCreateTime(new Date());
                alarmData.setfEquipmentCode("ip:" +  ip + ",port:" +  port  + "deviceId:" + deviceId);
                alarmData.setfAlarmData("三次读取后 状态不是为 1 或 3 或 4");
                alarmDataService.insertTEquipmentAlarmData(alarmData);
            }
        } catch (ModbusInitException e) {
            alarmData = new TEquipmentAlarmData();
            alarmData.setfAlarmType("04"); //01.老化柜 02.机械臂 03.老化层 04.点位
            alarmData.setfEquipmentCode("ip:" +  ip + ",port:" +  port );
            alarmData.setfAlarmData("Modbus初始化失败");
            alarmData.setCreateTime(new Date());
            alarmDataService.insertTEquipmentAlarmData(alarmData);
        } catch (ModbusTransportException e) {
            alarmData = new TEquipmentAlarmData();
            alarmData.setfAlarmType("04"); //01.老化柜 02.机械臂 03.老化层 04.点位
            alarmData.setfEquipmentCode("ip:" +  ip + ",port:" +  port  + "deviceId:" + deviceId);
            alarmData.setfAlarmData("日期写入失败");
            alarmData.setCreateTime(new Date());
            alarmDataService.insertTEquipmentAlarmData(alarmData);
        }
    }
    // 创建通用的停止条件（可选）
    public static Predicate<int[]> createDefaultStopCondition() {
        return values -> values.length >= 2 && values[1] == DeviceStatusReaderAndTimeSetter.TARGET_VALUE;
    }
}
