package com.imdroid.beidou.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.imdroid.common.util.ByteUtil;
import com.imdroid.common.util.HexUtil;
import com.imdroid.secapi.client.RtcmClient;
import com.imdroid.secapi.dto.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.List;

@Controller
public class APIController extends BasicController {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
    final String verServerConnectCmd = "AT+QIOPEN=1,2,\"TCP\",\"iot.im-droid.com\",7665,0,1";
    @Autowired
    RtcmClient rtcmClient;
    @Autowired
    GnssDeviceMapper deviceMapper;
    @Autowired
    GnssGroupMapper groupMapper;
    @Autowired
    GnssGroupCalcMapper groupCalcMapper;
    @Autowired
    GnssMsgMapper msgMapper;
    @Autowired
    DeviceCacheCmdMapper cacheCmdMapper;
    @Autowired
    WarningMsgMapper warningMsgMapper;
    @Autowired
    GnssStatusMapper gnssStatusMapper;

    /****** config ack *******/
    @PostMapping(value = "/api/config_ack")
    @ResponseBody
    public String onConfigAck(String deviceId, Integer tenantId, String configAck) {
        GnssDevice device = deviceMapper.queryByDeviceId(deviceId);
        if (device == null) return null;

        int msgType = Integer.parseInt(configAck.substring(0, 4), 16);
        // 配置是否成功
        if (msgType == 0xd311) {
            //最后一个字节为1表示配置成功，0表示配置失败
            if (configAck.endsWith("01")) {
                device.setSyn(true);
                deviceMapper.updateById(device);
            }
        } else if (msgType == 0xd312) {
            // 工作周期一致性检查
            checkWorkCycle(device, configAck);
        } else if (msgType == 0xd313) {
            if(device.getChange_flag()!=0) {
                if(device.clearChangeFlag(configAck)){
                    deviceMapper.updateById(device);
                }
            }
        }

        // 保存, debug 01 02上来的原始数据不保存
        if (msgType != 0xd313 || configAck.length() < 100) {
            saveMsg(deviceId, tenantId, msgType, configAck, false);
        }

        // 命令行显示
        String rxInfo = "RX " + dateFormat.format(System.currentTimeMillis()) +
                " " + deviceId + " ";
        if (msgType == 0xd31a || msgType == 0xd31b) {
            //转成字符串
            String dtuAck = configAck.substring(9 * 2);
            rxInfo += configAck + "(" + HexUtil.HexString2String(dtuAck) + ")";

            // 检查是否需要更新 ICCID
            updateICCID(device, dtuAck);
        } else if (msgType == 0xd313 && configAck.length() >= 90) {
            //转成字符串
            String dtuAck = configAck.substring(26 * 2);
            rxInfo += configAck + "(" + HexUtil.HexString2String(dtuAck) + ")";
        } else {
            rxInfo += configAck;
        }

        CmdLineWebSocketServer.sendMessageToAll(rxInfo);
        return null;
    }

    void checkWorkCycle(GnssDevice device, String cfgData) {
        // d3 12 00 12 00 81 e7 6f 01 0a09000001c2dd7ae1419ee148
        int pos = 9;
        byte[] hexValues = ByteUtil.hexStringTobyte(cfgData);
        byte workCycle = hexValues[pos++];
        byte workDur = hexValues[pos++];
        byte workOffset = hexValues[pos++];

        GnssGroup gnssGroup = groupMapper.selectById(device.getGroup_id());
        if (gnssGroup != null) {
            if (gnssGroup.getWork_cycle() != workCycle ||
                    gnssGroup.getActive_time() != workDur ||
                    gnssGroup.getActive_offset() != workOffset) {
                //产生告警
                WarningMsg warningMsg = new WarningMsg();
                warningMsg.setDeviceid(device.getDeviceid());
                warningMsg.setTenantid(device.getTenantid());
                warningMsg.setCreatetime(LocalDateTime.now());
                warningMsg.setDevicetype(WarningCfg.TYPE_GNSS);
                warningMsg.setCode(WarningCfg.TYPE_CFG_ABNORMAL);
                warningMsg.setLevel(WarningCfg.LEVEL_2);
                warningMsg.setInfo(WarningCfg.TYPE_NAME_CFG_ABNORMAL);
                warningMsgMapper.insert(warningMsg);
                //重新配置
                String sendCmd = gnssGroup.getConfigCmd(device);
                rtcmClient.config(device.getDeviceid(), sendCmd);
                // 保存
                saveMsg(device.getDeviceid(), device.getTenantid(), 0xD311, sendCmd, true);
            }
        }
    }

