package com.imdroid.beidou.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.imdroid.beidou.common.HttpResult;
import com.imdroid.common.util.HexUtil;
import com.imdroid.secapi.client.HttpResp;
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.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpSession;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.HashMap;

@Controller
public class CmdLineController extends BasicController{
    SimpleDateFormat dateFormat = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
    @Autowired
    RtcmClient rtcmClient;
    @Autowired
    GnssMsgMapper msgMapper;
    @Autowired
    DeviceCmdMapper deviceCmdMapper;
    @Autowired
    DeviceCacheCmdMapper cacheCmdMapper;
    @Autowired
    OpLogManager opLogManager;

    /**** 推送页面  *****/
    @RequestMapping("/page/cmd_line")
    public String gnssDevCfg(Model m, HttpSession session) {
        initModel(m, session);

        return "/page/cmd_line";
    }

    @RequestMapping("/page/table/frequent_cmd")
    public String frequentCmd(Model m, HttpSession session, String device_id, Integer send_channel) {
        initModel(m, session);
        m.addAttribute("device_id", device_id);
        m.addAttribute("send_channel", send_channel);

        return "/page/table/frequent_cmd";
    }

    @RequestMapping("/page/table/q_cache_cmd")
    public String queryCacheCmd(Model m, HttpSession session) {
        initModel(m, session);

        return "/page/table/q_cache_cmd";
    }

    /****** 发送指令 *******/
    @PostMapping(value = "/gnss/config_cmd")
    @ResponseBody
    public HttpResult configCmd(HttpSession session,
            @RequestParam("tx_win") String cmd,
                            @RequestParam("device_id") String deviceId,
                            @RequestParam("cmd_type") int cmdType,
                                @RequestParam("send_channel") int sendChannel) {
        if(!StringUtils.hasText(deviceId)){
            return HttpResult.fail("设备号不能为空");
        }

        String sendCmd;
        short len = 0;
        int msgType = 0xD310 + cmdType;
        HttpResp<HashMap<String, Object>> rsp;

        if(cmd.startsWith("set")||cmd.startsWith("get")){
            msgType = 0xD3FF;//后台命令
            sendCmd = cmd;
            len = (short) cmd.length();
            if(cmd.charAt(0)=='s') rsp = rtcmClient.configDevice(deviceId,sendCmd);
            else rsp = rtcmClient.getDeviceInfo(deviceId,sendCmd);
        }
        else{
            sendCmd = cmd.replaceAll(" +","");

            if(cmdType == 10 || cmdType==11){ // DTU,string format
                len = (short) (sendCmd.length() + 5);
                sendCmd = Integer.toHexString(msgType) + HexUtil.Short2HexString(len)+
                        HexUtil.Int2HexString(Integer.parseInt(deviceId))+
                        "01"+HexUtil.String2HexString(sendCmd);
            }
            else{ //hex format
                len = (short) (sendCmd.length()/2+4);
                sendCmd = Integer.toHexString(msgType) + HexUtil.Short2HexString(len)+
                        HexUtil.Int2HexString(Integer.parseInt(deviceId))+sendCmd;
            }
            if(sendChannel == 0)
                rsp = rtcmClient.config(deviceId,sendCmd);
            else rsp = rtcmClient.configByUdp(deviceId,sendCmd);
        }

        String txInfo = "TX "+ dateFormat.format(System.currentTimeMillis())+
                " "+deviceId+" "+sendCmd;
        if(cmdType == 1) txInfo += "("+cmd+")";
        if(rsp.getCode() != HttpResp.HTTP_RSP_OK){
            txInfo += "\r\n" + rsp.getResponseMessage();
        }
        else if(msgType == 0xD3FF){
            txInfo += "\r\n" + rsp.getResponseMessage();
        }

        // 保存
        GnssMsg gnssMsg = new GnssMsg();
        gnssMsg.setTenantid(getTenantId(session));
        gnssMsg.setCreatetime(LocalDateTime.now());
        gnssMsg.setDeviceid(deviceId);
        gnssMsg.setMsgtype(msgType);
        gnssMsg.setMsglen((int) len);
        gnssMsg.setTx(true);
        if(cmd.length() >= 100) {
            cmd = cmd.substring(0, 100)+"...";
        }
        gnssMsg.setContent(cmd);
        msgMapper.insert(gnssMsg);

        opLogManager.addLog(getLoginUser(session),getTenantId(session),
                OpLogManager.OP_TYPE_CMD,OpLogManager.OP_OBJ_DEVICE,
                deviceId + ": " + cmd);

        return HttpResult.success(txInfo);
    }

