package com.ruoyi.business.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.shaded.com.google.gson.JsonObject;
import com.ruoyi.business.domain.HwDevice;
import com.ruoyi.business.domain.HwDeviceMode;
import com.ruoyi.business.domain.HwDeviceModeFunction;
import com.ruoyi.business.domain.HwScene;
import com.ruoyi.business.domain.VO.DeviceControlVo;
import com.ruoyi.business.domain.VO.DeviceModeVo;
import com.ruoyi.business.domain.VO.HwDeviceVo;
import com.ruoyi.business.mapper.HwDeviceMapper;
import com.ruoyi.business.mapper.HwDeviceModeFunctionMapper;
import com.ruoyi.business.mapper.HwDeviceModeMapper;
import com.ruoyi.business.mapper.HwSceneMapper;
import com.ruoyi.business.service.IHwDeviceService;
import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.core.constant.HwDictConstants;
import com.ruoyi.common.core.constant.TdEngineConstants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.enums.DataTypeEnums;
import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.NumberUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.datascope.annotation.DataScope;
import com.ruoyi.tdengine.api.RemoteTdEngineService;
import com.ruoyi.tdengine.api.domain.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 设备信息Service业务层处理
 *
 * @author xins
 * @date 2023-08-24
 */
@Service
public class HwDeviceServiceImpl implements IHwDeviceService {
    @Autowired
    private HwDeviceMapper hwDeviceMapper;
    @Autowired
    private HwDeviceModeMapper hwDeviceModeMapper;
    @Autowired
    private HwSceneMapper hwSceneMapper;
    @Autowired
    private HwDeviceModeFunctionMapper hwDevieModeFunctionMapper;
    @Resource
    private RemoteTdEngineService remoteTdEngineService;
    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 查询设备信息
     *
     * @param deviceId 设备信息主键
     * @return 设备信息
     */
    @Override
    public HwDevice selectHwDeviceByDeviceId(Long deviceId) {

        return hwDeviceMapper.selectHwDeviceByDeviceId(deviceId);
    }

    /**
     * 查询设备信息,返回监控单元名称
     *
     * @param deviceId 设备信息主键
     * @return 设备信息
     */

    @Override
    public HwDevice selectHwDeviceJoinByDeviceId(Long deviceId) {
        HwDevice device = hwDeviceMapper.selectHwDeviceJoinByDeviceId(deviceId);
        Long deviceModeId = device.getDeviceModeId();
        if (deviceModeId != null) {
            HwDeviceMode mode = hwDeviceModeMapper.selectHwDeviceModeByDeviceModeId(deviceModeId);
            device.setGpsFlag(mode != null ? mode.getGpsFlag() : HwDictConstants.DEVICEMODE_GPS_FLAG_NO);
        }
        return device;
    }

    /**
     * 查询设备信息列表
     *
     * @param hwDevice 设备信息
     * @return 设备信息
     */
    @Override
    @DataScope(tenantAlias = "hd")
    public List<HwDevice> selectHwDeviceList(HwDevice hwDevice) {
        return hwDeviceMapper.selectHwDeviceList(hwDevice);
    }

    /**
     * 查询关联设备信息列表
     *
     * @param deviceId 设备信息主键
     * @return 设备信息
     */
    @Override
    public List<HwDevice> selectLinkDeviceList(Long deviceId) {
        List<HwDevice> devices = hwDeviceMapper.selectLinkedDevices(deviceId);
        for (HwDevice device : devices) {
            device.setDevicePic("http://175.27.215.92:9665/statics/2023/09/23/6793e53d7418643c6ea9abe29be2bdce_20230923183352A001.jpg");
        }
        return devices;
    }

