package com.imdroid.beidou.task;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.yulichang.query.MPJQueryWrapper;
import com.imdroid.beidou.entity.Tenant;
import com.imdroid.beidou.service.NotificationService;
import com.imdroid.secapi.dto.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutionException;

/***
 * 定时任务：
 * 1、定时清理消息表（缺省保留3个月）
 * 2、定时清理原始数据表（缺省保留1个月）
 * 3、定时清理操作日志（缺省保留1年）
 * 4、定时检查设备是否在线
 * 5、定时检查FwdRecords(1 year)
 */

@Slf4j
@Configuration
@EnableScheduling
public class DeviceStatusChecker {
    @Autowired
    GnssStatusMapper gnssStatusMapper;
    @Autowired
    GnssGroupMapper groupMapper;
    @Autowired
    WarningMsgMapper warningMsgMapper;
    @Autowired
    WarningCfgMapper warningCfgMapper;
    @Autowired
    NotificationService notificationService;
    @Autowired
    GnssCalcDataMapper dataMapper;
    @Autowired
    GnssDeviceMapper deviceMapper;
    static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Scheduled(cron = "0 18,48 * * * ?") // 每半时执行一次
    public void checkDeviceState() throws ExecutionException, InterruptedException {
        List<GnssGroup> groupCfgs = groupMapper.selectList(null);
        HashMap<Integer,Integer> group_cycle_map=new HashMap<>();
        for(GnssGroup g:groupCfgs){
            group_cycle_map.put(g.getId(), g.getWork_cycle());
        }

        List<WarningCfg> cfgList = warningCfgMapper.selectList(null);

        int noDataCycles = 2;
        for(WarningCfg cfg: cfgList){
            if(cfg.getType() == WarningCfg.TYPE_DEVICE_OFF_LINE){
                noDataCycles = cfg.getValue();
                break;
            }
        }
        LocalDateTime now = LocalDateTime.now();
        List<GnssStatusJoin> deviceStatuses = gnssStatusMapper.queryOnline();
        List<String> deviceIds = new ArrayList<>();
        for(GnssStatusJoin status : deviceStatuses){
            //如果上次上线到现在超过两个周期，则认为掉线了
            LocalDateTime expiredTime = status.getUpdatetime().plusMinutes(group_cycle_map.get(status.getGroup_id())*noDataCycles);
            if(now.isAfter(expiredTime)){
                status.setState(GnssStatus.STATE_OFFLINE);
                if(status.getWarningcode()==null) status.setWarningcode(0);
                status.setWarningcode(status.getWarningcode() | WarningCfg.TYPE_DEVICE_OFF_LINE);
                status.setWarning(WarningCfg.LEVEL_2);
                gnssStatusMapper.setOfflineByDeviceId(status);
                //告警消息
                WarningMsg warningMsg = new WarningMsg();
                warningMsg.setDevicetype(WarningCfg.TYPE_GNSS);
                warningMsg.setTenantid(status.getTenantid());
                warningMsg.setDeviceid(status.getDeviceid());
                warningMsg.setCreatetime(now);
                warningMsg.setLevel(WarningCfg.LEVEL_2);
                warningMsg.setInfo(WarningCfg.TYPE_NAME_DEVICE_OFF_LINE);
                warningMsg.setCode(WarningCfg.TYPE_DEVICE_OFF_LINE);
                warningMsgMapper.insert(warningMsg);
                //短信推送
                if(status.getTenantid() != Tenant.SAAS_PROVIDER_ID) {
                    deviceIds.add(status.getDeviceid() + "(" + status.getName() + ")");
                }
            }
        }
        if(deviceIds.size()>0){
            notificationService.onWarning(deviceIds.toString(),
                    WarningCfg.TYPE_NAME_DEVICE_OFF_LINE,
                    now.format(formatter), WarningCfg.LEVEL_2);
        }
    }

    @Scheduled(cron = "0 28 * * * ?") // 每小时执行一次
    void checkRoverStationCalcData() throws ExecutionException, InterruptedException {
        // 获取无固定解告警配置
        QueryWrapper<WarningCfg> warningCfgQueryWrapper = new QueryWrapper<>();
        warningCfgQueryWrapper.eq("typename",WarningCfg.TYPE_NAME_NO_FIXED_RESULT);
        warningCfgQueryWrapper.last("limit 1");
        WarningCfg warningCfg = warningCfgMapper.selectOne(warningCfgQueryWrapper);
        if(warningCfg == null) return;

        // 获取所有n个小时内无固定解的测站
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime beginTime = now.minusHours(warningCfg.getValue());
        QueryWrapper<GnssCalcData> calcDataQueryWrapper = new QueryWrapper<>();
        calcDataQueryWrapper.ge("createtime",beginTime.format(formatter));
        List<GnssCalcData> calcDataList = dataMapper.selectList(calcDataQueryWrapper);

        MPJQueryWrapper<GnssStatus> queryWrapper =
                new MPJQueryWrapper<GnssStatus>()
                        .selectAll(GnssStatus.class)
                        .leftJoin("gnssdevices d on t.deviceid = d.deviceid")
                        .eq("d.devicetype",GnssDevice.TYPE_REFERENCE_STATION)
                        .eq("d.opmode",GnssDevice.OP_MODE_USE)
                        .ne("t.state",GnssStatus.STATE_OFFLINE);
        List<GnssStatus> statusList = gnssStatusMapper.selectList(queryWrapper);

        List<String> deviceIds = new ArrayList<>();
        for(GnssStatus status: statusList){
            int warningCode = WarningCfg.TYPE_NO_FIXED_RESULT;
            for(GnssCalcData calcData:calcDataList){
                if(status.getDeviceid().equals(calcData.getDeviceid())){
                    warningCode = 0;
                    break;
                }
            }

            if(warningCode != (status.getWarningcode()&WarningCfg.TYPE_NO_FIXED_RESULT)){
                //清除原来的告警
                if(warningCode == 0) {
                    status.setWarningcode(status.getWarningcode() & ~WarningCfg.TYPE_NO_FIXED_RESULT);
                    status.setWarning(WarningCfg.LEVEL_0);
                }
                else{
                    WarningMsg warningMsg = new WarningMsg();
                    warningMsg.setDeviceid(status.getDeviceid());
                    warningMsg.setTenantid(status.getTenantid());
                    warningMsg.setCreatetime(now);
                    warningMsg.setDevicetype(WarningCfg.TYPE_GNSS);
                    warningMsg.setCode(WarningCfg.TYPE_NO_FIXED_RESULT);
                    warningMsg.setLevel(WarningCfg.LEVEL_2);
                    warningMsg.setInfo(WarningCfg.TYPE_NAME_NO_FIXED_RESULT);
                    warningMsgMapper.insert(warningMsg);

                    status.setWarningcode(status.getWarningcode() | WarningCfg.TYPE_NO_FIXED_RESULT);
                    status.setWarning(WarningCfg.LEVEL_2);
                    deviceIds.add(status.getDeviceid());
                }
                gnssStatusMapper.updateById(status);
            }
        }

        // 发短信通知
        if(deviceIds.size()>0){
            notificationService.onWarning(deviceIds.toString(),
                    WarningCfg.TYPE_NAME_NO_FIXED_RESULT,
                    LocalDateTime.now().format(formatter),
                    WarningCfg.LEVEL_2);
        }
    }

}