package com.imdroid.sideslope.executor;

import com.imdroid.common.util.DataTypeUtil;
import com.imdroid.common.util.HexUtil;
import com.imdroid.common.util.ThreadManager;
import com.imdroid.secapi.client.BeidouClient;
import com.imdroid.secapi.dto.*;
import com.imdroid.sideslope.message.D3F0SelfCheckMessage;
import com.imdroid.sideslope.service.Device;
import com.imdroid.sideslope.service.DeviceService;
import com.imdroid.sideslope.service.DataPersistService;
import com.imdroid.sideslope.service.GroupParaService;
import com.imdroid.sideslope.web.ApiController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Timer;
import java.util.TimerTask;


/**
 * @author Layton
 * @date 2023/2/2 20:40
 * 1、回ACK，以便终端判断是否连接上服务器后台
 * 2、同步参数
 * 3、判断是否发冷启动指令
 * 4、保存状态信息，判断是否有低电压等告警，清除离线告警
 */
@Component
public class D3F0SelfCheckMessageExecutor implements Executor<D3F0SelfCheckMessage, Void> {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    final String F9PInitCmd = "f9";
    final String GNSSPowerOff = "25 00";
    final String GNSSPowerOn = "25 01";
    final String F9PColdStartCmd = "b56206040400000002001068";
    final String BTCloseMneaCmd = "424be8e1020a00040000ffff";
    final String BTOpenGGACmd = "424b852c0208000400000001";
    final String BTSaveCmd = "424bcc1726040000";

    @Autowired
    private DataPersistService dataPersistService;
    @Autowired
    GnssMsgMapper msgMapper;

    @Autowired
    private BeidouClient beidouClient;
    // 由于消息数据大，从缓存查询设备信息效率更高
    @Autowired
    private DeviceService deviceService;
    @Autowired
    ApiController rtcmClient;
    @Autowired
    GroupParaService groupParaService;

    @Override
    public Void execute(D3F0SelfCheckMessage message) {
        logger.debug("receive d3f0 message of {} device: {}", message.getId(), DataTypeUtil.getHexString(message.getSrcData()));

        Device device = deviceService.findByDeviceId(message.getId());
        if(device == null) return null;
        // 补齐tenantId
        message.setTenantId(device.getTenantId());

        //应答
        sendD3F1Ack(device);
        //更新统计
        device.updateRx(message.getHeader(),message.getLen(),1);
        //更新采样率
        GnssGroup group = groupParaService.getBasicGroup(device.getBasicGroupId());
        if(group!=null) {
            device.setGnssSampleRate(group.getGnss_sample_s());
        }

        ThreadManager.getFixedThreadPool().submit(() -> {
            // 检查是否需要对设备的F9P进行冷启动操作
            if(device.getDeviceType() == Device.DEVICE_ROVER){
                if(device.getModel() == GnssDevice.MODEL_G505){
                    checkAndSendF9PColdStartCommand(device);
                }
                else{
                    checkAndResetBTGnss(device);
                }
            }
            else{
                if(device.getModel() == GnssDevice.MODEL_G510){
                    checkAndResetBTBsGnss(device);
                }
            }
            // 通知beidou服务设备上线，这里会触发参数同步
            GnssStatus lastGnssStatus = dataPersistService.getDeviceState(message.getId());
            try {
                if (lastGnssStatus != null && lastGnssStatus.getState() == GnssStatus.STATE_OFFLINE) {
                    beidouClient.onLine(lastGnssStatus.getDeviceid(),
                            lastGnssStatus.getTenantid(), lastGnssStatus.getUpdatetime());
                } else {
                    beidouClient.onDeviceActive(message.getId(), device.getTenantId());
                }
            }
            catch (Exception e){

            }
            //保存状态信息，判断是否有低电压等告警，清除离线告警
            dataPersistService.saveDeviceState(message);
        });

        return null;
    }

    @Override
    public Class<?> getMessageType() {
        return D3F0SelfCheckMessage.class;
    }

    /*private void checkAndSendF9PPowerOffCommand(Device device){
        if(device.getDeviceId().startsWith("2419") && device.getDeviceType() == Device.DEVICE_ROVER){
            // 连续6个周期无解，则立即发送F9P断电指令
            if(device.getNoFixedAndFloatResult() >= 6){
                sendF9PPowerOffCommand(device);
                logger.debug("{}: 连续{}次无固定解和浮点解，重启F9P",device.getDeviceId(), device.getNoFixedAndFloatResult());
                device.clearNoResultStat();
            }
        }
    }*/

    boolean isBaseStationFwd(Device device){
        Device bsDevice = deviceService.findByDeviceId(device.getParentId());
        if(bsDevice != null){
            LocalDateTime lastRxTime = bsDevice.getLastRxTime();
            if(lastRxTime != null &&
                lastRxTime.isAfter(LocalDateTime.now().minusMinutes(10))){
                return true;
            }
        }
        return false; //最近10分钟基站没有转发数据，可能是基站故障
    }