    /****** device active *******/
    @PostMapping(value = "/api/device_online")
    @ResponseBody
    public String onLine(String deviceId, Integer tenantId, LocalDateTime lastOnlineTime) {
        onDeviceActive(deviceId, tenantId);
        // 检查参数一致性
        String getWorkCycleCmd = "d3120005" +
                HexUtil.Int2HexString(Integer.parseInt(deviceId)) + "01";
        rtcmClient.config(deviceId, getWorkCycleCmd);
        // 保存
        saveMsg(deviceId, tenantId, 0xD312, getWorkCycleCmd, true);

        // 检查是否自动补传
        GnssDevice device = deviceMapper.queryByDeviceId(deviceId);
        if (device == null) return null;
        GnssGroupCalc groupCalc = groupCalcMapper.selectById(device.getCalc_group_id());
        if (groupCalc == null || !groupCalc.getAuto_upload()) return null;

        // 检查上次是否离线，如果是则启动补传
        LocalDateTime now = LocalDateTime.now();
        short len = 15;
        String uploadCmd = "D312" + HexUtil.Short2HexString(len) +
                HexUtil.Int2HexString(Integer.parseInt(deviceId)) +
                "1B"
                + HexUtil.Byte2HexString((byte) (lastOnlineTime.getYear() - 2000))
                + HexUtil.Byte2HexString((byte) (lastOnlineTime.getMonthValue()))
                + HexUtil.Byte2HexString((byte) (lastOnlineTime.getDayOfMonth()))
                + HexUtil.Byte2HexString((byte) (lastOnlineTime.getHour()))
                + HexUtil.Byte2HexString((byte) (lastOnlineTime.getMinute()))
                + HexUtil.Byte2HexString((byte) (now.getYear() - 2000))
                + HexUtil.Byte2HexString((byte) (now.getMonthValue()))
                + HexUtil.Byte2HexString((byte) (now.getDayOfMonth()))
                + HexUtil.Byte2HexString((byte) (now.getHour()))
                + HexUtil.Byte2HexString((byte) (now.getMinute()));
        rtcmClient.config(deviceId, uploadCmd);
        // 保存
        saveMsg(deviceId, tenantId, 0xD312, uploadCmd, true);

        return null;
    }

    /****** device active *******/
    @PostMapping(value = "/api/device_active")
    @ResponseBody
    public String onDeviceActive(String deviceId, Integer tenantId) {

        // 检查有没有待配置的参数
        GnssDevice device = deviceMapper.queryByDeviceId(deviceId);
        if (device == null) return null;

        if (!device.getSyn()) {
            GnssGroup gnssGroup = groupMapper.selectById(device.getGroup_id());
            if (gnssGroup != null) {
                String config = gnssGroup.getConfigCmd(device);
                if (config != null) {
                    rtcmClient.config(deviceId, config);
                    // 保存
                    saveMsg(deviceId, tenantId, 0xd311, config, true);
                }
            }
        }
        List<String> deviceCmds = device.getConfigCmd();
        for(String deviceCmd:deviceCmds){
            rtcmClient.config(deviceId, deviceCmd);
            // 保存
            saveMsg(deviceId, tenantId, 0xd312, deviceCmd, true);

        }

        // 检查有没有待发送的指令
        QueryWrapper<DeviceCacheCmd> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("deviceid", deviceId);
        queryWrapper.eq("syn", false);
        queryWrapper.last("limit 1");
        DeviceCacheCmd cacheCmd = cacheCmdMapper.selectOne(queryWrapper);
        if (cacheCmd != null) {
            rtcmClient.config(deviceId, cacheCmd.getCmd());
            cacheCmd.setSyn(true);
            cacheCmd.setUpdatetime(LocalDateTime.now());
            cacheCmdMapper.updateById(cacheCmd);
            // 保存
            saveMsg(deviceId, tenantId, cacheCmd.getMsgtype(), cacheCmd.getCmd(), true);
        }

        // 检查iccid
        checkAndAskICCID(device);

        return null;
    }

