package com.zt.plat.module.qms.iot.tcpserver.device.handler;

import com.zt.plat.module.qms.iot.tcpserver.core.*;
import com.zt.plat.module.qms.iot.tcpserver.device.RedisSessionComponent;
import com.alibaba.fastjson.JSONObject;
import com.zt.plat.module.qms.iot.tcpserver.IotDeviceType;
import com.zt.plat.module.qms.iot.tcpserver.IotPacket;
import com.zt.plat.module.qms.iot.tcpserver.IotUtils;
import com.zt.plat.module.qms.iot.tcpserver.handler.IotDataHander;
import com.zt.plat.module.qms.iot.tcpserver.publisher.BalanceDataPublisher;
import com.fhs.common.spring.SpringContextUtil;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.stereotype.Component;
import tech.zzjc.tio.cluster.TioClusterConfig;
import tech.zzjc.tio.cluster.TioClusterVo;
import tech.zzjc.tio.core.ChannelContext;
import tech.zzjc.tio.core.Tio;
import tech.zzjc.tio.core.TioConfig;
import tech.zzjc.tio.core.stat.ChannelStat;
import tech.zzjc.tio.utils.SystemTimer;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import static com.zt.plat.module.qms.iot.tcpserver.core.GroupConstant.CAA_ALL_CLIENT;

/**
 * <b>IotDeviceBalanceHandler</b>
 * 天平
 * <p>更新历史：</p>
 * <pre> 版本         更新时间            更新者        更新内容
 * V1.0      2021-10-14          王兴荣         Add</pre>
 * <b>Copyright (C)  云南志者竟成科技有限公司</b> 
 * @author 王兴荣 &lt;xingrong_wang@will-way.cn&gt;
 * @version V1.0 
 * @since 2021-10-14
 */
@Slf4j
@Component
public class IotDeviceBalanceHandler implements IotDataHander {

    //重量稳定个数
    private int weightStableNum = 10;

    @Override
    public Object hander(String msgId, String data, ChannelContext channelContext) throws Exception {
        //获取客户端连接信息
        ChannelStat stat = channelContext.stat;
        String realClientIp = channelContext.get("realClientIp") == null ? channelContext.getClientNode().getIp() : channelContext.get("realClientIp").toString();
        String realClientPort = channelContext.get("realClientPort") == null ? channelContext.getClientNode().getPort() + "" : channelContext.get("realClientPort").toString();
        String connectType = channelContext.get(ChannelContextConstant.CONNECT_TYPE) == null ? "" : channelContext.get(ChannelContextConstant.CONNECT_TYPE).toString();
        String realClient = realClientIp + ":" + realClientPort;
        //通过sessionContext传入设备ID
        IotDeviceSessionContext sessionContext = (IotDeviceSessionContext) channelContext.get(IotDeviceSessionContext.DEFAULT_DEVICE_SESSION_CONTEXT_KEY);
        String deviceCode = sessionContext.getDeviceCode();
        String deviceId = IotUtils.transDeviceCodeToId(deviceCode);
        RedisSessionComponent redisSessionComponent = (RedisSessionComponent) SpringContextUtil.getBean("redisSessionComponent");
        IotDeviceSessionForRedisContext deviceContext = redisSessionComponent.getByDeviceCode(deviceCode);
        String weightData = "0.0";
        String weightUnit = null;
        
//        if (channelContext.get("TenantId") == null || StringUtils.isBlank(data)) { //设备未注册成功，暂不处理数据
        if (StringUtils.isBlank(data)) { //设备未注册成功，暂不处理数据
            return null;
        }
        
        if ("---- METTLER TOLEDO ----".equals(data) || "METTLER TOLEDO".equals(data) 
        		|| "----.---".equals(data) || "---.---".equals(data)
                || "S I".equals(data) || "SI".equals(data) || "SI+".equals(data) || "ES".equals(data) 
                || "EL".equals(data) || data.startsWith("EL") || data.startsWith("I4 A")
                || data.startsWith("Stat")) {//天平发送的特殊字符
            return null;
        }

        String[] dataArray = analysisData(data, weightUnit);
        weightData = dataArray[0];
        weightUnit = dataArray[1];
        if (!NumberUtils.isParsable(weightData)) {
            log.error("{},天平接收到的数据不正确！接收到的数据：{} 16进制：{}", realClient, data, IotUtils.bytesToHex(data.getBytes("UTF-8")));
            return null;
        }
        List<Double> weightValueList = deviceContext.getWeightValueList();
        if (weightValueList == null) {
            weightValueList = new ArrayList<>(weightStableNum);
            deviceContext.setWeightValueList(weightValueList);

        }
        if (weightValueList.size() >= weightStableNum) {
            weightValueList.remove(0);
        }
        weightValueList.add(Double.parseDouble(weightData));
        int weightStable = 0;
        if (weightValueList.size() == weightStableNum) {
            double max = Collections.max(weightValueList);
            double min = Collections.min(weightValueList);
            double diff = max - min;
            //double average = weightValueList.stream().mapToDouble(a -> a.doubleValue()).average().getAsDouble();
            if (diff == 0 && max >= 0 && min >= 0) {//最大减去最小差值为0，并且值需要大于0
                weightStable = 1;
            }
        }
        
        if (weightUnit != null) {
            deviceContext.setBalanceWeightUnit(weightUnit);
		} else {
			weightUnit = deviceContext.getBalanceWeightUnit() == null ? "" :deviceContext.getBalanceWeightUnit();
		}
        
        //更新deviceContext信息
        ChannelContext deviceChannelContext = Tio.getByBsId(channelContext.getTioConfig(), deviceCode);
        if(deviceChannelContext != null){
            deviceContext.setClientProtocol(deviceChannelContext.getClientNode().getProtocol());
            deviceContext.setProxyIp(deviceChannelContext.getClientNode().getIp());
            deviceContext.setProxyPort(deviceChannelContext.getClientNode().getPort());
            deviceContext.setProxyProtocol(deviceChannelContext.getClientNode().getProtocol());
        }
        deviceContext.setClientIp(realClientIp);
        deviceContext.setClientPort(Integer.parseInt(realClientPort));
        deviceContext.setConnectType(connectType);
        deviceContext.setDecodeFailCount(stat.getDecodeFailCount());
        deviceContext.setGmtCreate(new Date(stat.getTimeCreated()));
        deviceContext.setReceivedBytes(stat.getReceivedBytes());
        deviceContext.setReceivedPackets(stat.getReceivedPackets());
        deviceContext.setReceivedTcps(stat.getReceivedTcps());
        deviceContext.setBytesPerTcpReceive(stat.getBytesPerTcpReceive());
        deviceContext.setPacketsPerTcpReceive(stat.getPacketsPerTcpReceive());
        deviceContext.setHandledBytes(stat.getHandledBytes());
        deviceContext.setHandledPackets(stat.getHandledPackets());
        deviceContext.setSentBytes(stat.getSentBytes());
        deviceContext.setSentPackets(stat.getSentPackets());


        deviceContext.setLastBalanceDataTime(SystemTimer.currTime);
        redisSessionComponent.update(deviceContext);
        //租户ID
        String tenantId = deviceContext.getTenantId();
        BalanceDataPublisher.publishEvent(Long.parseLong(deviceId), tenantId, weightData, weightUnit);
        JSONObject deviceData = new JSONObject();
        deviceData.put("deviceId", deviceId);
        deviceData.put("deviceType", IotDeviceType.BALANCE.getType());
        deviceData.put("controlRealName", deviceContext.getControlRealName());
        deviceData.put("weightData", weightData);
        deviceData.put("weightUnit", weightUnit);
        deviceData.put("weightStable", weightStable);

        //发布数据到客户端
        TioConfig tioConfig = channelContext.getTioConfig();
        JSONObject json = new JSONObject();
        json.put("cmd", Command.DEVICE_DATA.getName());
        json.put("clientType", ClientType.CAA_CLIENT.getName());
        json.put("data", deviceData);
        IotPacket packet = new IotPacket();
        packet.setBody((json.toJSONString() + "\r\n").getBytes(Charset.forName(IotPacket.CHARSET)));
        Tio.sendToGroup(tioConfig, CAA_ALL_CLIENT, packet);

        //通知天平数据到其他服务实例
//        log.info("天平数据：" + realClient + ":" + data);
        TioClusterConfig tioClusterConfig = tioConfig.getTioClusterConfig();
        TioClusterVo iotClusterVo = new TioClusterVo(packet);
        iotClusterVo.setGroup(CAA_ALL_CLIENT);
//        if(!"0.00".equals(weightData))
            tioClusterConfig.publish(iotClusterVo);

        return null;
    }