    private void checkAndSendF9PColdStartCommand(Device device){
        if((device.getWarningcode()&WarningCfg.TYPE_NO_FIXED_RESULT) !=0){
            if(isBaseStationFwd(device)) startF9PColdStartTask(device);
            device.clearNoResultStat();
        }
    }

    void saveMsg(String deviceId, int tenantId, int msgType, String content,boolean isTx){
        GnssMsg gnssMsg = new GnssMsg();
        gnssMsg.setCreatetime(LocalDateTime.now());
        gnssMsg.setTenantid(tenantId);
        gnssMsg.setDeviceid(deviceId);
        gnssMsg.setMsgtype(msgType);
        gnssMsg.setTx(isTx);
        if(content==null) content="";
        gnssMsg.setMsglen(content.length()/2);
        int saveContentLen = content.length();
        if(saveContentLen<=128)
            gnssMsg.setContent(content);
        else
            gnssMsg.setContent(content.substring(0,128));
        msgMapper.insert(gnssMsg);
    }
/*
    void sendF9PPowerOffCommand(Device device){
        int flag = 0xD313;
        String sendCmd = "2500";
        short len =   (short) (sendCmd.length()/2+4);
        sendCmd = Integer.toHexString(flag)+
                HexUtil.Short2HexString(len)+
                HexUtil.Int2HexString(Integer.parseInt(device.getDeviceId()))+
                sendCmd;

        rtcmClient.config(device.getDeviceId(), sendCmd);
        saveMsg(device.getDeviceId(), device.getTenantId(),0xD313, sendCmd, true);
    }
*/
    void sendGnssCommand(Device device, String gnssCmd){
        int msgType = 0xD310;
        short len = (short) (gnssCmd.length()/2+4);
        String sendCmd = Integer.toHexString(msgType) + HexUtil.Short2HexString(len)+
                HexUtil.Int2HexString(Integer.parseInt(device.getDeviceId()))+gnssCmd;
        rtcmClient.config(device.getDeviceId(), sendCmd);
        saveMsg(device.getDeviceId(), device.getTenantId(),msgType, sendCmd, true);
    }

    //example: d31300050080F2B3f9
    void sendDebugCommand(Device device, String cmd){
        int msgType = 0xD313;
        short len = (short) (cmd.length()/2+4);
        String sendCmd = Integer.toHexString(msgType) + HexUtil.Short2HexString(len)+
                HexUtil.Int2HexString(Integer.parseInt(device.getDeviceId()))+cmd;
        rtcmClient.config(device.getDeviceId(), sendCmd);
        saveMsg(device.getDeviceId(), device.getTenantId(),msgType, sendCmd, true);
    }
    void sendD3F1Ack(Device device){
        int flag = 0xD3F1;
        short len =   (short) (4);
        String sendCmd = Integer.toHexString(flag)+
                HexUtil.Short2HexString(len)+
                HexUtil.Int2HexString(Integer.parseInt(device.getDeviceId()));

        rtcmClient.config(device.getDeviceId(), sendCmd);
    }

    private void checkAndResetBTGnss(Device device){
        if(device.getNoFixedAndFloatResult()>0 &&device.getAbnormalD341Num()>10){
            if(isBaseStationFwd(device)) startBTResetTask(device);
            device.clearNoResultStat();
        }
        else if((device.getWarningcode()&WarningCfg.TYPE_CONT_INVALID_RESULT) !=0){
            if(isBaseStationFwd(device)) startBTHotStartTask(device);
            device.clearNoResultStat();
        }
    }

    private void checkAndResetBTBsGnss(Device device){
        if(device.getD341Count() < 50){
            startBTBsResetTask(device);
        }
    }

    void startF9PColdStartTask(Device device){
        Timer timer = new Timer();
        for(int delay=1; delay<=10; delay++) {
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    sendGnssCommand(device, F9PColdStartCmd);
                }
            }, delay*1500);
        }
    }

    void startBTHotStartTask(Device device){
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                sendGnssCommand(device, BTSaveCmd);
            }
        },1000);
    }

    void startBTBsResetTask(Device device){
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                sendGnssCommand(device, GNSSPowerOff);
            }
        },1000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                sendGnssCommand(device, GNSSPowerOn);
            }
        },11000);
    }

    void startBTResetTask(Device device){
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                sendGnssCommand(device, BTCloseMneaCmd);
            }
        },1000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                sendGnssCommand(device, BTCloseMneaCmd);
            }
        },4000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                sendGnssCommand(device, BTOpenGGACmd);
            }
        },7000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                sendGnssCommand(device, BTOpenGGACmd);
            }
        },10000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                sendGnssCommand(device, BTSaveCmd);
            }
        },13000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                sendGnssCommand(device, BTSaveCmd);
            }
        },16000);
    }


}
