package com.yuchen.saas.park.service.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.thinkunion.park.service.common.cache.CacheNames;
import com.yuchen.saas.integration.feign.api.vo.ProductInfoVO;
import com.yuchen.saas.park.api.entity.device.PmgBatSmartEquipment;
import com.yuchen.saas.park.api.enums.DeviceEnum;
import com.yuchen.saas.park.api.enums.DeviceTypeEnum;
import com.yuchen.saas.park.api.util.DeviceDataUtils;
import com.yuchen.saas.park.api.vo.park.devicepro.DeviceBasePro;
import com.yuchen.saas.park.api.vo.responsevo.ResponseVo;
import com.yuchen.saas.park.service.factory.SimpleDeviceFactory;
import com.yuchen.saas.park.service.iot.IotClientService;
import com.yuchen.saas.park.service.service.PmgBatParkPerceiveService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.collections4.map.HashedMap;
import org.nest.springwrap.core.redis.cache.NestRedis;
import org.nest.springwrap.core.tool.api.R;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @Author: 肖润飞
 * @CreateTime: 2022/09/07 11:00
 * @Description: 智慧物联网感知数据接口实现类
 * @Version: 1.0
 */
@Service
@Slf4j
public class PmgBatParkPerceiveServiceImpl implements PmgBatParkPerceiveService {

    @Resource
    private IotClientService iotClientService;

    @Resource
    private DeviceDataUtils deviceDataUtils;

    @Resource
    private NestRedis nestRedis;


    /**
     * 设置默认展示设备key
     */
    private static String[] defaultProductKeys;

    static {
        DeviceTypeEnum[] types = DeviceTypeEnum.values();
        List<String> listStr = new ArrayList<>();
        for (DeviceTypeEnum deviceTypeEnum : types) {
            String[] category = deviceTypeEnum.getCategory();
            for (String productKey : category) {
                listStr.add(productKey);
            }
        }
        defaultProductKeys = listStr.toArray(new String[]{});
    }

    /**
     * @return Map
     * @Author 肖润飞
     * @Description 获取产品统计数据
     * @CreateTime 2022/9/7 15:20
     * @Param [type: 查询的列表类型; type=all,type=enum]
     **/
    @Override
    public List<DeviceBasePro> getDeviceList(String type, String parkId) {
        //设备分类map
        //Map<String, List<DeviceBasePro>> resMap = new HashedMap<>();
        List<DeviceBasePro> resultList = new ArrayList<>();
        // 根据type类型获得需要展示的设备分类
        log.info("设备分类查询: start,type = {}", type);
        switch (type) {
            case "all":
                // 获得全部的设备分类
                ResponseVo responseVo = iotClientService.findAllProducts();
                List<ProductInfoVO> productInfoVOList = (List<ProductInfoVO>) responseVo.getData();
                productInfoVOList.forEach(info -> {
                    List<DeviceBasePro> deviceDataFromCash = deviceDataUtils.getDeviceDataFromCash(info.getProductKey(), parkId);
                    resultList.addAll(deviceDataFromCash);
                });
                break;
            case "enum":
                // 获得设定的设备分类
                DeviceEnum[] products = DeviceEnum.values();
                // 循环所有的设备分类
                for (DeviceEnum product : products) {
                    List<DeviceBasePro> deviceDataFromCash = deviceDataUtils.getDeviceDataFromCash(product.getValue(), parkId);
                    resultList.addAll(deviceDataFromCash);
                }
                break;
            case "category":
                // 获得手动设定设备分类
                for (String productKey : defaultProductKeys) {
                    List<DeviceBasePro> devicePro = deviceDataUtils.getDeviceDataFromCash(productKey, parkId);
                    resultList.addAll(devicePro);
                }
                break;
            default:
                throw new IllegalStateException("非法参数异常" + type);
        }
        log.info("设备分类查询: end,type = {}", type);
        //返回数据
        return resultList;
    }