    /**
     * 新增设备信息
     *
     * @param hwDevice 设备信息
     * @return 结果
     */
    @Transactional
    @Override
    public int insertHwDevice(HwDevice hwDevice) {
        hwDevice.setCreateTime(DateUtils.getNowDate());
        String deviceType = hwDevice.getDeviceType();
        int deviceId = hwDeviceMapper.insertHwDevice(hwDevice);
        switch (deviceType) {
            case HwDictConstants.DEVICE_TYPE_GATEWAY_DEVICE:
                this.updateMqttAuth(hwDevice);
                break;
            case HwDictConstants.DEVICE_TYPE_DIRECT_CONNECT_DEVICE:
                this.updateMqttAuth(hwDevice);
                this.createTdTable(hwDevice);
                break;
            case HwDictConstants.DEVICE_TYPE_GATEWAY_SUB_EQUIPMENT:
                this.createTdTable(hwDevice);
                break;
            default:
                throw new ServiceException("Unknown device type: " + deviceType);
        }
        this.createTdDeviceStatusTable(hwDevice);
        return deviceId;
    }

    /**
     * @param: hwDevice
     * @description 更新redis中的设备信息
     * @author xins
     * @date 2023-09-19 10:06
     */
    private void updateMqttAuth(HwDevice hwDevice) {
        try {
            HwScene scene = hwSceneMapper.selectHwSceneBySceneId(hwDevice.getSceneId());
            String modeAccount = scene.getModeAccount();
            String modeKey = scene.getModeKey();
            if (StringUtils.isNotEmpty(modeAccount) && StringUtils.isNotEmpty(modeKey)) {
                String deviceInfoStr = redisTemplate.opsForValue().get(HwDictConstants.REDIS_KEY_DEVICE_INFO);
                JSONArray deviceInfoJsonArr = new JSONArray();
                if (StringUtils.isNotEmpty(deviceInfoStr)) {
                    deviceInfoJsonArr = JSON.parseArray(deviceInfoStr);
                }
                boolean redisUpdated = false;//是否更新已有的值
                for (Object deviceInfoObj : deviceInfoJsonArr) {
                    JSONObject deviceInfoJson = (JSONObject) deviceInfoObj;
                    if (deviceInfoJson.getString("deviceCode").equals(hwDevice.getDeviceCode())) {
                        deviceInfoJson.put("userName", modeAccount);
                        deviceInfoJson.put("password", modeKey);
                        redisUpdated = true;
                    }
                }

                if (!redisUpdated) {
                    JSONObject deviceInfoJson = new JSONObject();
                    deviceInfoJson.put("deviceCode", hwDevice.getDeviceCode());
                    deviceInfoJson.put("username", modeAccount);
                    deviceInfoJson.put("password", modeKey);
                    deviceInfoJsonArr.add(deviceInfoJson);
                }

                redisTemplate.opsForValue().set(HwDictConstants.REDIS_KEY_DEVICE_INFO, deviceInfoJsonArr.toString());
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * @param: hwDevice
     * @description 在tdengine创建table
     * @author xins
     * @date 2023-09-19 10:07
     */
    private void createTdTable(HwDevice hwDevice) {
        TdTableVo tdTableVo = new TdTableVo();
        String databaseName = TdEngineConstants.getDatabaseName(hwDevice.getSceneId());
        String superTableName = TdEngineConstants.getSuperTableName(hwDevice.getDeviceModeId());
        String tableName = TdEngineConstants.getDeviceDataTableName(hwDevice.getDeviceId());

        List<TdField> tagsFields = getTdTagsFields(hwDevice);

        tdTableVo.setDatabaseName(databaseName);
        tdTableVo.setSuperTableName(superTableName);
        tdTableVo.setTableName(tableName);
        tdTableVo.setTagsFieldValues(tagsFields);

        R<?> tdReturnMsg = this.remoteTdEngineService.createTable(tdTableVo);
        if (tdReturnMsg.getCode() != Constants.SUCCESS) {//抛出异常，回滚事务
            throw new RuntimeException(tdReturnMsg.getMsg());
        }
    }

    private void createTdDeviceStatusTable(HwDevice hwDevice) {
        TdTableVo tdTableVo = new TdTableVo();
        tdTableVo.setDatabaseName(TdEngineConstants.PLATFORM_DB_NAME);
        tdTableVo.setSuperTableName(TdEngineConstants.DEFAULT_DEVICE_STATUS_SUPER_TABLE_NAME);
        tdTableVo.setTableName(TdEngineConstants.getDeviceStatusTableName(hwDevice.getDeviceId()));

        List<TdField> tagsFields = getTdTagsFields(hwDevice);

        TdField sceneIdTag = new TdField();
        sceneIdTag.setFieldName(TdEngineConstants.ST_TAG_SCENEID);
        sceneIdTag.setFieldValue(hwDevice.getSceneId());
        tagsFields.add(sceneIdTag);

        tdTableVo.setTagsFieldValues(tagsFields);

        R<?> tdReturnMsg = this.remoteTdEngineService.createTable(tdTableVo);
        if (tdReturnMsg.getCode() != Constants.SUCCESS) {//抛出异常，回滚事务
            throw new RuntimeException(tdReturnMsg.getMsg());
        }
    }

    private List<TdField> getTdTagsFields(HwDevice hwDevice) {
        List<TdField> tagsFields = new ArrayList<>();

        TdField deviceIdTag = new TdField();
        deviceIdTag.setFieldName(TdEngineConstants.ST_TAG_DEVICEID);
        deviceIdTag.setFieldValue(hwDevice.getDeviceId());
        tagsFields.add(deviceIdTag);

        TdField deviceCodeTag = new TdField();
        deviceCodeTag.setFieldName(TdEngineConstants.ST_TAG_DEVICECODE);
        deviceCodeTag.setFieldValue(hwDevice.getDeviceCode());
        deviceCodeTag.setDataTypeCode(DataTypeEnums.NCHAR.getDataCode());
        tagsFields.add(deviceCodeTag);

        TdField deviceNameTag = new TdField();
        deviceNameTag.setFieldName(TdEngineConstants.ST_TAG_DEVICENAME);
        deviceNameTag.setFieldValue(hwDevice.getDeviceName());
        deviceNameTag.setDataTypeCode(DataTypeEnums.NCHAR.getDataCode());
        tagsFields.add(deviceNameTag);

        TdField deviceModeIdTag = new TdField();
        deviceModeIdTag.setFieldName(TdEngineConstants.ST_TAG_DEVICEMODEID);
        deviceModeIdTag.setFieldValue(hwDevice.getDeviceModeId());
        tagsFields.add(deviceModeIdTag);

        TdField monitorUnitIdTag = new TdField();
        monitorUnitIdTag.setFieldName(TdEngineConstants.ST_TAG_MONITORUNITID);
        monitorUnitIdTag.setFieldValue(hwDevice.getMonitorUnitId());
        tagsFields.add(monitorUnitIdTag);

        return tagsFields;
    }


    /**
     * 查询3.	设备各类型占所有设备数量百分比饼状图（左下角）
     */
    @Override
    public List<DeviceModeVo> selectDeviceModeNameVo() {
        List<DeviceModeVo> list = hwDeviceMapper.selectDeviceModeNameVo();
        Integer value = 0;
        if (list.size() > 10) {
            for (int i = 9; i < list.size(); i++) {
                if (list.get(i).sum == null) {
                    list.get(i).sum = 0;
                }
                value = value + list.get(i).sum;
            }
        }
//        DeviceModeVo hwMonitorUnitTypeVo = new DeviceModeVo();
//        hwMonitorUnitTypeVo.setDeviceModeName("其他");
//        hwMonitorUnitTypeVo.setSum(value);
        Integer sums = 0;
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).sum == null) {
                list.get(i).sum = 0;
            }
            sums = sums + list.get(i).sum;
        }
        for (int i = 0; i < list.size(); i++) {
            list.get(i).setPercentage(NumberUtils.getPercentage(list.get(i).getSum(), sums));
            System.out.println(list.get(i).toString());
        }


        return list;
//        if (list.size() > 10) {
//            list.add(10, hwMonitorUnitTypeVo);
//            return list.subList(0, 10);
//        } else {
//            return list;
//        }
    }


