package com.njcn.csharmonic.service.impl;

import com.njcn.access.api.AskDeviceDataFeignClient;
import com.njcn.access.utils.MqttUtil;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.csdevice.api.CsLineFeignClient;
import com.njcn.csdevice.api.DataSetFeignClient;
import com.njcn.csdevice.api.EquipmentFeignClient;
import com.njcn.csdevice.pojo.po.CsDataSet;
import com.njcn.csdevice.pojo.po.CsEquipmentDeliveryPO;
import com.njcn.csdevice.pojo.po.CsLinePO;
import com.njcn.csharmonic.service.RealDataService;
import com.njcn.redis.utils.RedisUtil;
import com.njcn.system.api.DictTreeFeignClient;
import com.njcn.system.enums.DicDataEnum;
import com.njcn.web.utils.RequestUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author xuyang
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RealDataServiceImpl implements RealDataService {

    private final CsLineFeignClient csLineFeignClient;
    private final DataSetFeignClient dataSetFeignClient;
    private final AskDeviceDataFeignClient askDeviceDataFeignClient;
    private final EquipmentFeignClient equipmentFeignClient;
    private final RedisUtil redisUtil;
    private final MqttUtil mqttUtil;
    private final DictTreeFeignClient dictTreeFeignClient;

    @Override
    public boolean getBaseRealData(String lineId) {
        boolean result = false;
        try {
            //判断设备类型 治理无线设备需要判断mqtt、云前置设备直接判断设备运行状态
            CsEquipmentDeliveryPO dev = equipmentFeignClient.getDevByLineId(lineId).getData();
            String devModelCode = dictTreeFeignClient.queryById(dev.getDevType()).getData().getCode();
            if (Objects.equals(DicDataEnum.DEV_CLD.getCode(),devModelCode) && Objects.equals(dev.getDevAccessMethod(),"CLD")) {
                if (dev.getRunStatus() == 1) {
                    throw new BusinessException("装置离线");
                }
            } else {
                String clientName = "NJCN-" + dev.getNdid().substring(dev.getNdid().length() - 6);
                boolean mqttClient = mqttUtil.judgeClientOnline(clientName);
                if (!mqttClient) {
                    throw new BusinessException("装置离线");
                }
            }
            //获取装置所用模板
            CsLinePO po = csLineFeignClient.getById(lineId).getData();
            String modelId = po.getDataModelId();
            if (Objects.equals(DicDataEnum.DEV_CLD.getCode(),devModelCode) && Objects.equals(dev.getDevAccessMethod(),"CLD")) {
                CsDataSet csDataSet = dataSetFeignClient.getBaseDataSet(modelId,1).getData();
                askDeviceDataFeignClient.askCldRealData(dev.getId(),lineId,dev.getNodeId(),csDataSet.getIdx());
                updateRedisUserSet("rtDataUserId:" + lineId, RequestUtil.getUserIndex(), 600L);
                updateRedisUserSet("cldRtDataOverTime:" + lineId, RequestUtil.getUserIndex(), 5L);
            } else {
                CsDataSet csDataSet = dataSetFeignClient.getBaseDataSet(modelId,po.getClDid()).getData();
                askDeviceDataFeignClient.askRealData(dev.getNdid(),csDataSet.getIdx(),po.getClDid());
                redisUtil.saveByKeyWithExpire("rtDataUserId:"+lineId, RequestUtil.getUserIndex(),600L);
            }
            //等待装置响应,获取询问结果
            for (int i = 0; i < 5; i++) {
                Thread.sleep(1000);
                Object object;
                if (Objects.equals(DicDataEnum.DEV_CLD.getCode(),devModelCode) && Objects.equals(dev.getDevAccessMethod(),"CLD")) {
                    object = redisUtil.getObjectByKey("devResponse:" + lineId);
                } else {
                    object = redisUtil.getObjectByKey("devResponse:" + dev.getNdid());
                }
                if (Objects.isNull(object)) {
                    //throw new BusinessException("数据获取失败,设备无响应");
                } else {
                    int code = (Integer) object;
                    if (code != 200) {
                        //throw new BusinessException("数据获取失败,设备无响应");
                    } else {
                        result = true;
                        break;
                    }
                }
            }
        } catch (Exception e) {
            throw new BusinessException(e.getMessage());
        }
        return result;
    }

    @Override
    public boolean getHarmRealData(String lineId, Integer target) {
        boolean result = true;
        try {
            //判断设备类型 治理无线设备需要判断mqtt、云前置设备直接判断设备运行状态
            CsEquipmentDeliveryPO dev = equipmentFeignClient.getDevByLineId(lineId).getData();
            String devModelCode = dictTreeFeignClient.queryById(dev.getDevType()).getData().getCode();
            if (Objects.equals(DicDataEnum.DEV_CLD.getCode(),devModelCode) && Objects.equals(dev.getDevAccessMethod(),"CLD")) {
                if (dev.getRunStatus() == 1) {
                    throw new BusinessException("装置离线");
                }
            } else {
                String clientName = "NJCN-" + dev.getNdid().substring(dev.getNdid().length() - 6);
                boolean mqttClient = mqttUtil.judgeClientOnline(clientName);
                if (!mqttClient) {
                    throw new BusinessException("装置离线");
                }
            }
            //获取装置所用模板
            CsLinePO po = csLineFeignClient.getById(lineId).getData();
            String modelId = po.getDataModelId();
            //根据指标来获取不同的数据集
            if (Objects.equals(DicDataEnum.DEV_CLD.getCode(),devModelCode) && Objects.equals(dev.getDevAccessMethod(),"CLD")) {
                CsDataSet csDataSet = dataSetFeignClient.getHarmonicDataSet(modelId,1,target).getData();
                askDeviceDataFeignClient.askCldRealData(dev.getId(),lineId,dev.getNodeId(),csDataSet.getIdx());
            } else {
                CsDataSet csDataSet = dataSetFeignClient.getHarmonicDataSet(modelId,po.getClDid(),target).getData();
                askDeviceDataFeignClient.askRealData(dev.getNdid(),csDataSet.getIdx(),po.getClDid());
            }
            //等待装置响应,获取询问结果
            Thread.sleep(2000);
            Object object;
            if (Objects.equals(DicDataEnum.DEV_CLD.getCode(),devModelCode) && Objects.equals(dev.getDevAccessMethod(),"CLD")) {
                object = redisUtil.getObjectByKey("devResponse:" + lineId);
            } else {
                object = redisUtil.getObjectByKey("devResponse:" + dev.getNdid());
            }
            if (Objects.isNull(object)) {
                result = false;
            } else {
                int code = (Integer) object;
                if (code != 200) {
                    result = false;
                }
            }
        } catch (Exception e) {
            throw new BusinessException(e.getMessage());
        }
        return result;
    }

    /**
     * 更新Redis中的用户集合
     */
    private void updateRedisUserSet(String redisKey, String userIndex, Long expireSeconds) {
        try {
            Object redisObject = redisUtil.getObjectByKey(redisKey);
            Set<String> userSet = convertObjectToSetSafe(redisObject);
            userSet.add(userIndex);
            redisUtil.saveByKeyWithExpire(redisKey, userSet, expireSeconds);
        } catch (Exception e) {
            log.error("更新Redis用户集合失败，key: {}", redisKey, e);
        }
    }

    /**
     * 安全的对象到Set转换方法
     */
    private Set<String> convertObjectToSetSafe(Object obj) {
        if (obj == null) {
            return new HashSet<>();
        }
        if (obj instanceof Set) {
            // 类型安全的转换
            Set<?> rawSet = (Set<?>) obj;
            return rawSet.stream()
                    .filter(Objects::nonNull)
                    .map(Object::toString)
                    .collect(Collectors.toSet());
        } else if (obj instanceof Collection) {
            return ((Collection<?>) obj).stream()
                    .filter(Objects::nonNull)
                    .map(Object::toString)
                    .collect(Collectors.toSet());
        } else {
            log.warn("Redis中的对象类型不是Set或Collection: {}", obj.getClass().getName());
            return new HashSet<>();
        }
    }

}
