package com.cisdi.data.AMETEKSurfaceVision.gateway;

import com.alibaba.fastjson.JSON;

import com.cisdi.data.AMETEKSurfaceVision.DynamicCodeActionParamDTO;
import com.cisdi.data.AMETEKSurfaceVision.DynamicCodeActionParamDTO.PropertyConfig;
import com.cisdi.data.common.exception.BusinessException;
import com.cisdi.data.sdk.consts.ServiceName;
import com.cisdi.data.sdk.gateway.message.SocketMessage;
import com.cisdi.data.sdk.gateway.netty.IoSession;
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoSession;
import com.cisdi.data.sdk.service.DynamicCodecService;
import com.cisdi.data.sdk.service.SendService;
import com.cisdi.data.sdk.service.Service;
import com.cisdi.data.sdk.vo.ExeResultVo;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 表检仪协议会话
 *
 * @author tzz
 */
public class SurfaceVisionIoSession extends AbstractIoSession implements IoSession {
    private long lastAliveTime = System.currentTimeMillis();
    private static Logger logger = LoggerFactory.getLogger(SurfaceVisionIoSession.class);
    private String deviceId = null;
    private String gwPrefixCache = null;
    private final static byte[] beat = {0x07,0x7C,0x24,0x0D,0x0A};

    private int count = 1;
    // 初始化为0的原子整型变量作为计数器,用作发送命令的replayId,初始值为1

    /** 当前下发命令replayId */
    private Integer currentCount = -1;

    public void setCurrentSend(SurfaceVisionSocketReturnMessage currentSend) {
        this.currentSend = currentSend;
    }

    /** 当前下发命令信息 */
    private SurfaceVisionSocketReturnMessage currentSend = null;

    public void increment() {
        if (count < SurfaceVisionConstants.MAX_COUNT) {
            count++;
            // 自增1并返回新值
        }
        else {
            count = 1;
        }
    }

    public int getCount() {
        return count;
        // 获取当前计数器的值
    }


    public SurfaceVisionIoSession(String deviceId) {
        this.deviceId = deviceId;
    }

    @Override
    public String[] getDeviceIds() {
        return new String[0];
    }

    /** 获取当前下发电文点位配置信息 */
    private List<PropertyConfig> getPropertyConfig(String msgKeyName){
        //获取DynamicService
        Service service = serviceProvider.getByName(ServiceName.DynamicCodec);
        if (service == null || !(service instanceof DynamicCodecService)) {
            throw new BusinessException("获取DynamicService失败");
        }

        //获取网关ID
        String runId = socketGateway.getInstanceVo().getRunId();

        //获取点位配置信息
        DynamicCodecService dynamicCodecService = (DynamicCodecService)service;
        String actionParam = dynamicCodecService.findByRunIdAndMsgKey(runId, msgKeyName);
        DynamicCodeActionParamDTO dto = null;
        try {
            dto = JSON.parseObject(actionParam, DynamicCodeActionParamDTO.class);
        } catch (Exception e) {
            throw new BusinessException("连接id:" + runId + "电文号:" + msgKeyName + "json转换错误", e);
        }

        if (dto == null || dto.getPropertyList() == null || dto.getPropertyList().isEmpty()) {
            throw new BusinessException("连接id:" + runId + "电文号:" + msgKeyName + "属性列表为空");
        }

        //返回点位信息
        return dto.getPropertyList();
    }

