package com.ruoyi.system.iot.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.constant.IotConstants;
import com.ruoyi.common.core.domain.entity.User;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.core.redis.RedisLock;
import com.ruoyi.common.core.redis.enums.RedisLockKey;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.common.utils.onenet.CreateDeviceVo;
import com.ruoyi.common.utils.onenet.Token;
import com.ruoyi.ss.commandLog.service.ICommandLogService;
import com.ruoyi.ss.device.domain.Device;
import com.ruoyi.ss.device.domain.enums.DeviceCommand;
import com.ruoyi.ss.device.domain.enums.DeviceOnlineStatus;
import com.ruoyi.ss.device.domain.enums.DevicePowerStatus;
import com.ruoyi.ss.device.domain.vo.DeviceVO;
import com.ruoyi.ss.device.service.DeviceService;
import com.ruoyi.system.iot.domain.CurrentDeviceData;
import com.ruoyi.system.iot.domain.HistoryDeviceData;
import com.ruoyi.system.iot.domain.IotDeviceDetail;
import com.ruoyi.system.iot.domain.IotDeviceInfo;
import com.ruoyi.system.iot.domain.response.CommandResponse;
import com.ruoyi.system.iot.domain.response.CurrentDataPointResponse;
import com.ruoyi.system.iot.domain.response.DetailResponse;
import com.ruoyi.system.iot.domain.response.HistoryDataPointResponse;
import com.ruoyi.system.iot.enums.IotHttpStatus;
import com.ruoyi.system.iot.interfaces.IotDevice;
import com.ruoyi.system.iot.service.IotConverter;
import com.ruoyi.system.iot.service.IotService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author qzz
 * 2024/3/20
 */
@Service
@Slf4j
public class IotServiceImpl implements IotService {
    @Value("${sm.iotHost}")
    private String iotHost;

    @Value(value = "${sm.version}")
    private String version;

    @Value(value = "${sm.resourceName}")
    private String resourceName;

    @Value(value = "${sm.accessKey}")
    private String accessKey;

    @Value(value = "${sm.timeout}")
    private Integer timeout;

    @Autowired
    private IotConverter iotConverter;

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private RedisLock redisLock;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private ICommandLogService commandLogService;

    // 查询OneNet设备在线状态
    @Override
    public String getOnlineStatus(String deviceName, String productId) {
        if (StringUtils.isAnyBlank(deviceName, productId)) {
            return DeviceOnlineStatus.OFFLINE.getStatus();
        }
//        if (IotConstants.ONLINE_TYPE_COMMAND.equals(type)) {
            // 加锁，防止第一次会有多个请求进入
            boolean lock = redisLock.lock(RedisLockKey.DEVICE_ONLINE_COMMAND, deviceName);
            try {
                if (lock) {
//                    log.info("进入lock");
                    // 从缓存获取上次的在线状态，若不存在，则发命令，防止短时间发送命令过于频繁
                    String cacheKey = CacheConstants.DEVICE_ONLINE_STATUS + deviceName;
                    String incrementCacheKey = CacheConstants.DEVICE_OFFLINE_INCREMENT + deviceName;
                    String status = redisCache.getCacheObject(cacheKey);
                    if (StringUtils.isBlank(status)) {
//                        log.info("进入command");
                        // 发送命令
                        CommandResponse res = uploadData(deviceName, productId, "获取在线状态");

                        // 若是离线，则直接返回离线
                        if (res != null && res.isNotOnline()) {
                            status = DeviceOnlineStatus.OFFLINE.getStatus();
                        }
                        // 若是命令超时，则累加redis数据，超过3次则判断为离线
                        else if (res == null || res.isCmdTimeout()) {
                            long offlineCount = redisCache.incrementCacheValue(incrementCacheKey, 60, TimeUnit.SECONDS);
                            if (offlineCount >= 3) {
                                status = DeviceOnlineStatus.OFFLINE.getStatus();
                            } else {
                                status = DeviceOnlineStatus.ONLINE.getStatus();
                            }
                        }
                        // 若命令发送成功，则清空redis累加数据
                        else if (res.isSuccess()) {
                            status = DeviceOnlineStatus.ONLINE.getStatus();
                            redisCache.deleteObject(incrementCacheKey);
                        }

                        // 缓存结果10秒
                        redisCache.setCacheObject(cacheKey, status, 10, TimeUnit.SECONDS);
                    }

                    return status;
                } else {
                    return null;
                }
            } finally {
                if (lock) {
                    redisLock.unlock(RedisLockKey.DEVICE_ONLINE_COMMAND, deviceName);
                }
            }
//        } else {
//            IotDeviceDetail detail = this.getDeviceDetail(deviceName, productId);
//            if (detail == null) {
//                return DeviceOnlineStatus.OFFLINE.getStatus();
//            }
//            return IotDeviceDetail.Status.toDeviceOnlineStatus(detail.getStatus());
//        }
    }

//    private CommandResponse uploadData(String deviceName, String productId, String reason) {
//        if (StringUtils.isBlank(deviceName) || StringUtils.isBlank(productId)) {
//            return null;
//        }
//        return sendCommand(deviceName, IotConstants.COMMAND_UPLOAD_DATA, productId,reason);
//    }