    /**
     * 修改设备信息
     *
     * @param hwDevice 设备信息
     * @return 结果
     */
    @Transactional
    @Override
    public int updateHwDevice(HwDevice hwDevice) {
        HwDevice dbDevice = hwDeviceMapper.selectHwDeviceByDeviceId(hwDevice.getDeviceId());
        if (dbDevice.getDeviceStatus().equals(HwDictConstants.DEVICE_STATUS_PUBLISH)) {
            throw new ServiceException("已发布状态不能修改");
        }
        hwDevice.setUpdateTime(DateUtils.getNowDate());
        int rows = hwDeviceMapper.updateHwDevice(hwDevice);
        this.updateTdEngine(hwDevice, dbDevice);
        return rows;
    }

    /**
     * 修改设备状态
     *
     * @param hwDevice 设备信息
     * @return 结果
     */
    @Override
    public int changeDeviceStatus(HwDevice hwDevice) {
        HwDevice dbDevice = hwDeviceMapper.selectHwDeviceByDeviceId(hwDevice.getDeviceId());
        if (dbDevice.getDeviceStatus().equals(HwDictConstants.DEVICE_STATUS_PUBLISH)) {
            throw new ServiceException("已发布状态不能修改");
        }
        hwDevice.setUpdateTime(DateUtils.getNowDate());
        return hwDeviceMapper.updateHwDevice(hwDevice);
    }