    @PostMapping(value = "/gnss/cache_cmd")
    @ResponseBody
    public HttpResult cacheCmd(HttpSession session,
                                @RequestParam("tx_win") String cmd,
                                @RequestParam("device_id") String deviceId,
                                @RequestParam("cmd_type") int cmdType) {
        String sendCmd = cmd.replaceAll(" +","");
        short len = 0;
        int msgType;
        if(cmdType == 1){ // DTU,string format
            msgType = 0xD31A;
            len = (short) (sendCmd.length() + 5);
            sendCmd = "D31A"+ HexUtil.Short2HexString(len)+
                    HexUtil.Int2HexString(Integer.parseInt(deviceId))+
                    "01"+HexUtil.String2HexString(sendCmd);
        }
        else{ //hex format
            msgType = 0xD310+cmdType;
            len = (short) (sendCmd.length()/2+4);
            sendCmd = Integer.toHexString(msgType) + HexUtil.Short2HexString(len)+
                    HexUtil.Int2HexString(Integer.parseInt(deviceId))+sendCmd;
        }

        // 保存
        if(sendCmd.length() >= DeviceCacheCmd.MAX_CMD_LEN) {
            return HttpResult.fail("指令过长，不能超过325字节");
        }
        DeviceCacheCmd cacheCmd = new DeviceCacheCmd();
        cacheCmd.setDeviceid(deviceId);
        cacheCmd.setUpdatetime(LocalDateTime.now());
        cacheCmd.setType((short) cmdType);
        cacheCmd.setSyn(false);
        cacheCmd.setCmd(sendCmd);
        cacheCmd.setMsgtype(msgType);
        cacheCmdMapper.insert(cacheCmd);

        if(cmd.length() >= 100) {
            cmd = cmd.substring(0, 100)+"...";
        }
        opLogManager.addLog(getLoginUser(session),getTenantId(session),
                OpLogManager.OP_TYPE_CMD,OpLogManager.OP_OBJ_DEVICE,
                deviceId + " cache cmd: " + cmd);

        return HttpResult.success("OK");
    }

    @RequestMapping("/gnss/cmd/list")
    @ResponseBody
    public JSONObject listCmd(int page, int limit) {
        Page<DeviceCmd> pageable = new Page<>(page, limit);
        QueryWrapper<DeviceCmd> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByAsc("sort");
        IPage<DeviceCmd> cs = deviceCmdMapper.selectPage(pageable, queryWrapper);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", 0);
        jsonObject.put("msg", "");
        jsonObject.put("count", cs.getTotal());
        jsonObject.put("data", cs.getRecords());
        return jsonObject;
    }

    @RequestMapping("/gnss/cache_cmd/list")
    @ResponseBody
    public JSONObject listCacheCmd(int page, int limit) {
        Page<DeviceCacheCmd> pageable = new Page<>(page, limit);
        IPage<DeviceCacheCmd> cs = cacheCmdMapper.selectPage(pageable, null);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", 0);
        jsonObject.put("msg", "");
        jsonObject.put("count", cs.getTotal());
        jsonObject.put("data", cs.getRecords());
        return jsonObject;
    }

    private int getMaxSort() {
        QueryWrapper<DeviceCmd> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("sort");
        queryWrapper.last("limit 1");
        DeviceCmd maxSortCmd = deviceCmdMapper.selectOne(queryWrapper);
        return maxSortCmd != null ? maxSortCmd.getSort() : 0;
    }

    @PostMapping("/gnss/cmd/add")
    @ResponseBody
    public String addCmd(@RequestBody JSONObject object) throws Exception {
        DeviceCmd deviceCmd = JSONObject.toJavaObject(object, DeviceCmd.class);
        deviceCmd.setSort(getMaxSort() + 1);
        int num = deviceCmdMapper.insert(deviceCmd);

        if (num == 0) {
            return HttpResult.failed();
        } else{
            return HttpResult.ok();
        }
    }