    @Override
    public String getOnlineStatus(IotDevice device) {
        String status = DeviceOnlineStatus.OFFLINE.getStatus();
        if (device == null || StringUtils.isBlank(device.getProductId())) {
            return status;
        }
        // 优先使用mac1判断
        if (StringUtils.hasText(device.iotMac1())) {
            status = this.getOnlineStatus(device.iotMac1(), device.getProductId());
        }
        // 若还是离线，则判断mac2是否在线
        if (!Objects.equals(status, DeviceOnlineStatus.ONLINE.getStatus()) && StringUtils.hasText(device.iotMac1())) {
            status = this.getOnlineStatus(device.iotMac2(), device.getProductId());
        }
        return status;
    }

    // 通电
    @Override
    public CommandResponse open(String deviceName, String productId,String reason) {
        if (StringUtils.hasBlank(deviceName, productId)) {
            return null;
        }
        return sendCommand(deviceName, IotConstants.COMMAND_OPEN, productId,reason);
    }

    // 断电
    @Override
    public CommandResponse close(String deviceName, String productId,String reason) {
        if (StringUtils.hasBlank(deviceName, productId)) {
            return null;
        }
        return sendCommand(deviceName, IotConstants.COMMAND_CLOSE, productId,reason);
    }

    /**
     * returnMac  是否返回mac
     */
    @Override
    public boolean open(IotDevice device,boolean isIgnore,String reason, boolean returnMac) {
        boolean result = false;
        if (device == null || StringUtils.isBlank(device.getProductId())) {
            return result;
        }

        // 尝试用mac1通电
        try {
            CommandResponse response = this.open(device.iotMac1(), device.getProductId(),reason);
            IotHttpStatus status = IotHttpStatus.convertByCode(response.getCode());
            if (!IotHttpStatus.SUCCESS.equals(status) && !isIgnore) {
                log.error("【{}】mac1通电失败：{}", device.iotMac1(), status.getMsg());
                if (returnMac) {
                    throw new ServiceException(device.iotMac1(), 501);
                } else {
                    throw new ServiceException("通电发生异常：" + status.getMsg());
                }
            }
            // 如果状态不是成功但忽略异常，则直接返回true
            if (!IotHttpStatus.SUCCESS.equals(status)) {
                return true;
            }

            // 更新设备状态
            updateStatus(device.getDeviceId(), DevicePowerStatus.ON.getStatus());

            return true;
        } catch (Exception e) {
            log.info("mac1通电失败，尝试用mac2通电");
            try {
                if (!StringUtils.isAnyBlank(device.iotMac2(), device.getProductId())) {
                    CommandResponse response = this.open(device.iotMac2(), device.getProductId(), reason);
                    IotHttpStatus status = IotHttpStatus.convertByCode(response.getCode());

                    // 如果状态不是成功，并且不忽略异常
                    if (!IotHttpStatus.SUCCESS.equals(status) && !isIgnore) {
                        if (returnMac) {
                            throw new ServiceException(device.iotMac1(), 501);
                        } else {
                            throw new ServiceException("mac2通电失败：" + status.getMsg());
                        }
                    }

                    // 如果状态不是成功但忽略异常，则直接返回true
                    if (!IotHttpStatus.SUCCESS.equals(status)) {
                        return true;
                    }

                    // 更新设备状态
                    updateStatus(device.getDeviceId(), DevicePowerStatus.ON.getStatus());

                    return true;
                } else {
                    throw e;
                }
            } catch (Exception ex) {
                // 如果mac2也失败了，并且不忽略异常
                if (!isIgnore) {
                    if (returnMac) {
                        throw new ServiceException(device.iotMac1(), 501);
                    } else {
                        throw new ServiceException("mac2通电失败：" + ex.getMessage());
                    }
                }
                return true; // 忽略异常，直接返回true
            }
        }
    }

//    @Override
//    public boolean open(IotDevice device, boolean isIgnore, String reason, boolean returnMac) {
//        if (device == null || StringUtils.isBlank(device.getProductId())) {
//            return false;
//        }
//
//        // 尝试用mac1通电
//        boolean mac1Success = tryOpenDevice(device.iotMac1(), device.getProductId(), device.getDeviceId(), isIgnore, reason, returnMac);
//        if (mac1Success) {
//            return true;
//        }
//
//        // 如果mac1通电失败，尝试用mac2通电
//        log.info("mac1通电失败，尝试用mac2通电");
//        return tryOpenDevice(device.iotMac2(), device.getProductId(), device.getDeviceId(), isIgnore, reason, returnMac);
//    }
//
//    private boolean tryOpenDevice(String mac, String productId, Long deviceId, boolean isIgnore, String reason, boolean returnMac) {
//        if (StringUtils.isBlank(mac) || StringUtils.isBlank(productId)) {
//            return false;
//        }
//
//        try {
//            CommandResponse response = this.open(mac, productId, reason);
//            IotHttpStatus status = IotHttpStatus.convertByCode(response.getCode());
//
//            if (!IotHttpStatus.SUCCESS.equals(status)) {
//                if (!isIgnore) {
//                    // 如果不忽略异常，记录日志并抛出异常
//                    log.error("【{}】通电失败：{}", mac, status.getMsg());
//                    handleFailure(mac, status.getMsg(), returnMac);
//                }
//                return false; // 返回false表示通电失败
//            }
//
//            // 更新设备状态
//            updateStatus(deviceId, DevicePowerStatus.ON.getStatus());
//            return true; // 返回true表示通电成功
//        } catch (Exception e) {
//            if (!isIgnore) {
//                // 如果不忽略异常，记录日志并抛出异常
//                log.error("【{}】通电失败：{}", mac, e.getMessage());
//                handleFailure(mac, e.getMessage(), returnMac);
//            }
//            return false; // 返回false表示通电失败
//        }
//    }
//
//    private void handleFailure(String mac, String errorMsg, boolean returnMac) {
//        if (returnMac) {
//            throw new ServiceException(mac, 501);
//        } else {
//            throw new ServiceException("通电失败：" + errorMsg);
//        }
//    }

