package com.zehong.system.task;

import com.serotonin.modbus4j.ModbusFactory;
import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.ip.IpParameters;
import com.serotonin.modbus4j.ip.tcp.TcpMaster;
import com.serotonin.modbus4j.msg.ModbusResponse;
import com.serotonin.modbus4j.msg.ReadHoldingRegistersRequest;
import com.serotonin.modbus4j.msg.ReadHoldingRegistersResponse;
import com.zehong.system.domain.TEquipmentAlarmData;
import com.zehong.system.domain.TStoreyInfo;
import com.zehong.system.mapper.TStoreyInfoMapper;
import com.zehong.system.modbus.handler.ModbusResultHandler;
import com.zehong.system.modbus.handler.dto.DeviceStatusReaderDto;
import com.zehong.system.modbus.util.Modbus4jUtils;
import com.zehong.system.service.ITEquipmentAlarmDataService;
import org.apache.commons.lang3.StringUtils;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;
/**
 * @author lenovo
 * @date 2025/6/25
 * @description 上电以后 两分钟执行一次的逻辑
 */
@Component
@DisallowConcurrentExecution
public class DeviceCommunicationJob implements Job {
    private static final Logger log = LoggerFactory.getLogger(DeviceCommunicationJob.class);
    // 工厂（单例）
    private static final ModbusFactory modbusFactory = new ModbusFactory();
    public static final int MAX_RETRIES = 1; // 仅1次重试（减少总耗时）
    // 常量配置（优化重试，减少耗时）
    public static final int START_ADDRESS = 0;
    public static final int REGISTER_COUNT = 10;
    @Resource
    private ITEquipmentAlarmDataService alarmDataService;
    // 移除静态线程池，使用单线程顺序执行
    private final ExecutorService sequentialExecutor = Executors.newSingleThreadExecutor();
    @Resource
    private TStoreyInfoMapper tStoreyInfoMapper;

    @Autowired
    private ModbusResultHandler resultHandler;

    @Override
    public void execute(JobExecutionContext context) {
        log.info("=== DeviceCommunicationJob 开始执行 ===");

        try {
            // 使用单线程顺序执行，避免并发问题
            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                executeJobSafely(context);
            }, sequentialExecutor);