    /**
     * @param: deviceControlVo
     * @description 下发当网关，主题带设备编号
     * @author xins
     * @date 2023-09-25 14:56
     */
    @Override
    public void publishControlCommand(DeviceControlVo deviceControlVo) {
        JSONObject controlCommandJson = new JSONObject();
        StringBuilder controlCommandTopic = new StringBuilder();
        Long deviceId = deviceControlVo.getDeviceId();
        HwDevice device = hwDeviceMapper.selectHwDeviceByDeviceId(deviceId);
        String deviceType = device.getDeviceType();
        if (deviceType.equals(HwDictConstants.DEVICE_TYPE_GATEWAY_SUB_EQUIPMENT)) {
            Long gatewayDeviceId = device.getReleatedDeviceId();
            HwDevice gatewayDevice = hwDeviceMapper.selectHwDeviceByDeviceId(gatewayDeviceId);
            controlCommandTopic.append(StringUtils
                    .format(HwDictConstants.CONTROL_COMMAND_TOPIC_VALUE, gatewayDevice.getDeviceCode()));
        } else {
            controlCommandTopic.append(StringUtils
                    .format(HwDictConstants.CONTROL_COMMAND_TOPIC_VALUE, device.getDeviceCode()));
        }
        JSONObject payloadJson = new JSONObject();
        payloadJson.put(HwDictConstants.CONTROL_COMMAND_PAYLOAD_MID_KEY, device.getDeviceCode());
        payloadJson.put(HwDictConstants.CONTROL_COMMAND_PAYLOAD_TIMESTAMP_KEY, System.currentTimeMillis() / 1000);//单位：s
        payloadJson.put(HwDictConstants.CONTROL_COMMAND_PAYLOAD_TYPE_KEY, deviceControlVo.getType());
        payloadJson.put(HwDictConstants.CONTROL_COMMAND_PAYLOAD_PARAM_KEY, "{}");

        controlCommandJson.put(HwDictConstants.CONTROL_COMMAND_TOPIC_KEY, controlCommandTopic.toString());
        controlCommandJson.put(HwDictConstants.CONTROL_COMMAND_PAYLOAD_KEY, payloadJson.toString());

        System.out.println("---" + controlCommandJson.toString());
        redisTemplate.convertAndSend(HwDictConstants.CONTROL_COMMAND_REDIS_KEY, controlCommandJson.toString());
    }


