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.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
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;
    @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());

            // 提取并校验参数
            data = context.getJobDetail().getJobDataMap();
            if (data == null) {
                log.error("JobDataMap为空，终止执行");
                return;
            }
            fStoreyIdStr = data.getString("fStoreyId");
            if (StringUtils.isBlank(fStoreyIdStr)) {
                log.error("fStoreyId参数为空，终止执行");
                return;
            }

            // 转换参数
            try {
                fStoreyId = Long.parseLong(fStoreyIdStr);
            } catch (NumberFormatException e) {
                log.error("fStoreyId格式错误：{}，终止执行", fStoreyIdStr);
                return;
            }

            // 查询设备信息
            tStoreyInfo = tStoreyInfoMapper.selectTStoreyInfoById(fStoreyId);
            if (tStoreyInfo == null) {
                log.error("未查询到设备信息：fStoreyId={}，终止执行并清理任务", fStoreyId);
                context.getScheduler().deleteJob(context.getJobDetail().getKey());
                return;
            }
            ip = tStoreyInfo.getfIp();
            if (StringUtils.isBlank(ip)) {
                log.error("设备IP为空：fStoreyId={}，终止执行", fStoreyId);
                recordAlarm(tStoreyInfo, "设备IP为空，无法执行通信任务");
                return;
            }

            // 校验resultHandler
            if (resultHandler == null) {
                log.error("ModbusResultHandler未初始化，终止执行");
                recordAlarm(tStoreyInfo, "ModbusResultHandler未初始化");
                return;
            }

            // 将变量声明为final，供匿名内部类使用
            final String finalIp = ip;
            final Long finalFStoreyId = fStoreyId;
            final TStoreyInfo finalTStoreyInfo = tStoreyInfo;

            // 设备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);

            // 使用final变量
            executeWithTimeout(() -> {
                deviceStatusReaderAndTimeSetter.startMultiDeviceMonitoring(finalIp, 501, offsets1, resultHandler, ModbusResultHandler.createDefaultStopCondition());
                log.info("Modbus 501端口通信完成：fStoreyId={}", finalFStoreyId);
            }, 10, TimeUnit.SECONDS, finalTStoreyInfo, "501端口通信超时", finalIp, finalFStoreyId);

            executeWithTimeout(() -> {
                deviceStatusReaderAndTimeSetter.startMultiDeviceMonitoring(finalIp, 502, offsets2, resultHandler, ModbusResultHandler.createDefaultStopCondition());
                log.info("Modbus 502端口通信完成：fStoreyId={}", finalFStoreyId);
            }, 10, TimeUnit.SECONDS, finalTStoreyInfo, "502端口通信超时", finalIp, finalFStoreyId);

            executeWithTimeout(() -> {
                deviceStatusReaderAndTimeSetter.startMultiDeviceMonitoring(finalIp, 503, offsets3, resultHandler, ModbusResultHandler.createDefaultStopCondition());
                log.info("Modbus 503端口通信完成：fStoreyId={}", finalFStoreyId);
            }, 10, TimeUnit.SECONDS, finalTStoreyInfo, "503端口通信超时", finalIp, finalFStoreyId);

            // 校验执行时间
            long costTime = System.currentTimeMillis() - startTime;
            if (costTime > 110000) {
                log.warn("任务执行时间过长：{}ms（接近Cron周期），可能导致任务叠加", costTime);
                recordAlarm(finalTStoreyInfo, "任务执行时间过长：" + costTime + "ms");
            }

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

        } catch (Throwable e) {
            log.error("=== DeviceCommunicationJob 执行致命异常：fStoreyIdStr={} ===", fStoreyIdStr, e);
            try {
                if (tStoreyInfo != null && StringUtils.isNotBlank(tStoreyInfo.getfStoreyCode())) {
                    recordAlarm(tStoreyInfo, "通信任务异常：" + e.getMessage());
                } else {
                    TEquipmentAlarmData alarm = new TEquipmentAlarmData();
                    alarm.setfAlarmType("03");
                    alarm.setfEquipmentCode(fStoreyIdStr);
                    alarm.setfAlarmData("通信任务异常（设备信息缺失）：" + e.getMessage());
                    alarm.setfCreateTime(new Date());
                    alarmDataService.insertTEquipmentAlarmData(alarm);
                }
            } catch (Exception alarmEx) {
                log.error("=== 告警记录失败（不影响触发器） ===", alarmEx);
            }
        } finally {
            long costTime = System.currentTimeMillis() - startTime;
            log.info("=== DeviceCommunicationJob 执行结束：fStoreyIdStr={}（总耗时：{}ms） ===", fStoreyIdStr, costTime);
        }
    }

    // 简化方法签名，不需要传入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, timeoutMsg + "（IP：" + ip + "，设备ID：" + fStoreyId + "）");
        } catch (Exception e) {
            log.error("{}执行异常：fStoreyId={}, ip={}", timeoutMsg, fStoreyId, ip, e);
            recordAlarm(tStoreyInfo, timeoutMsg + "执行异常（IP：" + ip + "，设备ID：" + fStoreyId + "）：" + e.getMessage());
        }
    }

    private void recordAlarm(TStoreyInfo tStoreyInfo, String alarmData) {
        try {
            TEquipmentAlarmData alarm = new TEquipmentAlarmData();
            alarm.setfAlarmType("03");
            alarm.setfEquipmentCode(tStoreyInfo.getfStoreyCode());
            alarm.setfAlarmData(alarmData);
            alarm.setfCreateTime(new Date());
            alarmDataService.insertTEquipmentAlarmData(alarm);
        } catch (Exception e) {
            log.error("记录告警失败：{}", alarmData, e);
        }
    }
}
