package com.ruoyi.bst.device.service.impl;

import com.alibaba.fastjson2.JSON;
import com.ruoyi.bst.device.domain.Device;
import com.ruoyi.bst.device.domain.DeviceVO;
import com.ruoyi.bst.device.domain.enums.DeviceOnlineStatus;
import com.ruoyi.bst.device.domain.enums.DevicePowerStatus;
import com.ruoyi.bst.device.mapper.DeviceMapper;
import com.ruoyi.bst.device.service.DeviceIotService;
import com.ruoyi.bst.device.utils.DeviceUtils;
import com.ruoyi.bst.model.domain.enums.ModelTag;
import com.ruoyi.common.exception.ServiceException;
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.Token;
import com.ruoyi.iot.constants.IotConstants;
import com.ruoyi.iot.domain.IotDeviceInfo;
import com.ruoyi.iot.domain.response.CommandResponse;
import com.ruoyi.iot.interfaces.IotDevice;
import com.ruoyi.iot.service.IotService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DeviceIotServiceImpl implements DeviceIotService {

    @Autowired
    private IotService iotService;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private ScheduledExecutorService scheduledExecutorService;
    @Autowired
    private TransactionTemplate transactionTemplate;

    public DeviceVO selectById(Long deviceId){
        return deviceMapper.selectDeviceByDeviceId(deviceId);
    }

    @Override
    public void pullDeviceInfo(Long deviceId, String onlineType) {
        DeviceVO device = selectById(deviceId);
        pullDeviceInfo(device, onlineType);
    }


    @Override
    public void pullDeviceInfo(DeviceVO device, String onlineType) {
        this.pullDeviceInfoList(Collections.singletonList(device), onlineType);
    }


    @Override
    public void pullDeviceInfoList(List<DeviceVO> list, String onlineType) {
        if (CollectionUtils.isEmptyElement(list)) {
            return;
        }

        // 列表根据产品ID分组
        Map<String, List<DeviceVO>> group = list.stream()
                .filter(item -> StringUtils.hasText(item.getDeviceProductId()))
                .collect(Collectors.groupingBy(DeviceVO::getDeviceProductId));

        for (Map.Entry<String, List<DeviceVO>> entry : group.entrySet()) {

            // 批量获取设备信息
            List<DeviceVO> groupDeviceList = entry.getValue();
            String productId = entry.getKey();
            List<IotDeviceInfo> iotList = iotService.getDeviceInfo(groupDeviceList, productId);

            // 构造更新设备信息
            for (DeviceVO device : groupDeviceList) {
                // 获取数据点信息
                IotDeviceInfo deviceInfo = iotList.stream()
                        .filter(item -> Objects.equals(device.getMac(), item.getMac()) || Objects.equals(device.getMac2(), item.getMac()))
                        .findFirst().orElse(null);

                // 更新设备信息
                this.setDeviceInfo(device, deviceInfo);

            }
        }

        // 异步更新设备信息
        for (DeviceVO device : list) {
            scheduledExecutorService.schedule(() -> {
                if (StringUtils.hasText(onlineType)) {
                    // 获取并设置在线状态
                    this.setOnlineStatus(device, onlineType);
                }
                // 更新数据库
                this.updateIotInfo(device);
            }, 0, TimeUnit.SECONDS);
        }
    }



    private void setDeviceInfo(DeviceVO device, IotDeviceInfo iot) {
        if (device == null || iot == null) {
            return;
        }
        device.setLastPullTime(iot.getAt());
        device.setPowerStatus(iot.getS());
        device.setRemainTime(iot.getTime());
        device.setRealTimePower(iot.getP());
        device.setVoltage(iot.getV());
        device.setElectricity(iot.getA());
        device.setVersion(iot.getVersion());
        device.setVxs(iot.getVxs());
        device.setImsi(iot.getImsi());
        device.setSet(iot.getSet());
        device.setWxs(iot.getWxs());

        // 判断是否支持WIFI，支持则更新
        if (ModelTag.hasTag(device.getModelTags(), ModelTag.WIFI)) {
            device.setWifi(iot.getWifi());
        }

        // 判断是否支持电量，支持则更新
        if (ModelTag.hasTag(device.getModelTags(), ModelTag.ELE)) {
            device.setSurplusEle(iot.getM());
        } else {
            device.setSurplusEle(BigDecimal.ZERO);
        }

        // 总用电量
        if (iot.getW() != null) {
            // 若有数据点中的值大于数据库中的值，则更新
            if (iot.getW().compareTo(device.getTotalElectriQuantity()) >= 0) {
                device.setTotalElectriQuantity(iot.getW());
            }
            // 若数据点小于数据库中的值，则发命令恢复物联网设备的总用电量
            else {
                scheduledExecutorService.schedule(() -> {
                    String reason = "拉取设备信息时，恢复总用电量,数据库值:" + device.getTotalElectriQuantity() + "，OneNet值：" + iot.getW();
                    iotService.setTotalEle(device, device.getTotalElectriQuantity().multiply(new BigDecimal(1000)), reason);
                }, 0, TimeUnit.SECONDS);
            }
        }
    }


    private void setOnlineStatus(DeviceVO device, String onlineType) {
        // 是否在线
        String onlineStatus1 = iotService.getOnlineStatus(device.getMac(), device.getProductId(), onlineType);
        String onlineStatus2 = iotService.getOnlineStatus(device.getMac2(), device.getProductId(), onlineType);

        // 若有一个没获取到锁，则不更新状态
        boolean unlockMac1 = StringUtils.isNotBlank(device.getMac()) && onlineStatus1 == null;
        boolean unlockMac2 = StringUtils.isNotBlank(device.getMac2()) && onlineStatus2 == null;
        if (unlockMac1 || unlockMac2){
            device.setOnlineStatus(null);
            device.setOnlineStatus1(null);
            device.setOnlineStatus2(null);
            device.setLastOnlineTime(null);
        } else {
            device.setOnlineStatus1(onlineStatus1);
            device.setOnlineStatus2(onlineStatus2);
            if (DeviceOnlineStatus.ONLINE.getStatus().equals(onlineStatus1) || DeviceOnlineStatus.ONLINE.getStatus().equals(onlineStatus2)) {
                device.setOnlineStatus(DeviceOnlineStatus.ONLINE.getStatus());
                device.setLastOnlineTime(LocalDateTime.now());
            } else {
                device.setOnlineStatus(DeviceOnlineStatus.OFFLINE.getStatus());
            }
        }
    }

    @Override
    public int updateOnlineStatusByMac(String mac, String status) {
        if (StringUtils.isAnyBlank(mac, status)) {
            return 0;
        }
        return deviceMapper.updateOnlineStatusByMac(mac, status);
    }


    /**
     * 更新物联网信息
     */
    private int updateIotInfo(Device device) {
        Device data = new Device();
        data.setDeviceId(device.getDeviceId());
        data.setLastPullTime(device.getLastPullTime());
        data.setTotalElectriQuantity(device.getTotalElectriQuantity());
        data.setPowerStatus(device.getPowerStatus());
        data.setRemainTime(device.getRemainTime());
        data.setRealTimePower(device.getRealTimePower());
        data.setVoltage(device.getVoltage());
        data.setElectricity(device.getElectricity());
        data.setWifi(device.getWifi());
        data.setSurplusEle(device.getSurplusEle());
        data.setStatus(device.getStatus());
        data.setOnlineStatus(device.getOnlineStatus());
        data.setOnlineStatus1(device.getOnlineStatus1());
        data.setOnlineStatus2(device.getOnlineStatus2());
        data.setLastOnlineTime(device.getLastOnlineTime());
        data.setVersion(device.getVersion());
        data.setImsi(device.getImsi());
        data.setSet(device.getSet());
        data.setWxs(device.getWxs());
        return deviceMapper.updateDevice(data);
    }

//    @Override
//    public int resetWithBill(Long deviceId, boolean requiredIot, BigDecimal totalEle, String reason, boolean withTime, boolean withEle) {
//        ServiceUtil.assertion(deviceId == null, "设备id不能为空");
//
//        // 获取设备信息
//        DeviceVO device = deviceMapper.selectDeviceByDeviceId(deviceId);
//        ServiceUtil.assertion(device == null || device.getDeleted(), "设备不存在");
//        // 拉取最新设备信息
//        pullDeviceInfo(device, null);
//
//        // 关闭未完成订单
//        this.closeNotFinishedBill(device, totalEle);
//
//        Integer result = transactionTemplate.execute(status -> {
//            // 修改数据库设备信息
//            Device data = new Device();
//            data.setDeviceId(deviceId);
//            data.setStatus(DeviceStatus.NORMAL.getStatus());
//            if (withTime) {
//                data.setExpireTime(LocalDateTime.now());
//            }
//            if (withEle) {
//                data.setSurplusEle(BigDecimal.ZERO);
//                data.setExpireEle(device.getTotalElectriQuantity());
//            }
//            data.setUserOperaType(DeviceUserOperaType.RESET.getType());
//            data.setUserOperaEle(device.getTotalElectriQuantity());
//            data.setUserOperaTime(LocalDateTime.now());
//            int update = deviceMapper.updateSmDevice(data);
//            ServiceUtil.assertion(update != 1, "更新设备%s信息失败", device.getDeviceNo());
//
//            // 发送命令
//            if (withTime) {
//                CommandResponse res = iotService.setTime(device, 0L, reason);
//                if (requiredIot) {
//                    ServiceUtil.assertion(res == null, "归零电量失败，返回值为空");
//                    ServiceUtil.assertion(!res.isSuccess(), "归零电量失败，请检查设备是否在线或联系管理员");
//                }
//            }
//            if (withTime && withEle) {
//                try {
//                    Thread.sleep(5000);
//                } catch (Exception e) {
//                    log.error("设备归零等待时间异常:{}", e.getMessage());
//
//                    throw new ServiceException(e.getMessage());
//                }
//            }
//            if (withEle) {
//                CommandResponse res = iotService.setEle(device, BigDecimal.ZERO, reason);
//                if (requiredIot) {
//                    ServiceUtil.assertion(res == null, "归零电量失败，返回值为空");
//                    ServiceUtil.assertion(!res.isSuccess(), "归零电量失败，请检查设备是否在线或联系管理员");
//                }
//            }
//
//            return 1;
//        });
//
////        if (result != null && result == 1) {
////            this.resetRecord(device, RecordTimeType.TIME, reason);
////            this.resetRecord(device, RecordTimeType.ELE, reason);
////        }
//        return result == null ? 0 : result;
//    }

    /**
     * 开关设备
     */
    @Override
    public int switchDevice(Long deviceId, boolean open, String reason) {
        if (deviceId == null) {
            return 0;
        }
        DeviceVO device = selectById(deviceId);
        if (device == null) {
            return 0;
        }
        this.pullDeviceInfo(device, null);
        return this.switchDevice(device, open ? DevicePowerStatus.ON : DevicePowerStatus.OFF, reason);
    }

    /**
     * 切换设备通电状态（通/断电）
     *
     * @param device      设备id
     * @param powerStatus 通电状态
     * @param reason
     */
    @Override
    public int switchDevice(DeviceVO device, DevicePowerStatus powerStatus, String reason) {
        ServiceUtil.assertion(device == null || device.getDeleted(), "设备不存在");

        Integer result = transactionTemplate.execute(status -> {
            // 修改数据库
            Device data = new Device();
            data.setDeviceId(device.getDeviceId());
            data.setPowerStatus(powerStatus.getStatus());
            int update = deviceMapper.updateDevice(data);

            // 操作设备
            if (update == 1) {
                if (DevicePowerStatus.ON.equals(powerStatus)) {
                    boolean open = iotService.open(device, reason);
                    ServiceUtil.assertion(!open, "开启设备失败");
                } else if (DevicePowerStatus.OFF.equals(powerStatus)) {
                    boolean close = iotService.close(device, reason);
                    ServiceUtil.assertion(!close, "关闭设备失败");
                } else {
                    throw new ServiceException("不支持的操作");
                }
            }
            return update;
        });
        return result == null ? 0 : result;
    }




    @Override
    public boolean setWxs(Long deviceId, BigDecimal wxs, String reason) {
        if (deviceId == null || wxs == null) {
            return false;
        }
        DeviceVO device = selectById(deviceId);
        ServiceUtil.assertion(device == null, "ID为" + deviceId + "的设备不存在");
        return setWxs(device, wxs, reason);
    }

    public boolean setWxs(DeviceVO device, BigDecimal wxs, String reason) {
        if (device == null || wxs == null) {
            return false;
        }
        CommandResponse res = iotService.setWxs(device, wxs, reason);
        if (res == null || !res.isSuccess()) {
            return false;
        }
        return true;
    }

    @Override
    public boolean setSet(Long deviceId, String set, String reason) {
        if (deviceId == null || StringUtils.isBlank(set)) {
            return false;
        }
        DeviceVO device = selectById(deviceId);
        ServiceUtil.assertion(device == null, "ID为" + deviceId + "的设备不存在");
        return setSet(device, set, reason);
    }

    public boolean setSet(DeviceVO device, String set, String reason) {
        if (device == null || StringUtils.isBlank(set)) {
            return false;
        }
        CommandResponse res = iotService.setSet(device, set, reason);
        if (res == null || !res.isSuccess()) {
            return false;
        }
        return true;
    }

    @Override
    public int initTotalEle(Long deviceId) {
        if (deviceId == null) {
            return 0;
        }
        // 拉取设备信息
        this.pullDeviceInfo(deviceId, null);
        return deviceMapper.initTotalEle(deviceId);
    }
}