    /**
     * @param: hwDevice 前端传的对象
     * @param: dbDevice 目前数据库的对象
     * @description 更新TdEngine数据库tag
     * @author xins
     * @date 2023-09-19 10:55
     */
    private void updateTdEngine(HwDevice hwDevice, HwDevice dbDevice) {
        String deviceType = hwDevice.getDeviceType();
        String databaseName = TdEngineConstants.getDatabaseName(hwDevice.getSceneId());
        String tableName = TdEngineConstants.getDeviceDataTableName(hwDevice.getDeviceId());
        AlterTagVo alterTagVo = new AlterTagVo();
        alterTagVo.setDatabaseName(databaseName);
        alterTagVo.setTableName(tableName);
        R<?> tdReturnMsg;
        if (deviceType.equals(HwDictConstants.DEVICE_TYPE_DIRECT_CONNECT_DEVICE)
                || deviceType.equals(HwDictConstants.DEVICE_TYPE_GATEWAY_SUB_EQUIPMENT)) {
            if (!hwDevice.getDeviceCode().equals(dbDevice.getDeviceCode())) {
                alterTagVo.setTagName(TdEngineConstants.ST_TAG_DEVICECODE);
                alterTagVo.setTagValue("'" + hwDevice.getDeviceCode() + "'");

                tdReturnMsg = this.remoteTdEngineService.alterTableTag(alterTagVo);
                if (tdReturnMsg.getCode() != Constants.SUCCESS) {//抛出异常，回滚事务
                    throw new RuntimeException(tdReturnMsg.getMsg());
                }
            }
            if (!hwDevice.getDeviceName().equals(dbDevice.getDeviceName())) {
                alterTagVo.setTagName(TdEngineConstants.ST_TAG_DEVICENAME);
                alterTagVo.setTagValue("'" + hwDevice.getDeviceName() + "'");
                tdReturnMsg = this.remoteTdEngineService.alterTableTag(alterTagVo);
                if (tdReturnMsg.getCode() != Constants.SUCCESS) {//抛出异常，回滚事务
                    throw new RuntimeException(tdReturnMsg.getMsg());
                }
            }

            if (!hwDevice.getMonitorUnitId().equals(dbDevice.getMonitorUnitId())) {
                alterTagVo.setTagName(TdEngineConstants.ST_TAG_MONITORUNITID);
                alterTagVo.setTagValue(hwDevice.getMonitorUnitId());
                tdReturnMsg = this.remoteTdEngineService.alterTableTag(alterTagVo);
                if (tdReturnMsg.getCode() != Constants.SUCCESS) {//抛出异常，回滚事务
                    throw new RuntimeException(tdReturnMsg.getMsg());
                }
            }

            if (!hwDevice.getDeviceModeId().equals(dbDevice.getDeviceModeId())) {
                alterTagVo.setTagName(TdEngineConstants.ST_TAG_DEVICEMODEID);
                alterTagVo.setTagValue(hwDevice.getDeviceModeId());
                tdReturnMsg = this.remoteTdEngineService.alterTableTag(alterTagVo);
                if (tdReturnMsg.getCode() != Constants.SUCCESS) {//抛出异常，回滚事务
                    throw new RuntimeException(tdReturnMsg.getMsg());
                }
            }
        }
    }

    /**
     * 批量删除设备信息
     *
     * @param deviceIds 需要删除的设备信息主键
     * @return 结果
     */
    @Override
    public int deleteHwDeviceByDeviceIds(Long[] deviceIds) {
        return hwDeviceMapper.deleteHwDeviceByDeviceIds(deviceIds);
    }

    /**
     * 删除设备信息信息
     *
     * @param deviceId 设备信息主键
     * @return 结果
     */
    @Override
    public int deleteHwDeviceByDeviceId(Long deviceId) {
        return hwDeviceMapper.deleteHwDeviceByDeviceId(deviceId);
    }


