package com.imdroid.sideslope.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.imdroid.common.util.NumberUtils;
import com.imdroid.secapi.dto.*;
import com.imdroid.sideslope.sal.Device;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class WarningServiceImpl implements WarningService {
    @Autowired
    WarningCfgMapper warningCfgMapper;
    @Autowired
    WarningMsgMapper warningMsgMapper;
    @Autowired
    GnssStatusMapper gnssStatusMapper;

    // warning type <-> level & value
    Map<Integer, int[]> cfgMap = new ConcurrentHashMap<>();
    int warningLevel2Code = 0;

    @PostConstruct
    @Override
    public void refreshCfg(){
        QueryWrapper<WarningCfg> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("devicetype", WarningCfg.TYPE_GNSS);
        List<WarningCfg> cfgList = warningCfgMapper.selectList(null);
        cfgMap.clear();
        for(WarningCfg cfg: cfgList){
            cfgMap.put(cfg.getType(),new int[]{cfg.getLevel(),cfg.getValue()});
            if(cfg.getLevel() == WarningCfg.LEVEL_2){
                warningLevel2Code |= cfg.getType();
            }
        }
    }
    /***
     * 检查一个周期内的b562数量是否足够
     */
    @Override
    public void checkB562Num(String deviceId, Integer tenantId,
                             int[] numB562Stat){
        GnssStatus status = gnssStatusMapper.getByDeviceId(deviceId);
        if(status == null) return;

        boolean isUpdated = false;
        if ((status.getWarningcode() & WarningCfg.TYPE_LESS_D3XX) != 0) {
            status.setWarningcode(status.getWarningcode() & ~WarningCfg.TYPE_LESS_D3XX);
            isUpdated = true;
        }

        // b562少
        if(check(status, WarningCfg.TYPE_LESS_B562,
                WarningCfg.TYPE_NAME_LESS_B562,true,
                numB562Stat[0],null,
                "固定解:"+numB562Stat[0]+",浮点解:"+numB562Stat[1]+",全零:"+numB562Stat[2])) isUpdated=true;

        //清除连续无b562
        if(0 != numB562Stat[0]){
            if ((status.getWarningcode() & WarningCfg.TYPE_NO_FIXED_RESULT) != 0) {
                status.setWarningcode(status.getWarningcode() & ~WarningCfg.TYPE_NO_FIXED_RESULT);
                isUpdated = true;
            }
        }

        if(isUpdated){
            // 根据告警码确定告警级别
            status.setWarning(getWarningLevel(status.getWarningcode()));
            gnssStatusMapper.updateById(status);
        }
    }
    /***
     * 检查电压、RSSI等
     */
    @Override
    public void checkDeviceStatus(GnssStatusMsg statusMsg, GnssStatus curStatus){
        // 清除离线告警
        if(curStatus.getWarningcode() == null) curStatus.setWarningcode(0);
        boolean isUpdated = false;

        if ((curStatus.getWarningcode() & WarningCfg.TYPE_DEVICE_OFF_LINE) != 0) {
            curStatus.setWarningcode(curStatus.getWarningcode() & ~WarningCfg.TYPE_DEVICE_OFF_LINE);
            isUpdated = true;
        }

        //低电压告警
        if(statusMsg.getVoltage()!=null) {
            if(check(curStatus, WarningCfg.TYPE_LOW_VOLTAGE,
                    WarningCfg.TYPE_NAME_LOW_VOLTAGE,true,
                    statusMsg.getVoltage(), null,null)) isUpdated=true;
        }
        //低RSSI
        if(statusMsg.getRssi()!=null) {
            if(check(curStatus, WarningCfg.TYPE_LOW_RSSI,
                    WarningCfg.TYPE_NAME_LOW_RSSI,true,
                    statusMsg.getRssi().intValue(), null,null)) isUpdated=true;
        }
        //倾角异常告警
        if(statusMsg.getPitch()!=null) {
            if(check(curStatus, WarningCfg.TYPE_INCLINE,
                    WarningCfg.TYPE_NAME_INCLINE,false,
                    Math.abs(statusMsg.getPitch().intValue()),
                    Math.abs(statusMsg.getRoll().intValue()),
            "pitch:"+ NumberUtils.scaleTwo(statusMsg.getPitch().doubleValue())
                    +",roll:"+NumberUtils.scaleTwo(statusMsg.getRoll().doubleValue()))) isUpdated=true;
        }
        //卫星数
        if(curStatus.getSatelliteinuse()!=null){
            if(check(curStatus,WarningCfg.TYPE_LESS_INUSE_SAT,
                    WarningCfg.TYPE_NAME_LESS_INUSE_SAT,true,
                    curStatus.getSatelliteinuse(),null,null)) isUpdated=true;
        }

        // 根据告警码确定告警级别
        if(isUpdated){
            curStatus.setWarning(getWarningLevel(curStatus.getWarningcode()));
        }

    }

    boolean check(GnssStatus curStatus, int warningType, String warningName,
                  boolean isLessCmp, Integer value1, Integer value2, String auxInfo){
        boolean isUpdated=false;
        int newWarningCode = 0;
        int[] warningValues = cfgMap.get(warningType);
        if(warningValues!=null){
            if(isLessCmp) {
                if (value1 != null && value1 <= warningValues[1]) {
                    newWarningCode = warningType;
                }
                if (value2 != null && value2 <= warningValues[1]) {
                    newWarningCode = warningType;
                }
            }
            else{
                if (value1 != null && value1 >= warningValues[1]) {
                    newWarningCode = warningType;
                }
                if (value2 != null && value2 >= warningValues[1]) {
                    newWarningCode = warningType;
                }
            }
        }

        int oldWarningCode = curStatus.getWarningcode() & warningType;
        if(newWarningCode != oldWarningCode){
            if(newWarningCode == 0){
                curStatus.setWarningcode(curStatus.getWarningcode() & ~warningType);
            }
            else {
                WarningMsg warningMsg = new WarningMsg();
                warningMsg.setDeviceid(curStatus.getDeviceid());
                warningMsg.setTenantid(curStatus.getTenantid());
                warningMsg.setCreatetime(LocalDateTime.now());
                warningMsg.setDevicetype(WarningCfg.TYPE_GNSS);
                warningMsg.setCode(warningType);
                warningMsg.setLevel((short) warningValues[0]);
                if(auxInfo ==null) {
                    auxInfo = warningName + ":" + value1;
                    if (value2 != null) auxInfo = auxInfo + "," + value2;
                }
                else auxInfo = warningName + ":" + auxInfo;
                warningMsg.setInfo(auxInfo);
                warningMsgMapper.insert(warningMsg);
                //告警级别
                curStatus.setWarningcode(curStatus.getWarningcode() | warningType);
            }
            isUpdated = true;
        }
        return isUpdated;
    }

    /***
     * 检查未知报文是否较多
     */
    @Override
    public void checkTrx(GnssTrxMsg msg, GnssStatus curStatus){

    }

    public short getWarningLevel(int warningCode){
        if(warningCode == 0) return WarningCfg.LEVEL_0;
        else if((warningCode & warningLevel2Code) !=0 ) return WarningCfg.LEVEL_2;
        else return WarningCfg.LEVEL_1;
    }

    @Override
    public void checkD3xxNum(Device device){
        GnssStatus status = gnssStatusMapper.getByDeviceId(device.getDeviceId());
        if(status != null) {
            boolean isUpdated = false;
            // 清除b562告警
            if((status.getWarningcode() & (WarningCfg.TYPE_NO_FIXED_RESULT
                    |WarningCfg.TYPE_LESS_B562)) !=0 ) {
                status.setWarningcode(status.getWarningcode() & ~WarningCfg.TYPE_NO_FIXED_RESULT);
                status.setWarningcode(status.getWarningcode() & ~WarningCfg.TYPE_LESS_B562);
                isUpdated = true;
            }
            // 检查d331告警
            if(check(status, WarningCfg.TYPE_LESS_D3XX,
                    WarningCfg.TYPE_NAME_LESS_D3XX,true,
                    device.getD3xxCount(), null,null)) isUpdated=true;

            if(isUpdated) {
                status.setWarning(getWarningLevel(status.getWarningcode()));
                gnssStatusMapper.updateById(status);
            }
        }
    }
}
