package com.dcs.equipment.service.impl;

import com.dcs.dcs.domain.DcsEquipment;
import com.dcs.dcs.domain.vo.DcsEquipmentFormVo;
import com.dcs.dcs.service.IDcsEquipmentService;
import com.dcs.equipment.domain.Condition;
import com.dcs.equipment.domain.ModbusRequest;
import com.dcs.equipment.service.ModbusTcpService;
import com.dcs.equipment.task.ModbusTcpTask;
import com.dcs.equipment.utils.ModbusUtil;
import com.intelligt.modbus.jlibmodbus.exception.ModbusIOException;
import com.intelligt.modbus.jlibmodbus.exception.ModbusNumberException;
import com.intelligt.modbus.jlibmodbus.exception.ModbusProtocolException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

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

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

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

    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    private IDcsEquipmentService dcsEquipmentService;

    @Override
    public List<DcsEquipmentFormVo> getDataTwinEquipmentValues() {
        List<DcsEquipmentFormVo> equipmentFormVoList = getBroadCastEquipmentFormVoList();
        return equipmentFormVoList;
    }
    // 更新设备寄存器信息和数据地址
    public void updateEquipmentCodes() {
        DcsEquipmentFormVo dcsEquipment = new DcsEquipmentFormVo();
        List<DcsEquipmentFormVo> newEquipmentFormVoList = dcsEquipmentService.selectDcsEquipmentVoList(dcsEquipment);
        ModbusTcpTask.modbusRequestList = ModbusUtil.getModbusRequests(newEquipmentFormVoList);
        // 按照顺序存储数据
        newEquipmentFormVoList.sort(Comparator.comparing(DcsEquipment::getEquipmentId));
        ModbusTcpTask.equipmentFormVoList = newEquipmentFormVoList;
    }

    @Override
    public boolean processIfAllConditionsMet(List<DcsEquipmentFormVo> 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<DcsEquipmentFormVo> 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<DcsEquipmentFormVo> targets) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        List<ModbusRequest> modbusRequests = ModbusUtil.getModbusRequests(targets);
        for (ModbusRequest request : modbusRequests) {
            String functionCode = request.getFunctionCode();
            String dataType = request.getDataType();
            int address = request.getStartAddress();
            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(ModbusRequest request) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        return ModbusUtil.getValues(request);
    }

    @Override
    public void setCoils(ModbusRequest request) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        int slaveId = request.getSlaveId();
        int address = request.getStartAddress();
        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(slaveId, address, data);
    }

    @Override
    public void setCoil(ModbusRequest request) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        int slaveId = request.getSlaveId();
        int address = request.getStartAddress();
        ModbusUtil.setCoilValue(slaveId, address, objToBoolean(request.getData().get(0)));
    }

    @Override
    public void setIntRegisters(ModbusRequest request) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        int slaveId = request.getSlaveId();
        int address = request.getStartAddress();
        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(slaveId, address, data);
    }

    @Override
    public void setIntRegister(ModbusRequest request) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        int slaveId = request.getSlaveId();
        int address = request.getStartAddress();
        ModbusUtil.setRegisterValue(slaveId, address, objToInt(request.getData().get(0)));
    }

    @Override
    public void setFloatRegisters(ModbusRequest request) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        int slaveId = request.getSlaveId();
        int address = request.getStartAddress();
        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(slaveId, address, data);
    }

    @Override
    public void setFloatRegister(ModbusRequest request) throws ModbusProtocolException, ModbusNumberException, ModbusIOException {
        int slaveId = request.getSlaveId();
        int address = request.getStartAddress();
        ModbusUtil.setRegisterFloatValue(slaveId, address, objToFloat(request.getData().get(0)));
    }


}