    /**
     * @return List
     * @Author 肖润飞
     * @Description 根据设备的productKey获得设备列表
     * @CreateTime 2022/9/7 15:20
     * @Param [parkId] 园区id
     **/
    @Override
    public HashMap<String, Object> getDeviceList(String parkId) {
        HashMap<String, Object> resMap = new HashMap<>();
        //LambdaQueryWrapper<PmgBatSmartEquipment> lambdaQueryWrapper = new LambdaQueryWrapper();
        //lambdaQueryWrapper.eq(PmgBatSmartEquipment::getParkId, parkId);
        // 根据园区id查询全部的
        //List<PmgBatSmartEquipment> allDevice = smartEquipmentService.list(lambdaQueryWrapper);
        List<DeviceBasePro> resultList = new ArrayList<>();
        for (String productKey : defaultProductKeys) {
            List<DeviceBasePro> devicePro = deviceDataUtils.getDeviceDataFromCash(productKey, parkId);
            resultList.addAll(devicePro);
        }
        for (int i = 0; i < defaultProductKeys.length; i++) {
            String defaultProductKey = defaultProductKeys[i];
            List<DeviceBasePro> collect = resultList.stream()
                    .filter(equipment -> defaultProductKey.equals(equipment.getProductKey()))
                    .collect(Collectors.toList());
            resMap.put(defaultProductKey, collect);
        }
        return resMap;
    }


    /**
     * 统计园区设备种类
     *
     * @param productKeys 需要查询的设备分类
     * @param parkId      指定园区的id
     * @return 统计数据
     */
    @Override
    public Map<String, Object> deviceNumber(String[] productKeys, String parkId) {
        // productKeys如果不传递, 默认需要查询的设备: 默认查询水电设备
        if (productKeys == null || productKeys.length == 0) {
            productKeys = defaultProductKeys;
        }
        Map<String, Object> resMap = new HashMap<>();
        // 查询指定园区的设备
        //LambdaQueryWrapper<PmgBatSmartEquipment> lambdaQueryWrapper = new LambdaQueryWrapper();
        //lambdaQueryWrapper.eq(PmgBatSmartEquipment::getParkId, parkId);
        //List<PmgBatSmartEquipment> allDevice = smartEquipmentService.list(lambdaQueryWrapper);
        List<DeviceBasePro> resultList = new ArrayList<>();
        for (String productKey : defaultProductKeys) {
            List<DeviceBasePro> devicePro = deviceDataUtils.getDeviceDataFromCash(productKey, parkId);
            resultList.addAll(devicePro);
        }
        // 总设备数量
        resMap.put("total", resultList.size());
        AtomicInteger online = new AtomicInteger(0);
        AtomicInteger offline = new AtomicInteger(0);
        resultList.forEach(info -> {
            // 设备的在线离线
            if (info.getIsOnline() == 1) {
                online.getAndIncrement();
            } else {
                offline.getAndIncrement();
            }
        });
        resMap.put("online", online);
        resMap.put("offline", offline);
        // 查询当前指定设备的个数
        return resMap;
    }

    /**
     * 更新设备缓存数据
     *
     * @param equipment 设备数据
     */
    @Override
    public void updateDeviceCash(PmgBatSmartEquipment equipment) {
        String cashKey = new StringBuilder(CacheNames.DEVICE_PRO_PREFIX)
                .append(equipment.getParkId())
                .append(":")
                .append(equipment.getProductKey())
                .append(":")
                .append(equipment.getDeviceName())
                .toString();
        Boolean exists = nestRedis.exists(cashKey);
        //工厂创建产品属性对象
        DeviceBasePro devicePro = SimpleDeviceFactory.createDevicePro(equipment.getProductKey());
        //设置默认信息
        BeanUtil.copyProperties(equipment, devicePro);
        // exists : 缓存key存在则忽略此次未传递的数据,不存在不忽略
        Map<String, Object> stringObjectMap = BeanUtil.beanToMap(devicePro, false, exists);
        // 将对象转换成Map,并复制成新的map,解决hMset限定参数原因;
        Map<Object, Object> resMap = new HashedMap<>();
        if (MapUtils.isNotEmpty(stringObjectMap)) {
            resMap.putAll(stringObjectMap);
        }
        //放入缓存中
        if (MapUtils.isNotEmpty(resMap)) {
            nestRedis.hMset(cashKey, resMap);
        }
    }