    @Override
    public void onRead(Object message) {
        //获取表检仪上送或返回消息
        ByteBuf inBuf = (ByteBuf) message;

        int length = inBuf.readableBytes();

        //将消息头和消息体拆包，解析出消息头信息
        SurfaceVisionFrameInputVo vo = SurfaceVisionVoDecoder.Decode(inBuf);
        logger.info("AMETEKSurfaceVision收到 msg: {}", vo);

        //消息头，也是电文信息
        String msgKey = vo.getMsgKey();

        try {
            //通过消息头判断返回消息类型
            if(vo.getBeatType()){
                //判断是否心跳信息
                lastAliveTime = System.currentTimeMillis();
                logger.info("接收到心跳消息,当前时间为:{}", lastAliveTime);
            } else if (msgKey.startsWith(SurfaceVisionConstants.RETURN_HEADER1)) {
                //非Query命令正常返回消息
                //解码
                SurfaceVisionVoDecoder.DecodeReturn(vo);

                //组装返回信息，判断replayId是否一致
                ExeResultVo sendResult = new ExeResultVo();
                if (!currentCount.equals(vo.getReplayId())) {
                    logger.info("AMETEKSurfaceVision收到 msgkey: {} 消息:{}, ReplayId：{} 与实际发送下去的:{},不一致"
                        , msgKey, vo, vo.getReplayId(), currentCount);
                    sendResult.setSuccess(false);
                    sendResult.setMessage("返回消息replayId与发送消息replayId不符");
                } else {
                    sendResult.setSuccess(vo.getStatus());
                    sendResult.setMessage(vo.getDescription());
                }

                //组装返回结果
                returnData(sendResult);
            } else if (SurfaceVisionConstants.RETURN_HEADER2.equals(msgKey)) {
                //下发命令异常返回消息
                //解码
                SurfaceVisionVoDecoder.DecodeReturnError(vo);

                ExeResultVo sendResult = new ExeResultVo();
                sendResult.setSuccess(vo.getStatus());
                sendResult.setMessage(vo.getDescription());

                //组装返回结果
                returnData(sendResult);
            } else if (SurfaceVisionConstants.RETURN_HEADER3.equals(msgKey)) {
                //Query命令返回
                //解码
                SurfaceVisionVoDecoder.DecodeReturnQuery(vo);

                ExeResultVo sendResult = new ExeResultVo();
                sendResult.setSuccess(vo.getStatus());
                sendResult.setMessage(vo.getDescription());

                Map<Object, Object> queryData = new HashMap<>();
                queryData.putAll(vo.getReturnData());
                sendResult.setData(queryData);

                //组装返回结果
                returnData(sendResult);
            } else {
                //主动上报消息
                //解码
                SurfaceVisionVoDecoder.DecodeData(vo, getPropertyConfig(msgKey));
                Map<String, Object> realDataMap = vo.getReturnData();

                //数据发送到平台
                if (vo != null && serviceProvider != null && socketGateway != null) {
                    SendService service = (SendService) serviceProvider.getByName(ServiceName.Send);

                    //组装数据包
                    SocketMessage socketMessage = socketGateway.buildSocketMessage();
                    socketMessage.setDeviceId(deviceId);

                    socketMessage.getPropsMap().put(SurfaceVisionConstants.S_V_SEND_PLATFORM_DATA, realDataMap);

                    socketMessage.setMsgKey(msgKey);

                    //发送数据
                    service.sendMessage(socketMessage);
                } else {
                    logger.info("AMETEKSurfaceVision收到 msgkey: {} 消息:{}, 但是不能发到平台", msgKey, JSON.toJSONString(realDataMap));
                }
            }
        }catch (Exception e){
            logger.error("AMETEKSurfaceVision接收消息匹配错误, msgKey: {}, msg:{}, error", msgKey, vo, e);
        }

        if(socketGateway!= null && Boolean.TRUE.equals(socketGateway.getInstanceVo().getLogOpen())) {
            logger.info("AMETEKSurfaceVision {} 报文长度:{} vo:{} ", getChannel(), length,  JSON.toJSONString(vo));
        }

    }

    /** 设置当前下发命令返回信息 */
    private void returnData(ExeResultVo sendResult) {
        if(currentSend == null){
            throw new BusinessException("下发返回消息没有对应的下发命令");
        }
        currentSend.setRealData(sendResult);
        currentSend.setSendReturnFlag(true);
        currentSend = null;
    }

    @Override
    public void onOpen() {
        super.onOpen();
        logger.info("建立连接，channel:{}", getChannel());
    }

    @Override
    public void onClose() {
        super.onClose();
    }

    public void close() {
        if(getChannel() != null) {
            try {
                getChannel().close().sync();
            } catch (InterruptedException e) {
                logger.warn(e.getLocalizedMessage(), e);
            }
        }
    }

    public String gwPrefix() {
        if(gwPrefixCache != null) {
            return gwPrefixCache;
        }

        gwPrefixCache = "";
        if(socketGateway != null && socketGateway.getInstanceVo() != null) {
            gwPrefixCache = "网关Id:" + socketGateway.getInstanceVo().getRunId() + "连接:" + getChannel() + " ";
        }else {
            gwPrefixCache = "连接:" + getChannel() + " ";
        }

        return gwPrefixCache;
    }

    public long getLastAliveTime() {
        return lastAliveTime;
    }

    @Override
    public void send(Object message) {
        //下发命令
        SurfaceVisionSocketReturnMessage returnMsg = (SurfaceVisionSocketReturnMessage) message;
        String msgKey = returnMsg.getMsgKey();

        //与AMETEKSurfaceVisionSocketProtocol类对应
        Map<String, Object> propsMap = (Map<String, Object>)
            returnMsg.getPropsMap().get(SurfaceVisionConstants.S_V_SEND_DATA);

        //获取下发点位配置
        List<PropertyConfig> propertyConfigList = getPropertyConfig(msgKey);

        //获取计数器值作为下发命令replayId
        int c = getCount();
        logger.info("下发数据, 数据:{}, 点位配置:{}, 返回ID:{}", propsMap, propertyConfigList, c);

        ByteBuf byteBuf = SurfaceVisionEncoder.Encode(msgKey, propsMap, propertyConfigList, c);
        logger.info("下发数据的byteBuf:{}", byteBuf);

        //下发命令编码后发送
        getChannel().writeAndFlush(byteBuf);

        logger.info("下发数据成功");

        //缓存当前下发命令信息和replayId
        currentSend = returnMsg;
        currentCount = c;

        //计数器自增
        increment();
    }

    public void sendBeat() {
        logger.info("发送心跳");
        ByteBuf byteBuf = Unpooled.wrappedBuffer(beat);
        getChannel().writeAndFlush(byteBuf);
        logger.info("心跳发送成功");
    }
}
