package com.dcs.equipment.service.impl;

//import com.dcs.dcs.domain.vo.EquipmentParamFormVo;

import com.dcs.equipment.domain.Condition;
import com.dcs.equipment.domain.DeviceRequest;
import com.dcs.equipment.service.ModbusTcpService;
import com.dcs.equipment.utils.ModbusUtil;
import com.dcs.hnyz.domain.EquipmentParam;
import com.dcs.hnyz.domain.vo.EquipmentParamFormVO;
import com.intelligt.modbus.jlibmodbus.exception.ModbusIOException;
import com.intelligt.modbus.jlibmodbus.exception.ModbusNumberException;
import com.intelligt.modbus.jlibmodbus.exception.ModbusProtocolException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.CompletableFuture;

import static com.dcs.equipment.constants.ModbusConstants.*;
import static com.dcs.equipment.task.ModbusTcpTask.getBroadCastEquipmentParamFormVOList;
import static com.dcs.equipment.utils.ModbusUtil.*;

/**
 * @author: wangpx
 * @date: 2025-03-13 09:16
 */
@Service
public class ModbusTcpServiceImpl implements ModbusTcpService {

    private static final Logger logger = LoggerFactory.getLogger("modbusTcp");
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override
    public List<EquipmentParamFormVO> getDataTwinEquipmentValues() {
        List<EquipmentParamFormVO> equipmentFormVoList = getBroadCastEquipmentParamFormVOList();
        return equipmentFormVoList;
    }

    @Override
    public boolean processIfAllConditionsMet(List<EquipmentParam> targets, List<Condition> conditions) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        if (allConditionsMet(conditions)) {
            CompletableFuture.runAsync(() -> {
                while (true){
                    try {
                        if (!allConditionsMet(conditions)) {
                            executeEquipmentOperations(targets);
                            return;
                        }
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, threadPoolTaskExecutor);
            return true;
        }
        return false;
    }

    @Override
    public boolean processIfAnyConditionMet(List<EquipmentParam> targets, List<Condition> conditions) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        if (anyConditionMet(conditions)) {
            CompletableFuture.runAsync(() -> {
                while (true){
                    try {
                        if (anyConditionMet(conditions)) {
                            executeEquipmentOperations(targets);
                            return;
                        }
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }, threadPoolTaskExecutor);
            return true;
        }
        return true;
    }

    // 判断条件是否都满足
    private boolean allConditionsMet(List<Condition> conditions) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        if (conditions == null || conditions.isEmpty()) return true;
        for (Condition condition : conditions) {
//            String functionCode = condition.getFunctionCode();
            int slaveId = condition.getSlaveId();
            String dataType = condition.getDataType();
            Integer address = condition.getAddress();
            Object conditionValue = condition.getValue();
            Object value;
            switch (dataType) {
                case COIL_DATA_TYPE:
                    value = ModbusUtil.getCoilValue(1, address);
                    if (objToBoolean(value)!= objToBoolean(conditionValue)) return false;
                    break;
                case INT_DATA_TYPE:
                    value = ModbusUtil.getHoldingRegisterIntegerValue(1, address);
                    if (objToInt(value) != objToInt(conditionValue)) return false;
                    break;
                case FLOAT_DATA_TYPE:
                    value = ModbusUtil.getHoldingRegisterFloatValue(1, address);
                    if (objToFloat(value) != objToFloat(conditionValue)) return false;
                    break;
            }
        }
        return true;
    }
    // 判断条件是否有任意一个满足
    private boolean anyConditionMet(List<Condition> conditions) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        if (conditions == null || conditions.isEmpty()) return true;
        for (Condition condition : conditions) {
            String functionCode = condition.getFunctionCode();
            String dataType = condition.getDataType();
            Integer address = condition.getAddress();
            Object conditionValue = condition.getValue();
            Object value;
            switch (dataType) {
                case COIL_DATA_TYPE:
                    value = ModbusUtil.getCoilValue(1, address);
                    if (objToBoolean(value) == objToBoolean(conditionValue)) return true;
                    break;
                case INT_DATA_TYPE:
                    value = ModbusUtil.getHoldingRegisterIntegerValue(1, address);
                    if (objToInt(value) ==  objToInt(conditionValue)) return true;
                    break;
                case FLOAT_DATA_TYPE:
                    value = ModbusUtil.getHoldingRegisterFloatValue(1, address);
                    if (objToFloat(value) == objToFloat(conditionValue)) return true;
                    break;
            }
        }
        return true;
    }
    // 执行设备操作
    private void executeEquipmentOperations(List<EquipmentParam> targets) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        List<DeviceRequest> deviceRequests = ModbusUtil.getDeviceRequests(targets);
        for (DeviceRequest request : deviceRequests) {
            String resource = request.getResource();
            String dataType = request.getDataType();
            int address = request.getOffsetOrIndex();
            Object value = request.getData().get(0);
            switch (dataType) {
                case COIL_DATA_TYPE:
                    ModbusUtil.setCoilValue(1, address, objToBoolean(value));
                    break;
                case INT_DATA_TYPE:
                    ModbusUtil.setRegisterValue(1, address, objToInt(value));
                    break;
                case FLOAT_DATA_TYPE:
                    ModbusUtil.setRegisterFloatValue(1, address, objToFloat(value));
                    break;
            }
        }
    }

    @Override
    public List<Object> getValues(DeviceRequest request) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        return ModbusUtil.getValues(request);
    }

    @Override
    public void setCoils(DeviceRequest request) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        int unitId = request.getUnitId();
        int address = request.getOffsetOrIndex();
        List<Object> requestData = request.getData();
        boolean[] data = new boolean[requestData.size()];
        for (int i = 0; i < requestData.size(); i++) {
            data[i] =  objToBoolean(requestData.get(i));
        }
        ModbusUtil.setCoilValues(unitId, address, data);
    }

    @Override
    public void setCoil(DeviceRequest request) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        int unitId = request.getUnitId();
        int address = request.getOffsetOrIndex();
        ModbusUtil.setCoilValue(unitId, address, objToBoolean(request.getData().get(0)));
    }

    @Override
    public void setIntRegisters(DeviceRequest request) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        int unitId = request.getUnitId();
        int address = request.getOffsetOrIndex();
        List<Object> requestData = request.getData();
        int[] data = new int[requestData.size()];
        for (int i = 0; i < requestData.size(); i++) {
            data[i] = objToInt(requestData.get(i));
        }
        ModbusUtil.setRegisterValues(unitId, address, data);
    }

    @Override
    public void setIntRegister(DeviceRequest request) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        int unitId = request.getUnitId();
        int address = request.getOffsetOrIndex();
        ModbusUtil.setRegisterValue(unitId, address, objToInt(request.getData().get(0)));
    }

    @Override
    public void setFloatRegisters(DeviceRequest request) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        int unitId = request.getUnitId();
        int address = request.getOffsetOrIndex();
        List<Object> requestData = request.getData();
        float[] data = new float[requestData.size()];
        for (int i = 0; i < requestData.size(); i++) {
            data[i] = objToFloat(requestData.get(i));
        }
        ModbusUtil.setRegisterFloatValues(unitId, address, data);
    }

    @Override
    public void setFloatRegister(DeviceRequest request) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        int unitId = request.getUnitId();
        int address = request.getOffsetOrIndex();
        ModbusUtil.setRegisterFloatValue(unitId, address, objToFloat(request.getData().get(0)));
    }

}