    private void updateStatus(Long deviceId,String status) {
        Device device1 = new Device();
        device1.setPowerStatus(status);
        device1.setDeviceId(deviceId);
        int i = deviceService.updateSmDevice(device1);
        ServiceUtil.assertion(i == 0 ,"更新设备状态失败");
    }

    // 断电
    @Override
    public boolean close(String deviceName, String productId,boolean isIgnore,String reason) {
        if (StringUtils.isAnyBlank(deviceName, productId)) {
            return false;
        }
        CommandResponse response = sendCommand(deviceName, IotConstants.COMMAND_CLOSE, productId,reason);
        IotHttpStatus status = IotHttpStatus.convertByCode(response.getCode());
        if (!IotHttpStatus.SUCCESS.equals(status) && !isIgnore) {
            log.error("断电发生异常：{}, {}", deviceName, status.getMsg());
            throw new ServiceException("断电发生异常：" + status.getMsg());
        }
        return true;
    }

    @Override
    public boolean close(IotDevice device,boolean isIgnore,String reason, boolean returnMac) {
        boolean result = false;
        if (device == null || StringUtils.isBlank(device.getProductId())) {
            return result;
        }

        // 尝试用mac1通电
        try {
            CommandResponse response = this.close(device.iotMac1(), device.getProductId(),reason);
            IotHttpStatus status = IotHttpStatus.convertByCode(response.getCode());
            if (!IotHttpStatus.SUCCESS.equals(status) && !isIgnore) {
                log.error("【{}】mac1断电失败：{}", device.iotMac1(), status.getMsg());
                if (returnMac) {
                    throw new ServiceException(device.iotMac1(), 501);
                } else {
                    throw new ServiceException("断电发生异常：" + status.getMsg());
                }
            }
            // 如果状态不是成功但忽略异常，则直接返回true
            if (!IotHttpStatus.SUCCESS.equals(status)) {
                return true;
            }

            // 更新设备状态
            updateStatus(device.getDeviceId(), DevicePowerStatus.OFF.getStatus());

            return true;
        } catch (Exception e) {
            log.info("mac1断电失败，尝试用mac2断电");
            try {
                if (!StringUtils.isAnyBlank(device.iotMac2(), device.getProductId())) {
                    CommandResponse response = this.close(device.iotMac2(), device.getProductId(), reason);
                    IotHttpStatus status = IotHttpStatus.convertByCode(response.getCode());

                    // 如果状态不是成功，并且不忽略异常
                    if (!IotHttpStatus.SUCCESS.equals(status) && !isIgnore) {
                        if (returnMac) {
                            throw new ServiceException(device.iotMac1(), 501);
                        } else {
                            throw new ServiceException("mac2断电失败：" + status.getMsg());
                        }
                    }

                    // 如果状态不是成功但忽略异常，则直接返回true
                    if (!IotHttpStatus.SUCCESS.equals(status)) {
                        return true;
                    }

                    // 更新设备状态
                    updateStatus(device.getDeviceId(), DevicePowerStatus.ON.getStatus());

                    return true;
                } else {
                    throw e;
                }
            } catch (Exception ex) {
                // 如果mac2也失败了，并且不忽略异常
                if (!isIgnore) {
                    if (returnMac) {
                        throw new ServiceException(device.iotMac1(), 501);
                    } else {
                        throw new ServiceException("mac2断电失败：" + ex.getMessage());
                    }
                }
                return true; // 忽略异常，直接返回true
            }
        }
    }
//
//    @Override
//    public boolean close(IotDevice device,boolean isIgnore,String reason,boolean returnMac) {
//        boolean result = false;
//        if (device == null || StringUtils.isBlank(device.getProductId())) {
//            return result;
//        }
//
//        // 尝试用mac1断电
//        try {
//            result = this.close(device.iotMac1(), device.getProductId(),isIgnore,reason);
//            if (!result) {
//                throw new ServiceException("mac1断电失败");
//            }
//        } catch (Exception e) {
//            log.info("mac1断电失败:{}，尝试用mac2断电", e.getMessage());
//            if (!StringUtils.isAnyBlank(device.iotMac2(), device.getProductId())) {
//                result = this.close(device.iotMac2(), device.getProductId(),isIgnore,reason);
//            } else {
//                throw e;
//            }
//        }
//        // 更新设备状态
//        updateStatus(device.getDeviceId(),DevicePowerStatus.OFF.getStatus());
//
//        return result;
//    }