    /**
     * @return Map<String, List < HwDeviceVo>>
     * @description 设备监测页面，根据监控单元获取设备监控信息
     * @author xins
     * @date 2023-09-15 16:59
     */
    @Override
    public Map<String, List<HwDeviceVo>> getDevicesByMonitor(HwDevice queryHwDevice) {
        Map<String, List<HwDeviceVo>> devicesMap = new HashMap<String, List<HwDeviceVo>>();
        List<HwDeviceVo> controlDeviceVos = new ArrayList<HwDeviceVo>();
        List<HwDeviceVo> acquisitionDeviceVos = new ArrayList<HwDeviceVo>();
        Long sceneId = queryHwDevice.getSceneId();
        String databaseName = TdEngineConstants.getDatabaseName(sceneId);

        queryHwDevice.setDeviceType(HwDictConstants.DEVICE_TYPE_GATEWAY_SUB_EQUIPMENT);
        List<HwDevice> hwDevices = hwDeviceMapper.selectHwDeviceList(queryHwDevice);
        hwDevices.forEach(hwDevice -> {
            Long deviceId = hwDevice.getDeviceId();
            HwDeviceModeFunction queryDeviceModeFunction = new HwDeviceModeFunction();
            queryDeviceModeFunction.setDeviceModeId(hwDevice.getDeviceModeId());
            List<HwDeviceModeFunction> deviceModeFunctions = hwDevieModeFunctionMapper.selectHwDeviceModeFunctionList(queryDeviceModeFunction);

            String tableName = TdEngineConstants.getDeviceDataTableName(deviceId);
            TdSelectDto tdSelectDto = new TdSelectDto();
            tdSelectDto.setDatabaseName(databaseName);
            tdSelectDto.setTableName(tableName);
            List<TdField> schemaFieldValues = new ArrayList<TdField>();
            List<HwDeviceModeFunction> modeFunctions = new ArrayList<>();

            deviceModeFunctions.forEach(mf -> {
                if (mf.getFunctionMode().equals(HwDictConstants.FUNCTION_MODE_ATTRIBUTE)) {
                    TdField field = new TdField();
                    field.setFieldName(mf.getFunctionIdentifier());
                    schemaFieldValues.add(field);
                } else if (mf.getFunctionMode().equals(HwDictConstants.FUNCTION_MODE_SERVICE)) {
                    modeFunctions.add(mf);
                }

            });
            tdSelectDto.setSchemaFieldValues(schemaFieldValues);
            //从tdengine获取此设备的最新数据
            List<Map<String, Object>> deviceLatestDataMapList =
                    (List<Map<String, Object>>) this.remoteTdEngineService.getLatestData(tdSelectDto).getData();


            //获取此设备模型的功能列表
            //获取可控制设备：根据功能是属性的并且属性的数据类型是tinyint类型的（bool类型开关就是用tinyint），并且是读写的
//            List<HwDeviceModeFunction> dds = deviceModeFunctions.stream()
//                    .filter(dmf -> dmf.getFunctionMode().equals(HwDictConstants.FUNCTION_MODE_ATTRIBUTE)
//                            && dmf.getDataType() != null
//                            && String.valueOf(dmf.getDataType())
//                            .equals(String.valueOf(DataTypeEnums.TINYINT.getDataCode()))
//                            && dmf.getRwFlag()!=null
//                            && dmf.getRwFlag().equals(HwDictConstants.RW_FLAG_RW)
//                    ).collect(Collectors.toList());

            //转换成map，key为标识符，value为功能名称（主要tdengine存的是标识符，用来下面转换成功能名称）
            Map<String, String> functionIndentifierName = deviceModeFunctions.stream().collect(
                    Collectors.toMap(HwDeviceModeFunction::getFunctionIdentifier, HwDeviceModeFunction::getFunctionName));

            //获取可控制设备，根据是否有服务判断
//            List<HwDeviceModeFunction> modeFunctions = deviceModeFunctions.stream()
//                    .filter(dmf -> dmf.getFunctionMode().equals(HwDictConstants.FUNCTION_MODE_SERVICE)
//                    ).collect(Collectors.toList());

            if (modeFunctions != null && modeFunctions.size() > 0) {
                modeFunctions.forEach(modeFunction -> {
                    HwDeviceVo hwDeviceVo = new HwDeviceVo();
                    hwDeviceVo.setDeviceId(deviceId);
                    hwDeviceVo.setDeviceType(HwDictConstants.CONTROL_DEVICE);
                    hwDeviceVo.setDeviceCode(hwDevice.getDeviceCode());
                    hwDeviceVo.setDeviceName(hwDevice.getDeviceName());
                    hwDeviceVo.setDeviceModeFunction(modeFunction);
                    controlDeviceVos.add(hwDeviceVo);
                });
            }

            //将functionIdetifier转换成功能名称
            Map<String, Object> ddValueMap = new HashMap<String, Object>();
            if (deviceLatestDataMapList != null) {
                deviceLatestDataMapList.forEach(deviceLatestDataMap -> {
                    Set<String> functionIdentifiers = deviceLatestDataMap.keySet();
                    for (String dataFunctionIdentifier : functionIdentifiers) {
                        if (functionIndentifierName.get(dataFunctionIdentifier) != null) {
                            ddValueMap.put(functionIndentifierName.get(dataFunctionIdentifier),
                                    deviceLatestDataMap.get(dataFunctionIdentifier));
                        }
                    }

                });
            }
            //不论是否是控制型设备都显示最新数据
            HwDeviceVo hwDeviceVo = new HwDeviceVo();
            hwDeviceVo.setDeviceId(deviceId);
            hwDeviceVo.setDeviceModeId(hwDevice.getDeviceModeId());
            hwDeviceVo.setDeviceCode(hwDevice.getDeviceCode());
            hwDeviceVo.setDeviceName(hwDevice.getDeviceName());
            hwDeviceVo.setDeviceType(HwDictConstants.ACQUISITION_DEVICE);
            hwDeviceVo.setDeviceDataMap(ddValueMap);
            acquisitionDeviceVos.add(hwDeviceVo);

        });

        devicesMap.put(HwDictConstants.CONTROL_DEVICE_NAME, controlDeviceVos);
        devicesMap.put(HwDictConstants.ACQUISITION_DEVICE_NAME, acquisitionDeviceVos);

        return devicesMap;
    }