    /****** device stop *******/
    @PostMapping(value = "/api/device_stop")
    @ResponseBody
    public String onDeviceStop(String deviceId, Integer tenantId) {

        return null;
    }

    /****** gnss upload *******/
    @PostMapping(value = "/api/gnss_upload")
    @ResponseBody
    public String onGnssUpload(String deviceId, Integer tenantId, LocalDateTime uploadTime, String info) {
        saveMsg(deviceId, tenantId, 0xd342,
                "gnss data upload from " + uploadTime + ", " + info, false);
        return null;
    }

    @PostMapping(value = "/api/gnss_upload_pause")
    @ResponseBody
    public String onGnssUploadPause(String deviceId, Integer tenantId) {
        saveMsg(deviceId, tenantId, 0xd342, "gnss data upload pause", false);
        return null;
    }

    @PostMapping(value = "/api/gnss_upload_complete")
    @ResponseBody
    public String onGnssUploadComplete(String deviceId, Integer tenantId, LocalDateTime uploadTime) {
        saveMsg(deviceId, tenantId, 0xd342, "gnss data upload completely at " + uploadTime, false);
        return null;
    }

    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 checkAndAskICCID(GnssDevice device) {
        GnssStatus status = gnssStatusMapper.getByDeviceId(device.getDeviceid());

        // 1. 检查设备是否有 ICCID记录 （初始化）
        // 2. 检查设备是否从离线恢复 （防止更换 SIM 卡）
        // 3. 如果两种情况都不满足，则不查询 ICCID

        boolean isDeviceReconnecting = status != null && status.getState() == GnssStatus.STATE_OFFLINE;
        boolean isIccidEmpty = device.getIccid() == null || device.getIccid().trim().isEmpty();

        if (!isDeviceReconnecting && !isIccidEmpty) {
            return;
        }

        String sendCmd = "AT+ICCID";
        int msgType = 0xD310 + 10; // DTU
        short len = (short) (sendCmd.length() + 5);
        sendCmd = Integer.toHexString(msgType) + HexUtil.Short2HexString(len) +
                HexUtil.Int2HexString(Integer.parseInt(device.getDeviceid())) +
                "01" + HexUtil.String2HexString(sendCmd);
        rtcmClient.config(device.getDeviceid(), sendCmd);
    }
    void updateICCID(GnssDevice device, String dtuAck) {
        // 只检查 "ICCID:" 的十六进制部分
        if(!dtuAck.contains("49434349443a")){
            return;
        }
        String content = HexUtil.HexString2String(dtuAck);
        if(content.contains("+ICCID:")){
            String iccid = content.substring(content.indexOf("+ICCID:") + 8).trim();
            iccid = iccid.split("\r\n")[0].trim();
            device.setIccid(iccid);
            deviceMapper.updateById(device);
        }
    }

    /****** upgrade operations *******/
    @PostMapping(value = "/api/upgrade_ack")
    @ResponseBody
    public String onUpgradeAck() {
        //发连接服务器指令
        QueryWrapper<GnssDevice> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("opmode", GnssDevice.OP_MODE_UPGRADING);
        List<GnssDevice> gnssDeviceList = deviceMapper.selectList(queryWrapper);
        for (GnssDevice device : gnssDeviceList) {
            short len = (short) (verServerConnectCmd.length() + 5);
            String sendCmd = "d31a" + HexUtil.Short2HexString(len) +
                    HexUtil.Int2HexString(Integer.parseInt(device.getDeviceid())) +
                    "01" + HexUtil.String2HexString(verServerConnectCmd);
            rtcmClient.config(device.getDeviceid(), sendCmd);
        }
        //界面的升级按钮变灰
        UpgradeWebSocketServer.sendMessageToAll("on upgrade ack");
        return null;
    }

    @PostMapping(value = "/api/upgrading_ind")
    @ResponseBody
    public String onUpgradingInd(String deviceId, Byte progress) {
        UpgradeWebSocketServer.sendMessageToAll("on upgrade ind " + deviceId + "," + progress);
        return null;
    }

    @PostMapping(value = "/api/upgrade_complete_ind")
    @ResponseBody
    public String onUpgradeCompleteInd(String deviceId, Byte code) {
        UpgradeWebSocketServer.sendMessageToAll("on upgrade complete ind " + deviceId + "," + code);
        // 保存升级记录
        return null;
    }
}