package com.zehong.system.task;

import com.zehong.system.domain.TEquipmentAlarmData;
import com.zehong.system.domain.TStoreyInfo;
import com.zehong.system.mapper.TStoreyInfoMapper;
import com.zehong.system.modbus.business.DeviceStatusReaderAndTimeSetter;
import com.zehong.system.modbus.handler.ModbusResultHandler;
import com.zehong.system.service.ITEquipmentAlarmDataService;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
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.*;
import java.util.function.Predicate;

/**
 * @author lenovo
 * @date 2025/6/25
 * @description 上电以后 两分钟执行一次的逻辑
 */
@Component
@DisallowConcurrentExecution
public class DeviceCommunicationJob implements Job {
    private static final Logger log = LoggerFactory.getLogger(DeviceCommunicationJob.class);

    @Resource
    private ITEquipmentAlarmDataService alarmDataService;
    @Resource
    private DeviceStatusReaderAndTimeSetter deviceStatusReaderAndTimeSetter;
    @Resource
    private TStoreyInfoMapper tStoreyInfoMapper;

    @Autowired
    private ModbusResultHandler resultHandler;

    // 单个端口通信超时时间（确保总时间 < Cron周期）
    private static final int PORT_TIMEOUT_SECONDS = 8;
    // 临时线程池（避免静态线程池关闭问题）
    private final ExecutorService portExecutor = Executors.newFixedThreadPool(3); // 3个端口，3个线程
    @Override
    public void execute(JobExecutionContext context) {
        long startTime = System.currentTimeMillis();
        JobDataMap data = null;
        String fStoreyIdStr = null;
        Long fStoreyId = null;
        TStoreyInfo tStoreyInfo = null;
        String ip = null;

        try {
            log.info("=== DeviceCommunicationJob 启动：fStoreyIdStr={}，线程={} ===",
                    fStoreyIdStr, Thread.currentThread().getName());

            // 1. 提取参数（严格校验，避免后续异常）
            data = context.getJobDetail().getJobDataMap();
            if (data == null) {
                log.error("JobDataMap为空，终止执行");
                return;
            }
            fStoreyIdStr = data.getString("fStoreyId");
            if (StringUtils.isBlank(fStoreyIdStr)) {
                log.error("fStoreyId参数为空，终止执行");
                recordAlarm(null, "fStoreyId为空", "通信任务异常：fStoreyId参数为空");
                return;
            }

            // 2. 转换参数（处理格式错误）
            try {
                fStoreyId = Long.parseLong(fStoreyIdStr);
            } catch (NumberFormatException e) {
                log.error("fStoreyId格式错误：{}，终止执行", fStoreyIdStr);
                recordAlarm(null, fStoreyIdStr, "通信任务异常：fStoreyId格式错误：" + fStoreyIdStr);
                return;
            }

            // 3. 查询设备信息（双重校验+异常捕获）
            try {
                tStoreyInfo = tStoreyInfoMapper.selectTStoreyInfoById(fStoreyId);
            } catch (Exception e) {
                log.error("查询设备信息异常：fStoreyId={}", fStoreyId, e);
                recordAlarm(null, fStoreyIdStr, "通信任务异常：查询设备信息失败：" + e.getMessage());
                return;
            }
            if (tStoreyInfo == null) {
                log.error("未查询到设备信息：fStoreyId={}，清理无效任务", fStoreyId);
                // 清理任务（单独捕获SchedulerException，避免异常穿透）
                try {
                    context.getScheduler().deleteJob(context.getJobDetail().getKey());
                } catch (SchedulerException e) {
                    log.error("清理无效任务失败：fStoreyId={}", fStoreyId, e);
                }
                recordAlarm(null, fStoreyIdStr, "通信任务异常：未查询到设备信息，已清理任务");
                return;
            }
            ip = tStoreyInfo.getfIp();
            if (StringUtils.isBlank(ip)) {
                log.error("设备IP为空：fStoreyId={}，终止执行", fStoreyId);
                recordAlarm(tStoreyInfo, "设备IP为空", "通信任务异常：设备IP为空");
                return;
            }

            // 4. 校验依赖组件（避免空指针）
            if (resultHandler == null) {
                log.error("ModbusResultHandler未初始化，终止执行");
                recordAlarm(tStoreyInfo, "ResultHandler未初始化", "通信任务异常：ModbusResultHandler未初始化");
                return;
            }
            // 校验停止条件（避免NullPointerException）
            Predicate<int[]> stopCondition = ModbusResultHandler.createDefaultStopCondition();

            // 5. 设备ID列表（拆分后便于管理）
            List<Integer> offsets1 = 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);
            List<Integer> offsets2 = 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);
            List<Integer> offsets3 = Arrays.asList(55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72);