    // 获取历史设备数据点信息
    @Override
    public HistoryDeviceData getHistoryDataPoint(String deviceName, String productId) {
        String param = "device_name=" + deviceName + "&product_id=" + productId;
        String sendUrl = iotHost + IotConstants.ADDS_HISTORY_DATAPOINTS + "?"+param;

        String token = Token.getToken();
        String result = HttpUtils.sendGetWithToken(sendUrl, null, token);

        if (!StringUtils.hasText(result)) {
            log.error("与OneNet通信异常");
            return null;
        }
        HistoryDataPointResponse response = JSONObject.parseObject(result, HistoryDataPointResponse.class);
        if (!IotHttpStatus.SUCCESS.getCode().equals(response.getCode())) {
            log.error("获取历史设备数据点信息出错：" + response.getMsg());
            return null;
        }
        return response.getData();
    }

    @Override
    public int setTimeAndEle(IotDevice device, long seconds, BigDecimal ele) {
        try {
            int result1 = this.setTimeAndEle(device.iotMac1(), device.getProductId(), seconds, ele);
            ServiceUtil.assertion(result1 != 1, "mac1设置时间与电量失败");
            return result1;
        } catch (Exception e) {
            int result2 = this.setTimeAndEle(device.iotMac2(), device.getProductId(), seconds, ele);
            ServiceUtil.assertion(result2 != 1, "设置时间与电量失败" );
            return result2;
        }
    }

    @Override
    public int setTimeAndEle(String mac, String productId, long seconds, BigDecimal ele) {
        if (StringUtils.isAnyBlank(mac, productId) || ele == null) {
            return 0;
        }
        StringBuilder sb = new StringBuilder();
        sb.append(IotConstants.COMMAND_TIME).append(seconds).append(IotConstants.COMMAND_SEPARATOR)
                .append(IotConstants.COMMAND_SET_ELE).append(ele.multiply(BigDecimal.valueOf(1000))).append(IotConstants.COMMAND_SEPARATOR);
        CommandResponse res = sendCommand(mac, sb.toString(), productId, "设置时间与电量");
        return res.isSuccess() ? 1 : 0;
    }

    // 获取当前设备数据点信息
    public List<CurrentDeviceData> getCurrentDataPoint(List<String> deviceNames, String productId) {
        String param = "device_name=" + String.join(",", deviceNames) + "&product_id=" + productId;
        String sendUrl = iotHost+ IotConstants.ADDS_CURRENT_DATAPOINTS + "?" + param;

        String result = HttpUtils.sendGetWithToken(sendUrl, null, Token.getToken());

        log.info("IOT返回的结果【{}】", result);
        if (!StringUtils.hasText(result)) {
            log.error("与OneNet通信异常");
            return Collections.emptyList();
        }
        CurrentDataPointResponse response = JSONObject.parseObject(result, CurrentDataPointResponse.class);
        if (!IotHttpStatus.SUCCESS.getCode().equals(response.getCode())) {
            log.error("获取当前设备数据点信息出错：" + response.getMsg());
            return Collections.emptyList();
        }

        return response.getData().getDevices();
    }

    // 获取当前设备数据点信息
    private CurrentDeviceData getCurrentDataPoint(String deviceName, String productId) {
        List<CurrentDeviceData> list = this.getCurrentDataPoint(Collections.singletonList(deviceName), productId);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        return list.stream().filter(item -> Objects.equals(item.getTitle(), deviceName)).findFirst().orElse(null);
    }

    private IotDeviceDetail getDeviceDetail(String deviceName, String productId) {
        String sendUrl = iotHost + IotConstants.ADDS_DEVICE_DETAIL;
        String param = "device_name=" + deviceName + "&product_id=" + productId;

        String token = Token.getToken();
//        log.info("IOT获取到Authorization:【{}】",token);
        String result = HttpUtils.sendGetWithToken(sendUrl, param, token);

        if (!StringUtils.hasText(result)) {
            log.error("与OneNet通信异常");
            return null;
        }
        DetailResponse response = JSONObject.parseObject(result, DetailResponse.class);
        if (!IotHttpStatus.SUCCESS.getCode().equals(response.getCode())) {
            log.error("获取当前设备数据点信息出错：{}", response.getMsg());
            return null;
        }

        return response.getData();
    }