    /**
     * 对指定设备缓存进行上线/下线设置
     *
     * @param upOrDown   上线或者下线 1/0
     * @param productKey 设备productKey
     * @param deviceName 设备deviceName
     * @return
     */
    @Override
    public R upOrDownDevice(String upOrDown, String productKey, String deviceName, long parkId) {
        //参数检测
        if (!"0".equals(upOrDown) && !"1".equals(upOrDown)) {
            log.error("请求参数不正确 upOrDown = {}", upOrDown);
            return R.fail("请求参数不正确 upOrDown");
        }
        String cashKey = new StringBuilder(CacheNames.DEVICE_PRO_PREFIX).append(parkId).append(":").append(productKey).append(":").append(deviceName).toString();
        //查询指定设备是否存在上线/下线功能
        Boolean aBoolean = nestRedis.hExists(cashKey, "isOnline");
        if (!aBoolean) {
            log.error("指定设备不存在上线/下线功能 parkId = {} , productKey= {}, deviceName = {} ", parkId, productKey, deviceName);
            return R.fail("指定设备不存在上线/下线功能");
        }
        //对指定设备进行上线/下线
        nestRedis.hSet(cashKey, "isOnline", upOrDown);
        return R.success();
    }

    /**
     * 根据产品productKeys 查询设备信息
     *
     * @param parkId 园区id
     * @return
     */
    @Override
    public Map<String, Object> getDeviceListByProductKeys(String parkId) {
        // 获得手动设定设备分类
        Map<String, Object> resultMap = new HashMap<>();
        List<Map<String, Object>> weather = deviceDataUtils.getDeviceMapFromCash("5RczFvFljRepi3zh", parkId);
        boolean pmB = true;
        boolean phB = true;
        boolean speedB = true;
        boolean rainB = true;
        for (Map<String, Object> weatherMap : weather) {
            if (pmB) {
                Object pm25 = weatherMap.get("pm25");
                pm25 = pm25 == null ? 0 : pm25;
                Double pm25D = Double.valueOf(pm25 + "");
                if (pm25D > 0) {
                    resultMap.put("temperature", weatherMap.get("temperature"));
                    resultMap.put("humidity", weatherMap.get("humidity"));
                    resultMap.put("pm10", weatherMap.get("pm10"));
                    resultMap.put("pm25", weatherMap.get("pm25"));
                    resultMap.put("noise", weatherMap.get("noise"));
                    pmB = false;
                }
            }
        }
        List<Map<String, Object>> soil = deviceDataUtils.getDeviceMapFromCash("4sb2vBmPJ7t7ANxH", parkId);
        for (Map<String, Object> soilMap : soil) {
            if (phB) {
                Object ph = soilMap.get("ph");
                ph = ph == null ? 0 : ph;
                Double phD = Double.valueOf(ph + "");
                if (phD > 0) {
                    resultMap.put("ph", soilMap.get("ph"));
                    phB = false;
                }
            }

        }
        List<Map<String, Object>> wind = deviceDataUtils.getDeviceMapFromCash("NbhjLj9ESs4Rsjgh", parkId);
        for (Map<String, Object> windMap : wind) {
            if (speedB) {
                Object speed = windMap.get("speed");
                speed = speed == null ? 0 : speed;
                Double speedD = Double.valueOf(speed + "");
                if (speedD > 0) {
                    resultMap.put("speed", windMap.get("speed"));
                    speedB = false;
                }
            }
        }
        List<Map<String, Object>> rain = deviceDataUtils.getDeviceMapFromCash("m2CyX1ygxWSbcivH", parkId);
        for (Map<String, Object> rainMap : rain) {
            if (rainB) {
                Object rainfall = rainMap.get("rainfall");
                rainfall = rainfall == null ? 0 : rainfall;
                Double rainD = Double.valueOf(rainfall + "");
                if (rainD > 0) {
                    resultMap.put("rainfall", rainMap.get("rainfall"));
                    rainB = false;
                }
            }
        }
        return resultMap;
    }
}