package com.zd.laboratory.socket.service.impl;

import com.zd.common.core.constant.CacheConstants;
import com.zd.common.core.constant.CacheDevice;
import com.zd.common.core.enums.HardwareOperate;
import com.zd.common.core.utils.SpringUtils;
import com.zd.common.redis.service.RedisService;
import com.zd.laboratory.event.RelayHardwareStatusEvent;
import com.zd.laboratory.mqtt.entiy.EquipmentStatus;
import com.zd.laboratory.socket.constant.JXCTPacket;
import com.zd.laboratory.socket.exception.AnalysisException;
import com.zd.laboratory.socket.service.BaseRouter;
import com.zd.laboratory.socket.service.SocketService;
import com.zd.laboratory.socket.util.SocketUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;


/**
 * @author liubo
 * 全部问询FE DC 0B 08 08 08 08 08 08 02 02 30 5D 80 AC DB
 * 问询时间FE DC 0A 08 08 08 08 08 08 03 02 72 00 AC DB
 * 配置时间FE DC 10 08 08 08 08 08 08 03 00 14 03 03 10 14 14 D8 01 AC DB
 * 0号指令FE DC 09 08 08 08 08 08 08 00 B8 C1 AC DB
 */
@Service
public class RelayState implements BaseRouter {
    private static Logger log = LoggerFactory.getLogger(RelayState.class);

    @Autowired
    private SocketService socketService;
    @Autowired
    private RedisService redisService;

    public RelayState() {
        routerMap.put("00", this);
    }

    @Override
    public String routePacket(JXCTPacket tracketPacket) throws AnalysisException {

        int count = Integer.parseInt(tracketPacket.deviceNumber.substring(0, 2), 16);
//        继电器位号，2字节，0x03ff=0b001111111111，按位表示继电器状态，最低位表示第1号继电器，为0表示当前关闭，为1表示当前开启
        if (tracketPacket.body.length() < 4) {
            throw new AnalysisException(tracketPacket.deviceNumber + "继电器上报状态错误");
        }
        String bit = Integer.toBinaryString(Integer.parseInt(tracketPacket.body.substring(0, 4), 16));
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < count - bit.length(); i++) {
            builder.append("0");
        }
        bit = builder.toString() + bit;
//        设备ID，6字节，首位表示为几路继电器，最大为16路，即0x10，此处的0x12是为方便举例写的，
        if (count > bit.length()) {
            throw new AnalysisException(tracketPacket.deviceNumber + "继电器设备号错误");
        }
        String reverseBit = new StringBuilder(bit).reverse().toString();
        log.info(tracketPacket.deviceNumber + " :" + count + " 路  bit:" + bit + " reverseBit:" + reverseBit);

//        设备ID，6字节，首位表示为几路继电器，最大为16路，即0x10，此处的0x12是为方便举例写的，
        if (count > bit.length()) {
            throw new AnalysisException(tracketPacket.deviceNumber + "继电器设备号错误");
        }
        socketService.saveRelayInfo(tracketPacket.deviceNumber, count, 1);

        StringBuilder buff = new StringBuilder();
        for (int i = 0; i < count; i++) {
            if ("1".equals(reverseBit.substring(i, i + 1))) {
                buff.append("开");
            } else {
                buff.append("关");
            }
            if (i < count - 1) {
                buff.append(" | ");
            }
        }
        log.info(tracketPacket.deviceNumber + " :" + buff);
        StringBuilder relays = new StringBuilder();
        for (int i = 0; i < count; i++) {
            relays.append("继电器").append(i + 1);
            if (i < count - 1) {
                relays.append(" / ");
            }
        }
        log.info(relays.toString());
        Map<String, Object> redisData = new HashMap<>();
        redisData.put("reverseBit", reverseBit);
        redisData.put("relays", relays);
        redisData.put("buff", buff);

