package com.ho.datacollect.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.ho.business.constant.DeviceTypeConstant;
import com.ho.business.entity.DeviceTypeCol;
import com.ho.business.entity.ModelDeviceColComp;
import com.ho.business.service.ModelDeviceService;
import com.ho.business.vo.DeviceTransfer;
import com.ho.common.tools.constant.CommonConstant;
import com.ho.common.tools.service.RedisService;
import com.ho.datacollect.api.constant.DataCollectConstant;
import com.ho.datacollect.api.vo.req.add.DataSetParam;
import com.ho.datacollect.api.vo.req.add.TdDeviceAddReq;
import com.ho.datacollect.feignclient.DataCollectTdFeignClient;
import com.ho.datacollect.service.DataCollectService;
import com.ho.datacollect.service.ModelConvertService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description 一体机柜
 * Author yule
 * Date 2023/3/9 14:05
 */
@Service(DataCollectConstant.KEY_MAP.DEVICE001)
@Slf4j
public class Device001DataCollectServiceImpl implements DataCollectService {

    @Autowired
    DataCollectTdFeignClient tdFeignClient;

    @Autowired
    RedisService redisService;

    @Autowired
    ModelDeviceService modelDeviceService;

    @Autowired
    ModelConvertService modelConvertService;

    @Override
    public void doService(DataSetParam dataSetParam) {
        String deviceType = null;
        String modelName = null;
        try {
            //
            //String str = "{\"dataSet\":{\"YC0030\":0,\"YC0015\":0,\"YC0016\":0,\"YC0013\":21,\"YC0035\":65535,\"YC0014\":0,\"YC0036\":65535,\"YC0011\":0,\"YC0033\":65535,\"YC0012\":26,\"YC0034\":65535,\"YC0031\":1,\"YC0010\":0,\"YC0032\":0,\"YC0019\":25,\"YC0017\":0,\"YC0018\":0,\"YC0004\":0,\"YC0026\":8,\"YC0005\":5,\"YC0027\":0,\"YC0002\":5,\"YC0024\":220,\"YC0003\":45,\"YC0025\":624,\"YC0022\":75,\"YC0001\":23,\"YC0023\":1,\"YC0020\":30,\"YC0021\":80,\"YC0008\":0,\"YC0009\":0,\"YC0006\":10,\"YC0028\":0,\"YC0007\":1,\"YC0029\":0},\"deviceType\":\"11#air_condition_507\",\"deviceTypeId\":1522,\"freezeTime\":\"2024-01-22 15:53:00.216\",\"groupId\":155,\"modelName\":\"device_simple\",\"srcId\":432000015,\"stationId\":507}";
            //log.info("Device001DataCollectServiceImpl: dataSetParam:{}", JSONObject.toJSONString(dataSetParam));
            //dataSetParam = JSONObject.parseObject(str, DataSetParam.class);
            //拼接表名
            Integer groupId = dataSetParam.getGroupId();
            Integer stationId = dataSetParam.getStationId();
            Integer srcId = dataSetParam.getSrcId();
            //设备类型
            deviceType = dataSetParam.getDeviceType();
            modelName = dataSetParam.getModelName();
            //时间送过来是个字符串,要转成Date类型
            String freezeTime = dataSetParam.getFreezeTime();
            //捕获异常,如果时间转换出错,就使用现在的时间
            DateTime ts = new DateTime();
            Date createTime = new Date();
            Date updateTime = Convert.toDate(freezeTime);
            try {
                ts = DateUtil.parse(freezeTime, CommonConstant.DATE_YMD_HMSS);
            } catch (Exception e) {
                log.error("匹配入库时freezeTime格式转换时出错,电站：{},设备类型：{},freezeTime:{},", stationId, deviceType, freezeTime);
                return;
            }
            String tableName = new StringBuilder().append(groupId).append(DataCollectConstant.TABLE_LINK)
                    .append(stationId).append(DataCollectConstant.TABLE_LINK).append(srcId).toString();
            //创建新增对象
            TdDeviceAddReq device = new TdDeviceAddReq();
            //共通属性
            device.setGroupId(groupId);
            device.setStationId(stationId);
            device.setSrcId(srcId);
            device.setTableName(tableName);
            //inverterAddReq.setDeviceType(deviceType);
            JSONObject dataSet = dataSetParam.getDataSet();
            log.info("Device001DataCollectServiceImpl 产生的tableName: {}, freezeTime:{} , deviceType: {},modelName:{}", tableName, freezeTime, deviceType, modelName);
            //从设备定义表中得到需要哪些数据，不是所有数据都要入库
            //需要入库的字段是根据外部设备模型查出来的字段集合
            //dataSet赋值6个
            if (dataSet == null) {
                dataSet = new JSONObject();
            }
            /*List<ModelDeviceColComp> compList = modelDeviceService.getCompListByType(CommonConstant.ModelDeviceType.DEVICE, deviceType,null);
            if (compList.isEmpty()) {
                log.error("该设备未配置映射字段");
                return;
            }*/
            //入库的数据是设备原始格式,但需要经过一轮匹配,匹配到才入库不是每个字段都入库
            //JSONObject inputData = modelConvertService.getInputDataByDeviceType(dataSet, compList, deviceType);
            //先判断缓存中是否存在
            String redisKey = deviceType + ":" + stationId + ":" + srcId;
            Map<Object, Object> hgetall = redisService.hgetall(redisKey);
            JSONObject modifyDataObject = new JSONObject();
            //2024-01-22 根据点表配置的系数和偏移量, 先乘系数 再减去偏移量
            List<DeviceTypeCol> deviceTypeCols = modelDeviceService.selectByDeviceType(deviceType);
            //根据col分组
            Map<String, List<DeviceTypeCol>> colMap = deviceTypeCols.stream().collect(Collectors.groupingBy(DeviceTypeCol::getCol));
            JSONObject finalDataSet = dataSet;
            dataSet.forEach((k, v) -> {
                //todo 更改一体机柜缓存值类型
                DeviceTransfer deviceTransfer = (DeviceTransfer) hgetall.get(k);
                if (null == deviceTransfer) {
                    deviceTransfer = new DeviceTransfer();
                    deviceTransfer.setIsRecovery(null);
                    deviceTransfer.setEventId(null);
                }
                //如果系数不为空,偏移量不为空,则需要处理
                if (colMap.containsKey(k)) {
                    List<DeviceTypeCol> deviceTypeColsV = colMap.get(k);
                    if (deviceTypeColsV != null && deviceTypeColsV.size() >= 1) {
                        DeviceTypeCol deviceTypeCol = deviceTypeColsV.get(0);
                        BigDecimal primitive = new BigDecimal(String.valueOf(v));
                        deviceTransfer.setSrcValue(primitive);
                        if (deviceTypeCol.getFactor() != null) {
                            log.info("系数factor:" + deviceTypeCol.getFactor());
                            primitive = primitive.multiply(deviceTypeCol.getFactor());
                        }
                        if (deviceTypeCol.getOffsetValue() != null) {
                            log.info("系数偏移量 OffsetValue:" + deviceTypeCol.getOffsetValue());
                            primitive = primitive.subtract(deviceTypeCol.getOffsetValue());
                        }
                        if(CommonConstant.ONE.equals(deviceTypeCol.getFilterType())&&deviceTypeCol.getMaxValue()!=null&&deviceTypeCol.getMinValue()!=null){
                            if(primitive.compareTo(deviceTypeCol.getMaxValue())>0 || primitive.compareTo(deviceTypeCol.getMinValue())<0){
                                log.info("数据不符合设定的最大最小值要求，不更新redis缓存，redis的key:{},col:{}", redisKey, k);
                                return;
                            }
                        }
                        deviceTransfer.setValue(primitive);
                        if(deviceTransfer.getUpdateTime()==null){
                            deviceTransfer.setUpdateTime(updateTime);
                            modifyDataObject.put(k, deviceTransfer);
                        }else{
                            if(deviceTransfer.getUpdateTime().getTime()<=updateTime.getTime()){
                                deviceTransfer.setUpdateTime(updateTime);
                                modifyDataObject.put(k, deviceTransfer);
                            }
                        }
                        //把dataSet中的值也要根据
                        finalDataSet.put(k ,primitive);
                    }
                }
                //已经配置的字段并且值非空
//                Map<String,Object> map = new HashMap<>();
//                map.put(k,v);
//                map.put(DataCollectConstant.UPDATE_TIME, updateTime);
//                modifyDataObject.put(k,map);
            });
            //入时序库的对象元素是JsonObject
            JSONObject inputData = finalDataSet;
            if (inputData.isEmpty()) {
                log.error("转换后无匹配的数据字段 ,无需入库");
                return;
            }
            //时序数据对象, 把两个时间字段放进去
            inputData.put(DataCollectConstant.TS, ts);
            inputData.put(DataCollectConstant.CREATE_TIME, createTime);
            //将设备数据格式转换为平台数据格式(注意这个是平台数据格式)
            //JSONObject modelObject = modelConvertService.convertModelFromDevice(dataSet, compList, deviceType);
            //内部外部使用相同模型
            JSONObject modelObject = modifyDataObject;
            //addCommunicationStatus(dataSet, modelObject);
            String oldTs = null;
            try{
                oldTs = (String)hgetall.get(DataCollectConstant.TS);
            }catch (ClassCastException e){
                modelObject.put(DataCollectConstant.TS, DateUtil.format(ts,CommonConstant.DATE_YMD_HMSS));
                modelObject.put(DataCollectConstant.UPDATE_TIME, createTime);
                log.info("redis中ts是老的时间类型，不做适配处理，继续更新缓存中的ts以及updateTime,电站：{},设备类型：{},freezeTime:{},", stationId, deviceType, freezeTime);
            }
            if(oldTs!=null){
                DateTime oldDate = DateUtil.parse(oldTs, CommonConstant.DATE_YMD_HMSS);
                if(oldDate.getTime()<=ts.getTime()){
                    modelObject.put(DataCollectConstant.TS, DateUtil.format(ts,CommonConstant.DATE_YMD_HMSS));
                    //最后更新时间
                    modelObject.put(DataCollectConstant.UPDATE_TIME, createTime);
                }else{
                    log.info("redis中ts是时间比上送的ts更靠后,不更新redis中ts时间,电站：{},设备类型：{},freezeTime:{},", stationId, deviceType, freezeTime);
                }
            }
            //先判断缓存中是否存在
//            String redisKey = deviceType + ":" + stationId + ":" + srcId;
            Boolean flag = redisService.hasKey(redisKey);
            //缓存的数据是转换后的平台模型
            if (!flag) {
                //没数据新建一个createTime
                modelObject.put(DataCollectConstant.CREATE_TIME, createTime);
                //设备类型塞进去
                //modelObject.put(DataCollectConstant.DEVICE_TYPE, deviceType);
            }
            try{
                //将设备映射字段同时写到redis,它的值和原始字段一致
                List<ModelDeviceColComp> compList = modelDeviceService.getCompListByType(CommonConstant.ModelDeviceType.DEVICE, deviceType, null);
                JSONObject convertInputData = modelConvertService.getInputDataByDeviceTypeForDevice001(updateTime, modifyDataObject, compList, deviceType);
                log.info("映射的字段 convertInputData:" + convertInputData);
                if (!convertInputData.isEmpty()) {
                    modelObject.putAll(convertInputData);
                }
            }catch (Exception e){
                log.error("查询映射失败，请检查:{}", deviceType);
            }
            //log.info("modelObject: {}", modelObject);
            if(modelObject.size()>0){
                redisService.hmset(redisKey, modelObject);
            }
            //log.info("inputData:{},", inputData);
            device.setDevice(inputData);
            //指定超级表
            if (DeviceTypeConstant.DEVICE_COMPLEX.equals(modelName)) {
                tdFeignClient.insertDeviceComplex(device);
            } else if (DeviceTypeConstant.DEVICE_SIMPLE.equals(modelName)) {
                tdFeignClient.insertDeviceSimple(device);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("添加:{}  失败: {}", deviceType, e.getMessage());
        }

    }
}