    /**
     * 设置通电时长
     *
     * @param deviceName 设备名称
     * @param seconds    时长（秒）
     * @param productId
     * @return 是否成功
     */
    @Override
    public CommandResponse setTime(String deviceName, long seconds, String productId,String reason) {
        if (seconds < 0) {
            throw new ServiceException("设置通电时长参数错误：读数不允许小于0");
        }
        return sendCommand(deviceName, IotConstants.COMMAND_TIME + seconds + IotConstants.COMMAND_SEPARATOR, 5, productId,reason);
    }

    /**
     * 设置断电时长
     *
     * @param deviceName 设备名称
     * @param seconds    时长（秒）
     * @param productId
     * @return 是否成功
     */
    @Override
    public CommandResponse setTtme(String deviceName, long seconds, String productId,String reason) {
        if (seconds < 0) {
            throw new ServiceException("设置断电时长参数错误：读数不允许小于0");
        }
        return sendCommand(deviceName, IotConstants.COMMAND_REVERSE_TTME + seconds + IotConstants.COMMAND_SEPARATOR, 5, productId,reason);
    }

    @Override
    public CommandResponse setTime(IotDevice device, long seconds,String reason) {
        if (device == null || StringUtils.isBlank(device.getProductId())) {
            throw new ServiceException("设置时长错误：参数不允许为空");
        }

        CommandResponse res = null;
        if (StringUtils.hasText(device.iotMac1())) {
            res = this.setTime(device.iotMac1(), seconds, device.getProductId(),reason);
        }
        if ((res == null || !res.isSuccess()) && StringUtils.hasText(device.iotMac2())) {
            res = this.setTime(device.iotMac2(), seconds, device.getProductId(),reason);
        }

        return res;
    }

    /**
     * 开门
     *
     * @param device 设备名称
     * @param seconds 时长（秒）
     * @param reason 原因
     */
    @Override
    public CommandResponse km(IotDevice device, long seconds,String reason, boolean returnMac) {
        CommandResponse res = null;
        // 尝试用mac1开门
        try {
            if (device == null || StringUtils.isBlank(device.getProductId())) {
                throw new ServiceException("【开门】参数不允许为空");
            }

            if (StringUtils.hasText(device.iotMac1())) {
                res = sendCommand(device.iotMac1(), IotConstants.COMMAND_OPEN_DOOR + seconds + IotConstants.COMMAND_SEPARATOR, 5, device.getProductId(), reason);
            }

            IotHttpStatus status = null;
            if (res != null) {
                status = IotHttpStatus.convertByCode(res.getCode());
            }
            if (!IotHttpStatus.SUCCESS.equals(status)) {
                log.error("【{}】mac1开门失败：{}", device.iotMac1(), status.getMsg());
                if (returnMac) {
                    throw new ServiceException(device.iotMac1(), 501);
                } else {
                    throw new ServiceException("【开门】发送异常：" + status.getMsg());
                }
            }
        } catch (Exception e) {
            log.info("mac1开门失败，尝试用mac2开门");
            if ((res == null || !res.isSuccess()) && StringUtils.hasText(device.iotMac2())) {
                res = sendCommand(device.iotMac2(), IotConstants.COMMAND_OPEN_DOOR + seconds + IotConstants.COMMAND_SEPARATOR, 5, device.getProductId(), reason);
            }
            IotHttpStatus status = null;
            if (res != null) {
                status = IotHttpStatus.convertByCode(res.getCode());
            }
            if (!IotHttpStatus.SUCCESS.equals(status)) {
                log.error("【{}】mac2开门失败：{}", device.iotMac1(), status.getMsg());
                if (returnMac) {
                    throw new ServiceException(device.iotMac1(), 501);
                } else {
                    throw new ServiceException("【开门】发送异常：" + status.getMsg());
                }
            }
        }
        return res;
    }

    /**
     * 关门
     *
     * @param device 设备名称
     * @param seconds 时长（秒）
     * @param reason 原因
     */
    @Override
    public CommandResponse gm(IotDevice device, long seconds,String reason, boolean returnMac){
        if (device == null || StringUtils.isBlank(device.getProductId())) {
            throw new ServiceException("【关门】参数不允许为空");
        }

        if (seconds < 0) {
            throw new ServiceException("【关门】时间不允许小于0");
        }
        CommandResponse res = null;
        if (StringUtils.hasText(device.iotMac1())) {
            res = sendCommand(device.iotMac1(), IotConstants.COMMAND_REVERSE_DOOR + seconds + IotConstants.COMMAND_SEPARATOR, 5, device.getProductId(), reason);
        }
        if ((res == null || !res.isSuccess()) && StringUtils.hasText(device.iotMac2())) {
            res = sendCommand(device.iotMac2(), IotConstants.COMMAND_REVERSE_DOOR + seconds + IotConstants.COMMAND_SEPARATOR, 5, device.getProductId(), reason);
        }

        return res;
    }