    /**
     * 查询设备信息列表,join监控单元、设备模型等表
     *
     * @param hwDevice 设备信息
     * @return 设备信息
     */
    @Override
    @DataScope(tenantAlias = "hd")
    public List<HwDevice> selectHwDeviceJoinList(HwDevice hwDevice) {
        return hwDeviceMapper.selectHwDeviceJoinList(hwDevice);
    }


    /**
     * @param: days
     * @description 计算前几天的设备在线数量
     * @author xins
     * @date 2023-09-20 19:28
     */
    @Override
    public void computeOnlineDevicecCount(int days) {
        JSONObject jsonObject = new JSONObject();
        for (int i = 1; i <= days; i++) {

            Date currentDate = new Date();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(currentDate);
            calendar.add(Calendar.DAY_OF_MONTH, -i);
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            Long startTime = calendar.getTimeInMillis();//先是昨天 00:00
            calendar.set(Calendar.HOUR_OF_DAY, 23);
            calendar.set(Calendar.MINUTE, 59);
            calendar.set(Calendar.SECOND, 59);
            Long endTime = calendar.getTimeInMillis();//23:59.59
            Map<Long, Integer> onlineDeviceCountPerDay = computeDeviceCountPerDay(startTime, endTime);
            Set<Long> times = onlineDeviceCountPerDay.keySet();
            for (Long key : times) {
                jsonObject.put(String.valueOf(key), onlineDeviceCountPerDay.get(key));
            }
        }
        redisTemplate.opsForValue().set(HwDictConstants.REDIS_KEY_ONLINE_DEVICE_COUNT_INFO, jsonObject.toString());
    }

