package com.zehong.web.controller.equipment;

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.system.domain.TEquipmentAlarmData;
import com.zehong.system.domain.TEquipmentInfo;
import com.zehong.system.domain.modbus.ModbusDeviceData;
import com.zehong.system.modbus.util.Modbus4jUtils;
import com.zehong.system.service.ITEquipmentAlarmDataService;
import com.zehong.system.service.ITEquipmentInfoService;
import com.zehong.system.task.AgingCabinetInspectionAndPowerCheckTask;
import com.zehong.system.task.CheckPowerOnCommandEvent;
import com.zehong.system.task.PowerOffCommandEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * @author lenovo
 * @date 2025/6/11
 * @description 测试定时任务的接口，每次调用都能实时显示
 */
@RestController
@RequestMapping("/testTaskController")
public class TestTaskController {

    private static final Logger log = LoggerFactory.getLogger(AgingCabinetInspectionAndPowerCheckTask.class);
    private final ExecutorService executor = Executors.newFixedThreadPool(10);
    @Resource
    private ITEquipmentInfoService tEquipmentInfoService;

    @Resource
    private ITEquipmentAlarmDataService tEquipmentAlarmDataService;

    @Resource
    private ApplicationEventPublisher eventPublisher; // 新增事件发布器

    /**
     * 断电
     */
    @GetMapping("/testPowerOutage")
    public void powerOutage() {
        // 10 层
        List<Integer> registerOffsets = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
        ModbusMaster master;
        try {
            master = Modbus4jUtils.getMaster("192.168.1.102", 504);
            for (Integer registerOffset : registerOffsets) {
                Boolean aBoolean = Modbus4jUtils.writeCoil(master, 1,registerOffset,false );
            }
        } catch (ModbusInitException | ModbusTransportException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 五分钟一次
     * 1.老化柜、标定柜巡查
     * 2.老化层断电
     */
    @GetMapping("/getAgingCabinetAndPowerCheck")
    public DeferredResult<List<ModbusDeviceData>> getAgingCabinetAndPowerCheck() {

        List<String> type = new ArrayList<>();
        type.add("1");
        type.add("2");
        List<TEquipmentInfo> equipmentInfos = tEquipmentInfoService.selectTEquipmentList(type);

        DeferredResult<List<ModbusDeviceData>> deferredResult = new DeferredResult<>();
        TEquipmentAlarmData alarmData = new TEquipmentAlarmData();

        try {
            if (equipmentInfos.size() == 0) {
                log.error("设备列表查询结果为空");
                throw new Exception("无设备信息！");
            }
            List<CompletableFuture<ModbusDeviceData>> futures = equipmentInfos.stream().map(equipmentInfo -> CompletableFuture.supplyAsync(() -> {
                ModbusMaster master = null;
                // 10 层
                List<Integer> registerOffsets = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
                try {
                    master = Modbus4jUtils.getMaster(equipmentInfo.getfIp(), equipmentInfo.getfPort());
                    Map<Integer, Object> integerObjectMap = Modbus4jUtils.batchReadAgingCabinetStatus(master, registerOffsets);

                    // 返回结果 无错误
                    return createErrorData(equipmentInfo, "", "", integerObjectMap);

                } catch (ModbusInitException e) {
                    // 记录异常数据
                    alarmData.setfAlarmType("01"); //01.老化柜 02.机械臂 03.老化层 04.点位
                    alarmData.setfEquipmentCode(equipmentInfo.getfEquipmentCode());
                    alarmData.setfAlarmData("定时任务巡检:Modbus初始化失败");
                    tEquipmentAlarmDataService.insertTEquipmentAlarmData(alarmData);
                    // 更新老化柜状态（“0”空闲，“1”运行，“2”故障）
                    equipmentInfo.setfStatus("2");
                    tEquipmentInfoService.updateTEquipmentInfo(equipmentInfo);

                    // 返回错误信息
                    Map<Integer, Object> errorMap = new HashMap<>();
                    // 返回结果
                    return createErrorData(equipmentInfo, "2", "Modbus初始化失败", errorMap);
                    // 层有错误返回 柜可能连不上也在这个报错里面
                } catch (ModbusTransportException e) {
                    // 网线没插好通讯不上
                    if (e.getMessage().equals("java.net.SocketTimeoutException: connect timed out")) {
                        // 记录异常数据
                        alarmData.setfAlarmType("01"); //01.老化柜 02.机械臂 03.老化层 04.点位
                        alarmData.setfEquipmentCode(equipmentInfo.getfEquipmentCode());
                        alarmData.setfAlarmData("定时任务巡检:老化柜网线没插好");
                        // 线接错误
                    } else {
                        // 记录异常数据
                        alarmData.setfAlarmType("01"); //01.老化柜 02.机械臂 03.老化层 04.点位
                        alarmData.setfEquipmentCode(equipmentInfo.getfEquipmentCode());
                        alarmData.setfAlarmData("定时任务巡检:老化柜通信线路没接好");
                    }
                    tEquipmentAlarmDataService.insertTEquipmentAlarmData(alarmData);
                    // 更新老化柜状态（“0”空闲，“1”运行，“2”故障）
                    equipmentInfo.setfStatus("2");
                    tEquipmentInfoService.updateTEquipmentInfo(equipmentInfo);

                    Map<Integer, Object> errorMap = new HashMap<>();
                    // 网线没插好通讯不上
                    // 返回结果
                    if (e.getMessage().equals("java.net.SocketTimeoutException: connect timed out")) {
                        return createErrorData(equipmentInfo, "2", "定时任务巡检:网线没插好", errorMap);
                    } else {
                        // 线接错误
                        // 返回结果
                        return createErrorData(equipmentInfo, "2", "定时任务巡检:通信线路没接好", errorMap);
                    }
                } catch (ErrorResponseException e) {
                    Map<Integer, Object> errorMap = new HashMap<>();
                    // 返回结果
                    return createErrorData(equipmentInfo, "2", "定时任务巡检:ErrorResponseException", errorMap);
                } finally {
                    if (master != null) {
                        master.destroy();
                    }
                }
            }, executor)).collect(Collectors.toList());

            // 等待所有任务完成并收集结果
            CompletableFuture<List<ModbusDeviceData>> listCompletableFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
                    .thenApply(v -> futures.stream()
                            .map(CompletableFuture::join)
                            .collect(Collectors.toList()));
            // 处理 老化柜 是 运行 开始 空闲
            CompletableFuture<List<ModbusDeviceData>> processedFuture = listCompletableFuture.thenApply(this::processDeviceData);

            processedFuture.whenComplete((result, ex) -> {
                if (ex != null) {
                    deferredResult.setErrorResult(Collections.singletonList(createErrorData(ex)));
                } else {
                    deferredResult.setResult(result);
                }
            });

        } catch (Exception e) {
            e.printStackTrace();
        }
        return deferredResult;
    }

    private ModbusDeviceData createErrorData(TEquipmentInfo equipmentInfo, String status,
                                             String errorReason, Map<Integer, Object> integerObjectMap) {
        ModbusDeviceData deviceData = new ModbusDeviceData();
        deviceData.setId(equipmentInfo.getfEquipmentId());
        deviceData.setfIp(equipmentInfo.getfIp());
        deviceData.setfPort(equipmentInfo.getfPort());
        deviceData.setDeviceCode(equipmentInfo.getfEquipmentCode());
        deviceData.setDeviceStatus(status);
        deviceData.setErrorReason(errorReason);
        deviceData.setfPowerOutageIp(equipmentInfo.getfPowerOutageIp());
        deviceData.setfPowerOutagePort(equipmentInfo.getfPowerOutagePort());
        if (integerObjectMap != null) {
            deviceData.setRegisterValues(integerObjectMap.entrySet().stream()
                    .collect(Collectors.toMap(
                            Map.Entry::getKey,
                            e -> e.getValue() != null ? e.getValue().toString() : "NULL"
                    )));
        }
        return deviceData;
    }

    //  处理 老化柜 是 运行 开始 空闲
    private List<ModbusDeviceData> processDeviceData(List<ModbusDeviceData> deviceDataList) {

        for (ModbusDeviceData modbusDeviceData : deviceDataList) {
            Map<Integer, String> registerValues = modbusDeviceData.getRegisterValues();
            // 大于0 说明 柜能通信；小于0 说明柜 不能通信
            if (registerValues.size() > 0) {
                boolean isRun = false;
                for (Map.Entry<Integer, String> entry : registerValues.entrySet()) {
                    Integer registerOffset = entry.getKey();
                    String registerValue = entry.getValue();
                    if ("true".equals(registerValue)) {
                        eventPublisher.publishEvent(new CheckPowerOnCommandEvent(
                                this,
                                modbusDeviceData.getDeviceCode(),
                                modbusDeviceData.getfPowerOutageIp(),
                                modbusDeviceData.getfPowerOutagePort(),
                                registerOffset +1,
                                registerOffset
                        ));
                        isRun = true;
                        // 要给这个 层 发断电的  指令
                    } else {
                        // 发布断电指令事件（不再直接执行）
                        eventPublisher.publishEvent(new PowerOffCommandEvent(
                                this,
                                modbusDeviceData.getDeviceCode(),
                                modbusDeviceData.getfPowerOutageIp(),
                                modbusDeviceData.getfPowerOutagePort(),
                                registerOffset
                        ));
                    }
                }
                if (isRun) {
                    modbusDeviceData.setDeviceStatus("1");
                } else {
                    modbusDeviceData.setDeviceStatus("0");
                }
            } else {
                modbusDeviceData.setDeviceStatus("0");
            }
        }
        return deviceDataList;
    }

    private ModbusDeviceData createErrorData(Throwable ex) {
        ModbusDeviceData errorData = new ModbusDeviceData();
        errorData.setDeviceCode("error");
        errorData.setRegisterValues(Collections.singletonMap(0, "系统错误：" + ex.getMessage()));
        return errorData;
    }
}