            // 设置总超时
            future.get(180, TimeUnit.SECONDS); // 3分钟总超时
            log.info("=== DeviceCommunicationJob 正常完成 ===");

        } catch (TimeoutException e) {
            log.error("任务执行超时", e);
            recordAlarm(context, "任务执行超时（3分钟）");
        } catch (Exception e) {
            log.error("任务执行异常（已捕获，不会影响触发器）", e);
            recordAlarm(context, "任务执行异常: " + e.getMessage());
        }
    }
    private void executeJobSafely(JobExecutionContext context) {
        try {
            // 1. 提取参数
            JobDataMap data = context.getJobDetail().getJobDataMap();
            String fStoreyIdStr = data.getString("fStoreyId");

            if (StringUtils.isBlank(fStoreyIdStr)) {
                log.warn("fStoreyId参数为空");
                return;
            }

            Long fStoreyId = Long.parseLong(fStoreyIdStr);
            TStoreyInfo tStoreyInfo = tStoreyInfoMapper.selectTStoreyInfoById(fStoreyId);

            if (tStoreyInfo == null || StringUtils.isBlank(tStoreyInfo.getfIp())) {
                log.warn("设备信息无效: fStoreyId={}", fStoreyId);
                return;
            }

            // 2. 顺序执行三个端口（不要并行）
            executePortSequentially(tStoreyInfo, fStoreyId);

        } catch (Exception e) {
            log.error("executeJobSafely内部异常", e);
            // 这里不抛出异常，只是记录日志
        }
    }
    private void executePortSequentially(TStoreyInfo tStoreyInfo, Long fStoreyId) {
        String ip = tStoreyInfo.getfIp();

        // 顺序执行，避免并发问题
        executeSinglePortSafely(ip, 501, getOffsets501(), fStoreyId, tStoreyInfo);
        executeSinglePortSafely(ip, 502, getOffsets502(), fStoreyId, tStoreyInfo);
        executeSinglePortSafely(ip, 503, getOffsets503(), fStoreyId, tStoreyInfo);
    }

    private void executeSinglePortSafely(String ip, int port, List<Integer> deviceIds,
                                         Long fStoreyId, TStoreyInfo tStoreyInfo) {
        log.info("开始执行端口{}: ip={}, 设备数={}", port, ip, deviceIds.size());

        for (int deviceId : deviceIds) {
            try {
                executeSingleDeviceSafely(ip, port, deviceId, fStoreyId, tStoreyInfo);
                // 每个设备执行后短暂休息，避免资源竞争
                Thread.sleep(50);
            } catch (Exception e) {
                log.error("设备{}执行异常: ip={}, port={}", deviceId, ip, port, e);
                // 继续执行下一个设备，不中断整个任务
            }
        }

        log.info("端口{}执行完成: ip={}", port, ip);
    }

    private void executeSingleDeviceSafely(String ip, int port, int deviceId,
                                           Long fStoreyId, TStoreyInfo tStoreyInfo) {
        ModbusMaster master = null;
        try {
            // 创建连接
            master = createModbusMaster(ip, port);

            // 读取数据（简化重试逻辑）
            int[] result = readDeviceRegistersOnce(master, deviceId);

            // 处理结果
            if (resultHandler != null) {
                resultHandler.accept(new DeviceStatusReaderDto(ip, port, deviceId, result));
            }

            log.debug("设备{}通信成功: ip={}, port={}", deviceId, ip, port);

        } catch (Exception e) {
            log.warn("设备{}通信失败: ip={}, port={}, 错误: {}",
                    deviceId, ip, port, e.getMessage());
            // 不抛出异常，只记录警告
        } finally {
            // 确保资源释放
            if (master != null) {
                try {
                    master.destroy();
                } catch (Exception e) {
                    log.debug("释放Modbus连接异常: deviceId={}", deviceId, e);
                }
            }
        }
    }

    /**
     * 简化版：只读取一次，不重试
     */
    private int[] readDeviceRegistersOnce(ModbusMaster master, int deviceId)
            throws ModbusTransportException {
        ReadHoldingRegistersRequest request =
                Modbus4jUtils.getReadHoldingRegistersRequest(deviceId, START_ADDRESS, REGISTER_COUNT);

        ModbusResponse response = master.send(request);

        if (!(response instanceof ReadHoldingRegistersResponse)) {
            throw new IllegalArgumentException("Invalid response type");
        }

        ReadHoldingRegistersResponse regResponse = (ReadHoldingRegistersResponse) response;
        short[] signedValues = regResponse.getShortData();

        // 转换为无符号整数
        int[] unsignedValues = new int[signedValues.length];
        for (int i = 0; i < signedValues.length; i++) {
            unsignedValues[i] = signedValues[i] & 0xFFFF;
        }

        return unsignedValues;
    }

    private void recordAlarm(JobExecutionContext context, String alarmData) {
        try {
            JobDataMap data = context.getJobDetail().getJobDataMap();
            String fStoreyIdStr = data.getString("fStoreyId");

            TEquipmentAlarmData alarm = new TEquipmentAlarmData();
            alarm.setfAlarmType("03");
            alarm.setfEquipmentCode(fStoreyIdStr != null ? fStoreyIdStr : "unknown");
            alarm.setfAlarmData(alarmData);
            alarm.setfCreateTime(new Date());
            alarmDataService.insertTEquipmentAlarmData(alarm);
        } catch (Exception e) {
            log.error("记录告警失败", e);
        }
    }

    // 设备列表
    private List<Integer> getOffsets501() {
        return Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27);
    }

    private List<Integer> getOffsets502() {
        return Arrays.asList(28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54);
    }

    private List<Integer> getOffsets503() {
        return Arrays.asList(55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72);
    }
    /**
     * 创建新的Modbus连接
     */
    private ModbusMaster createModbusMaster(String ip, int port) throws ModbusInitException {
        IpParameters params = new IpParameters();
        params.setHost(ip);
        params.setPort(port);

        // 显式声明为TcpMaster，避免后续反射类型转换问题
        TcpMaster master = (TcpMaster) modbusFactory.createTcpMaster(params, true);
        master.setTimeout(3000); // 3秒连接超时
        master.setRetries(1);    // 1次重试
        master.init();
        log.debug("Modbus连接创建成功：IP={}, 端口={}, Master={}", ip, port, master);
        return master;
    }
}
