package com.dcs.equipment.task;

import com.alibaba.fastjson2.JSON;
import com.dcs.equipment.domain.ModbusRequest;
import com.dcs.equipment.domain.ModbusResponse;
import com.dcs.equipment.server.EquipmentListWebSocketServer;
import com.dcs.equipment.server.EquipmentTreeWebSocketServer;
import com.dcs.equipment.service.InfluxDBService;
import com.dcs.equipment.service.ModbusTcpService;
import com.dcs.hnyz.cache.CacheCenter;
import com.dcs.hnyz.domain.EquipmentParam;
import com.dcs.hnyz.domain.vo.EquipmentParamFormVo;
import com.dcs.hnyz.utils.EquipmentParamUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;

import static com.dcs.equipment.constants.ModbusConstants.*;
import static com.dcs.equipment.domain.ModbusTcpEnum.DATA_ADDRESS_LENGTH_MAP;
import static com.dcs.equipment.utils.ModbusUtil.getValues;

/**
 * @author: wangpx
 * @date: 2025-03-06 16:45
 */
@Component("ModbusTcpTask")
public class ModbusTcpTask {
    private static final Logger logger = LoggerFactory.getLogger("modbusTcp");
    @Resource
    private EquipmentListWebSocketServer equipmentListWebSocketServer;
    @Resource
    private EquipmentTreeWebSocketServer equipmentTreeWebSocketServer;
    @Autowired
    private ModbusTcpService modbusTcpService;
    @Autowired
    private InfluxDBService influxDBService;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private ScheduledExecutorService scheduledExecutorService;

    // 保存modbus请求信息
    public static volatile List<ModbusRequest> modbusRequestList;
    // 保存设备寄存器信息和数据地址
    public static volatile List<EquipmentParam> equipmentParamList;

    @PostConstruct
    private void init() {
        modbusTcpService.updateEquipmentCodes();
    }
    // 广播的设备消息数据 TODO 改用双缓冲减少GC
    private static volatile List<EquipmentParamFormVo> broadCastEquipmentParamFormVOList = new ArrayList<>();

    public static List<EquipmentParamFormVo> getBroadCastEquipmentParamFormVOList() {
        return broadCastEquipmentParamFormVOList;
    }

    // 保存数据到influxdb
    private void saveDataToInfluxdb(List<EquipmentParamFormVo> equipmentParamList) {
        CompletableFuture.runAsync(() ->
            influxDBService.saveDataToInfluxDB("shanghai_dcs_bucket", equipmentParamList)
        , scheduledExecutorService);
    }

    private void updateDataToEquipmentParamFormVOList() {
        // modbus请求次数
        int requestNum = modbusRequestList.size();
        // 保存modbus响应信息
        Map<String, List<ModbusResponse>> modbusResponseMap = new HashMap<>();
        modbusResponseMap.put(COIL_FUNCTION_CODE, new ArrayList<>());
        modbusResponseMap.put(INPUT_FUNCTION_CODE, new ArrayList<>());
        modbusResponseMap.put(HOLDING_FUNCTION_CODE, new ArrayList<>());
        CompletableFuture<Void>[] futures = new CompletableFuture[requestNum];
        for (int i = 0; i < requestNum; i++) {
            int finalI = i;
            try {
                futures[finalI] = CompletableFuture.runAsync(() -> {
                    ModbusRequest modbusRequest = modbusRequestList.get(finalI);
                    List<Object> list = new ArrayList<>();
                    // 响应数据
                    ModbusResponse response = new ModbusResponse();
                    response.setSlaveId(modbusRequest.getSlaveId());
                    response.setFunctionCode(modbusRequest.getFunctionCode());
                    response.setDataType(modbusRequest.getDataType());
                    response.setStartAddress(modbusRequest.getStartAddress());
                    response.setQuantity(modbusRequest.getQuantity());
                    try {
                        list = getValues(modbusRequest);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    response.setData(list);
                    modbusResponseMap.get(modbusRequest.getFunctionCode()).add(response);
                }, scheduledExecutorService);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            CompletableFuture.allOf(futures).get();  // 等待所有任务完成
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 拷贝设备信息
        List<EquipmentParamFormVo> deepCopyEquipmentParamFormVOList = new ArrayList<>();
        for (EquipmentParam equipmentParam : equipmentParamList) {
            EquipmentParamFormVo equipmentParamVO = new EquipmentParamFormVo();
            BeanUtils.copyProperties(equipmentParam, equipmentParamVO);
            // 必须拷贝，否则会导致继承数据更新丢失
            equipmentParamVO.setRegisterName(equipmentParam.getRegisterName());
            deepCopyEquipmentParamFormVOList.add(equipmentParamVO);
        }
        // 装填设备数据
        for (EquipmentParamFormVo equipmentVo : deepCopyEquipmentParamFormVOList) {
            String registerCode = equipmentVo.getRegisterCode();
            Integer address = equipmentVo.getAddress();
            if (registerCode == null) continue; // 跳过没有功能码的设备
            for (ModbusResponse modbusResponse : modbusResponseMap.get(registerCode)) {
                // 跳过不匹配的数据类型
                if (!equipmentVo.getDataType().equals(modbusResponse.getDataType())) continue;
                int startAddress = modbusResponse.getStartAddress();
                int quantity = modbusResponse.getQuantity();
                int dataLength = DATA_ADDRESS_LENGTH_MAP.get(modbusResponse.getDataType());
                // 跳过不在当前地址范围内的响应数据
                if (address < startAddress || address > startAddress + (quantity * dataLength)) continue;
                int index = (address - startAddress) / dataLength;
//                List<Object> data = modbusResponse.getData();
                Object o = modbusResponse.getData().get(index);
                equipmentVo.setValue(o);
                break;
            }
        }
        broadCastEquipmentParamFormVOList = Collections.unmodifiableList(deepCopyEquipmentParamFormVOList);
        CacheCenter.registerNowDataMap= EquipmentParamUtils.paramListToMap(broadCastEquipmentParamFormVOList);
        saveDataToInfluxdb(deepCopyEquipmentParamFormVOList);
    }

    // 保存并广播设备数据消息
    public void saveAndBroadcastEquipmentData() {
        updateDataToEquipmentParamFormVOList();
        // 广播列表设备数据
        equipmentListWebSocketServer.broadCastInfo(JSON.toJSONString(broadCastEquipmentParamFormVOList));
    }

    public void broacastEquipmentTree() {
        // 拷贝设备信息
//        List<EquipmentParamFormVo> deepCopyEquipmentParamFormVOList = broadCastEquipmentParamFormVOList;
//        for (EquipmentParamFormVo equipmentParamFormVo : broadCastEquipmentParamFormVOList) {
//            deepCopyEquipmentParamFormVOList.add(equipmentParamFormVo.clone());
//        }
    }

}