    private Map<Long, Integer> computeDeviceCountPerDay(Long startTime, Long endTime) {
        //先增加需要查询的字段名称（由于tdengine用last和last_row查询时字段显示有bug，所以需要设置要查询的字段）
        List<TdField> schemaFields = new ArrayList<TdField>();
        TdField deviceTypeField = new TdField();
        deviceTypeField.setFieldName(TdEngineConstants.ST_TAG_DEVICETYPE);

        TdField onlineStatusField = new TdField();
        onlineStatusField.setFieldName(TdEngineConstants.ST_TAG_ONLINESTATUS);

        schemaFields.add(deviceTypeField);
        schemaFields.add(onlineStatusField);

        DeviceStatus queryGroupStatus = new DeviceStatus();
        queryGroupStatus.setStartTime(startTime);
        queryGroupStatus.setEndTime(endTime);
        queryGroupStatus.setSchemaFields(schemaFields);

        DeviceStatus queryLastStatus = new DeviceStatus();
        queryLastStatus.setEndTime(startTime);
        queryLastStatus.setSchemaFields(schemaFields);

//        System.out.println(DateUtils.dateTime(new Date(startTime)) + "----" + DateUtils.dateTime(new Date(endTime)));
        Map<Long, Integer> onlineDeviceCountByDay = new HashMap<Long, Integer>();

        //先获取starttime和endtime时间范围内在线的设备状态信息
        Map<Long, List<DeviceStatus>> groupDeviceStatuMapList =
                (Map<Long, List<DeviceStatus>>) this.remoteTdEngineService.getOnlineDevicesGroupByDay(queryGroupStatus).getData();
        if (groupDeviceStatuMapList == null) {
            groupDeviceStatuMapList = new HashMap<>();
        }

        //获取在endtime之前最后的设备状态信息（有些设备会一直在线，没有连续的上线下线记录，所以要获取最近的设备状态信息来补齐后面的设备在线情况）
        List<Map<String, Object>> lastDeviceStatuMapList =
                (List<Map<String, Object>>) this.remoteTdEngineService.getLastOnlineDevices(queryLastStatus).getData();
        if (lastDeviceStatuMapList == null || lastDeviceStatuMapList.isEmpty()) {
            onlineDeviceCountByDay.put(startTime, 0);
        } else {
            for (Map<String, Object> groupDeviceStatuMap : lastDeviceStatuMapList) {
                DeviceStatus ds = new DeviceStatus();
                for (Map.Entry<String, Object> entry : groupDeviceStatuMap.entrySet()) {
                    switch (entry.getKey()) {
                        case TdEngineConstants.ST_TAG_DEVICEID:
                            ds.setDeviceId((long) (Integer) entry.getValue());
                            break;
                        case TdEngineConstants.ST_TAG_DEVICETYPE:
                            ds.setDeviceType((Integer) entry.getValue());
                            break;
                        case TdEngineConstants.ST_TAG_ONLINESTATUS:
                            ds.setOnlineStatus((Integer) entry.getValue());
                            break;
                        default:
                            break;
                    }
                }

                List<DeviceStatus> dss = groupDeviceStatuMapList.get(ds.getDeviceId());
                int count = 0;
                if (dss == null) {
                    if (String.valueOf(ds.getOnlineStatus())
                            .equals(HwDictConstants.DEVICE_ONLINE_STATUS_ONLINE)) {
                        count = this.getDeviceCount(ds);
                    }
                } else {
                    count = this.getDeviceCount(dss.get(0));
                }

                if (onlineDeviceCountByDay.get(startTime) == null) {
                    onlineDeviceCountByDay.put(startTime, count);
                } else {
                    onlineDeviceCountByDay.put(startTime, onlineDeviceCountByDay.get(startTime) + count);
                }
            }
        }

        return onlineDeviceCountByDay;
    }

    private int getDeviceCount(DeviceStatus ds) {
        String deviceType = String.valueOf(ds.getDeviceType());
        if (deviceType.equals(HwDictConstants.DEVICE_TYPE_GATEWAY_DEVICE)) {
            HwDevice queryDevice = new HwDevice();
            queryDevice.setReleatedDeviceId(ds.getDeviceId());
            List<HwDevice> deviceList = hwDeviceMapper.selectHwDeviceList(queryDevice);
            return deviceList == null ? 0 : deviceList.size();
        } else {
            return 1;
        }
    }


    /**
     * @return String
     * @param: sceneId
     * @description 获取最近几天在线设备数量
     * @author xins
     * @date 2023-09-21 9:09
     */
    @Override
    public JSONObject getOnlineDevicesCount(Long sceneId) {
        JSONObject returnObj = new JSONObject();
        int onlineDevicesCount = hwDeviceMapper.getOnlineDeviceNum(sceneId);

        JSONObject sortedJsonObject = new JSONObject();

        String onlineDeviceCountJsonStr = redisTemplate.opsForValue().get(HwDictConstants.REDIS_KEY_ONLINE_DEVICE_COUNT_INFO);
        if (onlineDeviceCountJsonStr != null) {
            JSONObject jsonObject = JSONObject.parseObject(onlineDeviceCountJsonStr);

            jsonObject.forEach((key, value) -> {
                String dateStrKey = DateUtils.parseDateToStr(DateUtils.MM_DD, new Date(Long.parseLong(key)));
                sortedJsonObject.put(dateStrKey, value);
            });
        }

        returnObj.put("onlineDevicesTrend", sortedJsonObject);
        returnObj.put("onlineDevicesCount", onlineDevicesCount);
        return returnObj;
    }


}