            // 6. 多端口并行通信（使用临时线程池，避免静态线程池问题）
            final String finalIp = ip;
            final Long finalFStoreyId = fStoreyId;
            final TStoreyInfo finalTStoreyInfo = tStoreyInfo;
            Future<?> port1Future = portExecutor.submit(() -> {
                executePortCommunication(finalIp, 501, offsets1, resultHandler, stopCondition, finalFStoreyId, finalTStoreyInfo);
            });
            Future<?> port2Future = portExecutor.submit(() -> {
                executePortCommunication(finalIp, 502, offsets2, resultHandler, stopCondition, finalFStoreyId, finalTStoreyInfo);
            });
            Future<?> port3Future = portExecutor.submit(() -> {
                executePortCommunication(finalIp, 503, offsets3, resultHandler, stopCondition, finalFStoreyId, finalTStoreyInfo);
            });

            // 等待所有端口完成（总超时 = 单个端口超时 * 1.2，避免无限等待）
            port1Future.get(PORT_TIMEOUT_SECONDS * 1200, TimeUnit.MILLISECONDS);
            port2Future.get(PORT_TIMEOUT_SECONDS * 1200, TimeUnit.MILLISECONDS);
            port3Future.get(PORT_TIMEOUT_SECONDS * 1200, TimeUnit.MILLISECONDS);

            // 7. 校验执行时间（确保未超过Cron周期）
            long costTime = System.currentTimeMillis() - startTime;
            if (costTime > 240000) { // 超过4分钟（Cron为5分钟，留1分钟缓冲）
                log.warn("任务执行超时：{}ms（Cron周期5分钟），可能导致下一次任务延迟", costTime);
                recordAlarm(tStoreyInfo, "任务超时", "通信任务警告：执行时间过长：" + costTime + "ms");
            }

            log.info("=== DeviceCommunicationJob 成功：fStoreyId={}，耗时={}ms ===", finalFStoreyId, costTime);

        } catch (Throwable e) {
            // 8. 捕获所有异常（确保不传播到Quartz）
            log.error("=== DeviceCommunicationJob 致命异常：fStoreyIdStr={} ===", fStoreyIdStr, e);
            recordAlarm(tStoreyInfo, fStoreyIdStr, "通信任务致命异常：" + e.getMessage());

        } finally {
            // 9. 强制释放资源（避免内存泄漏）
            portExecutor.shutdown(); // 关闭临时线程池
            long costTime = System.currentTimeMillis() - startTime;
            log.info("=== DeviceCommunicationJob 结束：fStoreyIdStr={}，总耗时={}ms ===", fStoreyIdStr, costTime);
        }
    }
    /**
     * 单个端口的Modbus通信（独立方法，便于异常管控）
     */
    private void executePortCommunication(String ip, int port, List<Integer> deviceIds,
                                          ModbusResultHandler resultHandler, Predicate<int[]> stopCondition,
                                          Long fStoreyId, TStoreyInfo tStoreyInfo) {
        try {
            log.info("开始端口{}通信：fStoreyId={}，设备数={}", port, fStoreyId, deviceIds.size());
            deviceStatusReaderAndTimeSetter.startMultiDeviceMonitoring(ip, port, deviceIds, resultHandler, stopCondition);
            log.info("端口{}通信完成：fStoreyId={}", port, fStoreyId);
        } catch (Exception e) {
            log.error("端口{}通信异常：fStoreyId={}", port, fStoreyId, e);
            recordAlarm(tStoreyInfo, "端口" + port + "异常", "Modbus通信异常：端口" + port + "失败：" + e.getMessage());
        }
    }
    // 简化方法签名，不需要传入ip和fStoreyId参数
    private void executeWithTimeout(Runnable task, long timeout, TimeUnit unit,
                                    TStoreyInfo tStoreyInfo, String timeoutMsg,
                                    String ip, Long fStoreyId) {
        try {
            ExecutorService executor = Executors.newSingleThreadExecutor();
            Future<?> future = executor.submit(task);
            future.get(timeout, unit);
            executor.shutdown();
        } catch (TimeoutException e) {
            log.error("{}：fStoreyId={}, ip={}", timeoutMsg, fStoreyId, ip, e);
            recordAlarm(tStoreyInfo, tStoreyInfo.getfEquipmentCode(),timeoutMsg + "（IP：" + ip + "，设备ID：" + fStoreyId + "）");
        } catch (Exception e) {
            log.error("{}执行异常：fStoreyId={}, ip={}", timeoutMsg, fStoreyId, ip, e);
            recordAlarm(tStoreyInfo, tStoreyInfo.getfEquipmentCode(),timeoutMsg + "执行异常（IP：" + ip + "，设备ID：" + fStoreyId + "）：" + e.getMessage());
        }
    }


    /**
     * 统一告警记录（兼容设备信息为空的场景）
     */
    private void recordAlarm(TStoreyInfo tStoreyInfo, String equipmentCode, String alarmData) {
        try {
            TEquipmentAlarmData alarm = new TEquipmentAlarmData();
            alarm.setfAlarmType("03"); // 老化层告警
            alarm.setfEquipmentCode(tStoreyInfo != null ? tStoreyInfo.getfStoreyCode() : equipmentCode);
            alarm.setfAlarmData(alarmData);
            alarm.setfCreateTime(new Date());
            alarmDataService.insertTEquipmentAlarmData(alarm);
        } catch (Exception e) {
            log.error("告警记录失败：{}", alarmData, e);
        }
    }
}
