package com.dcs.equipment.task;

import com.alibaba.fastjson2.JSON;
import com.dcs.equipment.domain.DeviceRequest;
import com.dcs.equipment.domain.DeviceResponse;
import com.dcs.equipment.server.EquipmentListWebSocketServer;
import com.dcs.equipment.service.DeviceService;
import com.dcs.equipment.service.InfluxDBService;
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.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;

import static com.dcs.equipment.domain.ModbusTcpEnum.DATA_ADDRESS_LENGTH_MAP;

/**
 * @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;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private InfluxDBService influxDBService;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private ScheduledExecutorService scheduledExecutorService;

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

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

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

    private void updateDataToEquipmentParamFormVOList() {
        // 获取设备响应数据
        Map<String, List<DeviceResponse>> deviceResponseMap = deviceService.getResponseMapByDeviceRequests(deviceRequestList);

        // 拷贝设备信息
        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 (DeviceResponse deviceResponse : deviceResponseMap.get(registerCode)) {
                // 跳过不匹配的数据类型
                if (!equipmentVo.getDataType().equals(deviceResponse.getDataType())) continue;
                int startAddress = deviceResponse.getOffsetOrIndex();
                int quantity = deviceResponse.getLengthOrQos();
                int dataLength = DATA_ADDRESS_LENGTH_MAP.get(deviceResponse.getDataType());
                // 跳过不在当前地址范围内的响应数据
                if (address < startAddress || address > startAddress + (quantity * dataLength)) continue;
                int index = (address - startAddress) / dataLength;
//                List<Object> data = modbusResponse.getData();
                Object o = deviceResponse.getData().get(index);
                equipmentVo.setValue(o);
                break;
            }
        }
        broadCastEquipmentParamFormVOList = Collections.unmodifiableList(deepCopyEquipmentParamFormVOList);
        CacheCenter.registerNowDataMap= EquipmentParamUtils.paramListToMap(broadCastEquipmentParamFormVOList);
        // 保存数据到influxdb
        CompletableFuture.runAsync(() ->
                influxDBService.saveDataToInfluxDB("shanghai_dcs_bucket", deepCopyEquipmentParamFormVOList)
        , scheduledExecutorService);
    }

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

}