    private String[] analysisData(String data, String weightUnit){
        String weightData = "0.0";
        byte[] nul = {0x00};
        data = data.replace(new String(nul), "");
        data = data.replace(new String(IotUtils.hexToByte("efbfbd"), StandardCharsets.UTF_8), "");//乱码
        if (data.contains("VH")) {//中间特殊字母
            data = data.substring(data.lastIndexOf("VH") + 2);
        }
        if (data.startsWith("S") || data.startsWith("N") || data.startsWith("G")) {
            String[] splits = data.split("\\s+");//按一个或多个空格拆分
            if (splits.length == 5) {
                if ("-".equals(splits[2])) {
                    weightData = splits[2] + splits[3];
                } else {
                    weightData = splits[3];
                }
                weightUnit = splits[4];
            } else if (splits.length == 4) {
                if ("M".equals(splits[3])) {
                    weightData = splits[1];
                    weightUnit = splits[2];
                } else {
                    weightData = splits[2];
                    weightUnit = splits[3];
                }
            } else if (splits.length == 3) {
                if("+".equals(splits[1])) {
                    weightData = splits[2];
                } else if ("-".equals(splits[1])) {
                    weightData = splits[1] + splits[2];
                } else if (("S".equals(splits[1]) || "N".equals(splits[1])) && splits[2].length() > 2) {
                    if (splits[2].endsWith("mg")) {
                        weightData = splits[2].substring(0, splits[2].length() - 2);
                        weightUnit = "mg";
                    } else if (splits[2].endsWith("g")) {
                        weightData = splits[2].substring(0, splits[2].length() - 1);
                        weightUnit = "g";
                    } else {
                        weightData = splits[2];
                    }
                } else {
                    weightData = splits[1];
                    weightUnit = splits[2];
                }
            } else if (splits.length == 2) {
                weightData = splits[1];
            } else {
                weightData = data;
            }
        }
        else {
            data = data.replace("(", "").replace(")", "");
            String[] splits = data.split("\\s+");
            if (splits.length == 3) {
                if("+".equals(splits[0])) {
                    weightData = splits[1];
                } else if ("-".equals(splits[0])) {
                    weightData = splits[0] + splits[1];
                } else {
                    weightData = splits[1];
                }
                weightUnit = splits[2];
            } else if(splits.length == 2) {
                if("+".equals(splits[0])) {
                    weightData = splits[1];
                } else if ("-".equals(splits[0])) {
                    weightData = splits[0] + splits[1];
                } else {
                    weightData = splits[0];
                    weightUnit = splits[1];
                }
            } else {
                weightData = data;
            }
        }
        if (weightData.startsWith("+")) {
            weightData = weightData.substring(1);
        }
        return new String[]{weightData, weightUnit};
    }

}