    @Override
    public CommandResponse setTtme(IotDevice device, long seconds, String reason) {
        if (device == null || StringUtils.isBlank(device.getProductId())) {
            throw new ServiceException("设置时长错误：参数不允许为空");
        }

        CommandResponse res = null;
        if (StringUtils.hasText(device.iotMac1())) {
            res = this.setTtme(device.iotMac1(), seconds, device.getProductId(),reason);
        }
        if ((res == null || !res.isSuccess()) && StringUtils.hasText(device.iotMac2())) {
            res = this.setTtme(device.iotMac2(), seconds, device.getProductId(),reason);
        }

        return res;
    }


    @Override
    public CommandResponse addEle(String deviceName, BigDecimal ele, String productId) {
        if (ele == null || ele.compareTo(BigDecimal.ZERO) < 0) {
            throw new ServiceException("充值电量错误：充值电量不允许小于0");
        }
        return sendCommand(deviceName, IotConstants.COMMAND_ADD_ELE + ele.multiply(BigDecimal.valueOf(1000)) + IotConstants.COMMAND_SEPARATOR, 5, productId,"");
    }

    @Override
    public CommandResponse addEle(IotDevice device, BigDecimal ele) {
        if (device == null || StringUtils.isBlank(device.getProductId())) {
            throw new ServiceException("充值电量错误：参数不允许为空");
        }

        CommandResponse res = null;
        if (StringUtils.hasText(device.iotMac1())) {
            res = this.addEle(device.iotMac1(), ele, device.getProductId());
        }
        if ((res == null || !res.isSuccess()) && StringUtils.hasText(device.iotMac2())) {
            res = this.addEle(device.iotMac2(), ele, device.getProductId());
        }

        return res;
    }

    @Override
    public CommandResponse setEle(String deviceName, BigDecimal ele, String productId) {
        if (ele == null) {
            throw new ServiceException("设置电量错误：电量不允许为空");
        }
        return sendCommand(deviceName, IotConstants.COMMAND_SET_ELE + ele.multiply(BigDecimal.valueOf(1000)) + IotConstants.COMMAND_SEPARATOR, 5, productId,"");
    }

    @Override
    public CommandResponse setEle(IotDevice device, BigDecimal ele) {
        if (device == null || StringUtils.isBlank(device.getProductId())) {
            throw new ServiceException("设置电量错误：参数不允许为空");
        }

        CommandResponse res = null;
        if (StringUtils.hasText(device.iotMac1())) {
            res = this.setEle(device.iotMac1(), ele, device.getProductId());
        }
        if ((res == null || !res.isSuccess()) && StringUtils.hasText(device.iotMac2())) {
            res = this.setEle(device.iotMac2(), ele, device.getProductId());
        }

        return res;
    }

    @Override
    public IotDeviceInfo getDeviceInfo(String deviceName, String productId) {
        if (StringUtils.isAnyBlank(deviceName, productId)) {
            return null;
        }
        CurrentDeviceData currentDataPoint = getCurrentDataPoint(deviceName, productId);
        if (currentDataPoint == null) {
            return null;
        }
        return iotConverter.toIotDeviceInfo(currentDataPoint, null);
    }

    @Override
    public IotDeviceInfo getDeviceInfo(IotDevice device) {
        if (device == null || StringUtils.isBlank(device.getProductId())) {
            return null;
        }

        CurrentDeviceData data1 = getCurrentDataPoint(device.iotMac1(), device.getProductId());
        CurrentDeviceData data2 = getCurrentDataPoint(device.iotMac2(), device.getProductId());

        return iotConverter.toIotDeviceInfo(data1, data2);
    }

    @Override
    public List<IotDeviceInfo> getDeviceInfo(List<? extends IotDevice> deviceList, String productId) {
        if (CollectionUtils.isEmpty(deviceList)) {
            return Collections.emptyList();
        }

        // 获取数据点列表
        List<String> macList = CollectionUtils.map(deviceList, IotDevice::iotMac1);
        macList.addAll(CollectionUtils.map(deviceList, IotDevice::iotMac2));
        List<CurrentDeviceData> dataList = getCurrentDataPoint(macList, productId);
        if (CollectionUtils.isEmpty(dataList)) {
            return Collections.emptyList();
        }

        // 构造返回数据
        List<IotDeviceInfo> result = new ArrayList<>();
        for (IotDevice device : deviceList) {
            CurrentDeviceData data1 = dataList.stream().filter(item -> Objects.equals(device.iotMac1(), item.getTitle())).findFirst().orElse(null);
            CurrentDeviceData data2 = dataList.stream().filter(item -> Objects.equals(device.iotMac2(), item.getTitle())).findFirst().orElse(null);
            IotDeviceInfo iotDeviceInfo = iotConverter.toIotDeviceInfo(data1, data2);
            if (iotDeviceInfo != null) {
                result.add(iotDeviceInfo);
            }
        }

        return result;
    }