        //缓存数据
        //缓存数据前先查询出来上一次数据 为了减少操作数据库的次数（每一个继电器上报数据都会导致更新数据），
        //但是缓存后可能会产生数据不一致的（设备的状态与实际不一致）， 操作设备后会同步
        //优化方案：业务数据状态也放入redis, 最新数据和业务数据对比，根据对比结果产生事件，先更新业务数据缓存，根据事件进行写库操作，再双写更新业务数据缓存。
        Map<String, Object> relayData = socketService.getRelayData(tracketPacket.deviceNumber);
        redisService.setCacheObject(CacheDevice.RELAY_KEY.getRedisKey() + tracketPacket.deviceNumber, redisData,
                CacheDevice.RELAY_KEY.getRedisTime(), TimeUnit.SECONDS);

        redisService.setCacheObject( CacheDevice.RELAY_LIFE.getRedisKey() + tracketPacket.deviceNumber, tracketPacket.deviceNumber,
                CacheDevice.RELAY_LIFE.getRedisTime() ,TimeUnit.SECONDS);
        //抛出事件， 便于以后解耦
        if(relayData==null||!relayData.get("reverseBit").equals(reverseBit))
        {
            //上线：功能更新切换事件
            //创建上线对象
            EquipmentStatus equipmentStatus = new EquipmentStatus();
            equipmentStatus.setNum(tracketPacket.deviceNumber);
            equipmentStatus.setHardwareOperate(HardwareOperate.ONLINE);
            //抛出继电器上下线切换事件
            RelayHardwareStatusEvent relayHardwareStatusEvent = new RelayHardwareStatusEvent(equipmentStatus);
            SpringUtils.getApplicationContext().publishEvent(relayHardwareStatusEvent);
        }

        if (tracketPacket.body.length() < 16) {
            log.info(tracketPacket.deviceNumber + "继电器上报状态时间长度错误");
        } else {
            //        /日期，年，1字节，年份的前两位固定为20，直接取值，如0x14,十进制为20
            String year = tracketPacket.body.substring(4, 6);
            //日期，月，1字节
            String month = tracketPacket.body.substring(6, 8);
            //日期，日，1字节
            String day = tracketPacket.body.substring(8, 10);
            //日期，时，1字节
            String hour = tracketPacket.body.substring(10, 12);
            //日期，分，1字节
            String minute = tracketPacket.body.substring(12, 14);
            //日期，秒，1字节
            String seconds = tracketPacket.body.substring(14, 16);
            log.info(tracketPacket.deviceNumber + ":" + "20" +
                    SocketUtils.getHex2Sting(year, 2) + "-"
                    + SocketUtils.getHex2Sting(month, 2) + "-"
                    + SocketUtils.getHex2Sting(day, 2) + " "
                    + SocketUtils.getHex2Sting(hour, 2) + ":"
                    + SocketUtils.getHex2Sting(minute, 2) + ":"
                    + SocketUtils.getHex2Sting(seconds, 2));
            Timestamp relayTime = Timestamp.valueOf("20" +
                    SocketUtils.getHex2Sting(year, 2) + "-"
                    + SocketUtils.getHex2Sting(month, 2) + "-"
                    + SocketUtils.getHex2Sting(day, 2) + " "
                    + SocketUtils.getHex2Sting(hour, 2) + ":"
                    + SocketUtils.getHex2Sting(minute, 2) + ":"
                    + SocketUtils.getHex2Sting(seconds, 2));
            // 设备时差
            long timeDifference = System.currentTimeMillis() - relayTime.getTime();
            log.info(tracketPacket.deviceNumber + " date :" + relayTime.toString() + " 时差:" + timeDifference + "  " + SocketUtils.getTimeFormatDay(timeDifference));
            if (Math.abs(timeDifference) > 10000) {
                log.info("时差大于10s，下发请求校时");
                tracketPacket.order = "07";
                tracketPacket.body = "8000";
//                Channel channel = TCPServerHandler.channelMap.get(tracketPacket.deviceNumber);
//                if (channel != null) {
                String sendBody = tracketPacket.encodeString();
                log.info(tracketPacket.deviceNumber + "  下发请求校时：" + sendBody);
                return sendBody;
            }
        }
        return null;
    }
}