    @PostMapping("/gnss/cmd/delete")
    @ResponseBody
    public String deleteCmd(@RequestParam int del_id) throws Exception {
        int num = deviceCmdMapper.deleteById(del_id);
        if (num == 0) {
            return HttpResult.failed();
        } else return HttpResult.ok();
    }
    
    @PostMapping("/gnss/cmd/go_top")
    @ResponseBody
    public String topCmd(@RequestParam int id) throws Exception {
        DeviceCmd cmd = deviceCmdMapper.selectById(id);
        if(cmd == null) return HttpResult.failed();

        QueryWrapper<DeviceCmd> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByAsc("sort");
        queryWrapper.last("limit 1");
        DeviceCmd minSortCmd = deviceCmdMapper.selectOne(queryWrapper);
        
        if(minSortCmd != null && !minSortCmd.getId().equals(cmd.getId())) {
            cmd.setSort(minSortCmd.getSort() - 1);
            deviceCmdMapper.updateById(cmd);
        }
        
        return HttpResult.ok();
    }
    
    @PostMapping("/gnss/cmd/go_bottom")
    @ResponseBody
    public String bottomCmd(@RequestParam int id) throws Exception {
        DeviceCmd cmd = deviceCmdMapper.selectById(id);
        if(cmd == null) return HttpResult.failed();
        
        cmd.setSort(getMaxSort() + 1);
        deviceCmdMapper.updateById(cmd);
        
        return HttpResult.ok();
    }
    
    @PostMapping("/gnss/cmd/move_up")
    @ResponseBody
    public String moveUpCmd(@RequestParam int id) throws Exception {
        DeviceCmd cmd = deviceCmdMapper.selectById(id);
        if(cmd == null) return HttpResult.failed();
        
        QueryWrapper<DeviceCmd> queryWrapper = new QueryWrapper<>();
        queryWrapper.lt("sort", cmd.getSort());
        queryWrapper.orderByDesc("sort");
        queryWrapper.last("limit 1");
        DeviceCmd prevCmd = deviceCmdMapper.selectOne(queryWrapper);
        
        if(prevCmd != null) {
            int tempSort = cmd.getSort();
            cmd.setSort(prevCmd.getSort());
            prevCmd.setSort(tempSort);
            
            deviceCmdMapper.updateById(cmd);
            deviceCmdMapper.updateById(prevCmd);
        }
        
        return HttpResult.ok();
    }
    
    @PostMapping("/gnss/cmd/move_down")
    @ResponseBody
    public String moveDownCmd(@RequestParam int id) throws Exception {
        DeviceCmd cmd = deviceCmdMapper.selectById(id);
        if(cmd == null) return HttpResult.failed();
        
        QueryWrapper<DeviceCmd> queryWrapper = new QueryWrapper<>();
        queryWrapper.gt("sort", cmd.getSort());
        queryWrapper.orderByAsc("sort");
        queryWrapper.last("limit 1");
        DeviceCmd nextCmd = deviceCmdMapper.selectOne(queryWrapper);
        
        if(nextCmd != null) {
            int tempSort = cmd.getSort();
            cmd.setSort(nextCmd.getSort());
            nextCmd.setSort(tempSort);
            
            deviceCmdMapper.updateById(cmd);
            deviceCmdMapper.updateById(nextCmd);
        }
        
        return HttpResult.ok();
    }

    @PostMapping("/gnss/cache_cmd/delete")
    @ResponseBody
    public String deleteCacheCmd(@RequestParam int del_id) throws Exception {
        int num = cacheCmdMapper.deleteById(del_id);
        if (num == 0) {
            return HttpResult.failed();
        } else return HttpResult.ok();
    }

    @PostMapping("/gnss/cmd/update")
    @ResponseBody
    public String updateCmd(@RequestBody JSONObject object) throws Exception {
        DeviceCmd deviceCmd = JSONObject.toJavaObject(object, DeviceCmd.class);
        int num = deviceCmdMapper.updateById(deviceCmd);

        if (num == 0) {
            return HttpResult.failed();
        } else {
            return HttpResult.ok();
        }
    }
}