    @Override
    public int create(String mac, String productId) {
        String sendUrl = iotHost + IotConstants.CREATE_DEVICE;
        CreateDeviceVo createDeviceVo = new CreateDeviceVo();
        createDeviceVo.setDevice_name(mac);
        createDeviceVo.setProduct_id(productId);
        String result = HttpUtils.sendPostWithToken(sendUrl, JSON.toJSONString(createDeviceVo), Token.getToken());
        if (!StringUtils.hasText(result)) {
            log.error("与OneNet通信异常");
            return HttpStatus.NOT_FOUND;
        }
        JSONObject paramsObj = JSON.parseObject(result);
        return paramsObj.getInteger("code");
    }

    private CommandResponse sendCommand(String deviceName, String command, String productId,String reason) {
        return sendCommand(deviceName, command, null, productId,reason);
    }

    // 发送MQTT命令
    private CommandResponse sendCommand(String deviceName, String command, Integer timeout, String productId,String reason) {
        if (timeout == null) {
            timeout = this.timeout;
        }
        String sendUrl = iotHost + IotConstants.ADDS_COMMAND;
        String param = "device_name=" + deviceName + "&product_id=" + productId +"&timeout=" + timeout;
        sendUrl = sendUrl  + "?" + param;
        String token = Token.getToken();
        try {
            // 发送命令
            String result = HttpUtils.sendPostWithToken(sendUrl, command, token);
            ServiceUtil.assertion(!StringUtils.hasText(result), "与OneNet通信异常");
            CommandResponse res = JSON.parseObject(result, CommandResponse.class);

            // 记录成功日志
            this.addCommandLog(deviceName, command, res.getMsg(), reason, res.getCode());

            // 若返回数据为离线或者超时，则判断设备是否在线
//            if (IotHttpStatus.checkOnlineList().contains(res.getCode())) {
//                deviceService.checkOnlineByCommandLogSync(deviceName);
//            }
            return res;
        } catch (Exception e) {
            this.addCommandLog(deviceName, command, "操作失败：" + e.getMessage(), reason, null);
            throw e;
        }
    }

    // 异步添加日志
    private void addCommandLog(String deviceName, String command, String result, String reason, Integer iotCode) {
        LoginUser loginUser = null;
        try {
            loginUser = SecurityUtils.getLoginUser();
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        commandLogService.asynchronousSaveLog(command,deviceName, result, reason, loginUser, iotCode);
    }

    @Override
    public CommandResponse trySetTime(IotDevice device, long seconds, int tryCount,String reason) {
        CommandResponse res = this.setTime(device, seconds,reason);
        if (res == null || !res.isSuccess()) {
            if (tryCount > 0) {
                try {
                    Thread.sleep(1000);
                    return trySetTime(device, seconds, --tryCount,reason);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return res;
    }

    @Override
    public CommandResponse trySetEle(IotDevice device, BigDecimal ele, int tryCount) {
        CommandResponse res = this.setEle(device, ele);
        if (res == null || !res.isSuccess()) {
            if (tryCount > 0) {
                try {
                    Thread.sleep(1000);
                    return trySetEle(device, ele, --tryCount);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return res;
    }

    @Override
    public CommandResponse setWifi(IotDevice device, String wifiName, String wifiPwd) {

        CommandResponse res = null;
        if (StringUtils.hasText(device.iotMac1())) {
            res = this.setWifi(device.iotMac1(), device.getProductId(), wifiName, wifiPwd);
        }
        if ((res == null || !res.isSuccess()) && StringUtils.hasText(device.iotMac2())) {
            res = this.setWifi(device.iotMac2(), device.getProductId(), wifiName, wifiPwd);
        }

        return res;
    }

    @Override
    public CommandResponse setWifi(String mac, String productId, String wifiName, String wifiPwd) {
        if (StringUtils.hasBlank(mac, productId)) {
            return null;
        }
        CommandResponse res1 = sendCommand(mac, IotConstants.COMMAND_SET_SSID + wifiName + IotConstants.COMMAND_SEPARATOR, productId,"");
        if (res1.isSuccess()) {
            return sendCommand(mac, IotConstants.COMMAND_SET_PASS + wifiPwd + IotConstants.COMMAND_SEPARATOR, productId,"");
        }
        return null;
    }

    @Override
    public boolean setVoice(IotDevice device, long seconds) {
        if (device == null) {
            return false;
        }

        try {
            boolean res = this.setVoice(device.iotMac1(), device.getProductId(), seconds);
            ServiceUtil.assertion(!res, "设备MAC1设置语音播报时间失败");
            return true;
        } catch (Exception e) {
            log.warn("设备MAC1设置语音播报时间失败: {}", e.getMessage());
            return this.setVoice(device.iotMac2(), device.getProductId(), seconds);
        }
    }

    @Override
    public boolean setVoice(String mac, String productId, long seconds) {
        if (StringUtils.isBlank(mac) || StringUtils.isBlank(productId)) {
            return false;
        }
        CommandResponse res = this.sendCommand(mac, IotConstants.COMMAND_SET_VOICE + seconds + IotConstants.COMMAND_SEPARATOR, productId,"设置语音播报失败");
        ServiceUtil.assertion(!res.isSuccess(), "设置语音播报失败：" + res.getMsg());
        return res.isSuccess();
    }

    @Override
    public boolean setTotalEle(IotDevice device, BigDecimal totalEle) {
        if (device == null || totalEle.compareTo(BigDecimal.ZERO) < 0) {
            return false;
        }

        try {
            boolean res = this.setTotalEle(device.iotMac1(), device.getProductId(), totalEle);
            ServiceUtil.assertion(!res, "设备MAC1设置总电量失败");
            return res;
        } catch (Exception e) {
            log.warn("设备MAC1设置总电量失败: {}", e.getMessage());
            return this.setTotalEle(device.iotMac2(), device.getProductId(), totalEle);
        }
    }

    @Override
    public boolean setTotalEle(String deviceName, String productId, BigDecimal totalEle) {
        if (StringUtils.isAnyBlank(deviceName, productId)) {
            return false;
        }
        if (totalEle.compareTo(BigDecimal.ZERO) < 0) {
            return false;
        }

        CommandResponse res = this.sendCommand(deviceName, IotConstants.COMMAND_SET_TOTAL_ELE + totalEle + IotConstants.COMMAND_SEPARATOR, productId,"设置总电量失败");
        return res != null && res.isSuccess();
    }

    @Override
    public CommandResponse setVxs(DeviceVO device, BigDecimal vxs, String reason) {
        ServiceUtil.assertion(device == null || vxs == null, "设备或参数为空");

        CommandResponse res = null;
        if (StringUtils.hasText(device.iotMac1())) {
            res = this.setVxs(device.iotMac1(), vxs, device.getProductId(), reason);
        }
        if ((res == null || !res.isSuccess()) && StringUtils.hasText(device.iotMac2())) {
            res = this.setVxs(device.iotMac2(), vxs, device.getProductId(), reason);
        }

        return res;
    }

    @Override
    public CommandResponse uploadData(IotDevice device, String reason, boolean recordLog) {
        ServiceUtil.assertion(device == null || StringUtils.isBlank(device.getProductId()), "设备为空");
        CommandResponse res = null;
        if (StringUtils.hasText(device.iotMac2())) {
            res = this.uploadData(device.iotMac2(), device.getProductId(), reason);
        }
        if ((res == null || !res.isSuccess()) && StringUtils.hasText(device.iotMac1())) {
            res = this.uploadData(device.iotMac1(), device.getProductId(), reason);
        }
        return res;
    }

    private CommandResponse uploadData(String deviceName, String productId, String reason) {
        if (StringUtils.isBlank(deviceName) || StringUtils.isBlank(productId)) {
            return null;
        }
        return sendCommand(deviceName, IotConstants.COMMAND_UPLOAD_DATA, productId,reason);
    }


    private CommandResponse setVxs(String deviceName, BigDecimal vxs, String productId, String reason) {
        if (StringUtils.isBlank(deviceName) || vxs == null || productId == null) {
            return null;
        }
        String command = IotConstants.COMMAND_SET_VXS + vxs + IotConstants.COMMAND_SEPARATOR;
        return sendCommand(deviceName, command, productId,reason);
    }

    /**
     * 重启设备
     */
    @Override
    public CommandResponse reboot(IotDevice device, String reason) {
        if (device == null || StringUtils.isBlank(device.getProductId())) {
            return null;
        }
        CommandResponse res = null;
        if (StringUtils.hasText(device.iotMac2())) {
            res = reboot(device.iotMac2(),  device.getProductId(), reason);
        }
        if ((res == null || !res.isSuccess()) && StringUtils.hasText(device.iotMac1())) {
            res = reboot(device.iotMac1(), device.getProductId(), reason);
        }
        return res;
    }

    /**
     * 开门
     */
    @Override
    public CommandResponse openDoor(IotDevice device, String reason, boolean open) {
        if (device == null || StringUtils.isBlank(device.getProductId())) {
            return null;
        }
        CommandResponse res = null;
        if (StringUtils.hasText(device.iotMac2())) {
            res = openDoor(device.iotMac2(),  device.getProductId(), reason,open);
        }
        if ((res == null || !res.isSuccess()) && StringUtils.hasText(device.iotMac1())) {
            res = openDoor(device.iotMac1(), device.getProductId(), reason,open);
        }
        return res;
    }

    private CommandResponse reboot(String deviceName, String productId, String reason) {
        if (StringUtils.isAnyBlank(deviceName, productId)) {
            return null;
        }
        String command = IotConstants.COMMAND_REBOOT;
        return sendCommand(deviceName, command, productId, reason);
    }

    private CommandResponse openDoor(String deviceName, String productId, String reason, boolean open) {
        if (StringUtils.isAnyBlank(deviceName, productId)) {
            return null;
        }
        String command;
        if(open){
            command = IotConstants.COMMAND_OPEN_DOOR +"5";
        }else{
            command = IotConstants.COMMAND_REVERSE_DOOR +"5";
        }
        return sendCommand(deviceName, command, productId, reason);
    }
}
