package com.imdroid.sideslope.calc;

import com.imdroid.secapi.client.BeidouClient;
import com.imdroid.secapi.dto.*;
import com.imdroid.sideslope.message.BaseMessage;
import com.imdroid.sideslope.message.D341LocationMessage;
import com.imdroid.sideslope.message.D342LocationMessage;
import com.imdroid.sideslope.sal.Device;
import com.imdroid.sideslope.sal.DeviceService;
import com.imdroid.sideslope.service.DataPersistService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

@Service
public class MultiLineGNSSCalcService {

    static class D342Time{
        LocalDateTime createTime;
        LocalDateTime uploadTime;
    }
    private static final Logger logger = LoggerFactory.getLogger(MultiLineGNSSCalcService.class);
    private static final Map<String, D342Time> deviceMap = new ConcurrentHashMap<>();
    private static final Map<String, ResendRecord> fwdRecordMap = new ConcurrentHashMap<>();

    @Autowired
    SingleLineGNSSCalcService calcService;
    @Autowired
    GNSSCalcFilterService gnssCalcFilterService;
    @Autowired
    private ResendRecordMapper resendRecordMapper;
    @Autowired
    private BeidouClient beidouClient;
    @Autowired
    DataPersistService dataPersistService;
    @Resource(name = "local")
    private DeviceService deviceService;

    @Autowired
    GnssGroupCalcMapper groupCalcMapper;
    List<GnssGroupCalc> groupCalcList;

    synchronized GnssGroupCalc getGroupCalc(int groupId){
        if(groupCalcList == null){
            groupCalcList = groupCalcMapper.selectList(null);
        }
        if(groupCalcList != null){
            for(GnssGroupCalc groupCalc:groupCalcList){
                if(groupCalc.getId() == groupId) return groupCalc;
            }
        }
        return null;
    }

    public void calc(D342LocationMessage d342Message){
        // 如果时间跨度大于1分钟，或者不含d341，则计算平滑值
        String deviceId = d342Message.getId();
        D342Time lastD342Time = deviceMap.get(deviceId);
        LocalDateTime msgTime = d342Message.getOriginalTime();
        int d341Count = d342Message.getMessageList().size();
        if(msgTime!=null) logger.debug(deviceId + " proc D342: "+msgTime+" seq:"+d342Message.getSeq()+" D341 num: "+d341Count);

        if(d341Count>0) {
            if(msgTime==null){
                logger.debug(deviceId + " invalid D342");
                return;
            }

            if(lastD342Time != null) {
                logger.debug(deviceId + " last D342: " + lastD342Time.createTime);
                if (msgTime.isAfter(lastD342Time.createTime.plusMinutes(4))) {
                    logger.info(deviceId + " d341 cycle done!");
                    // 计算上轮结果
                    Device device = deviceService.findByDeviceId(deviceId);
                    GnssGroupCalc groupCalc = getGroupCalc(device.getCalcGroupId());
                    calcService.calSingleDone(device, groupCalc, lastD342Time.createTime);
                }
            }
            else{
                logger.info(deviceId + " D342 session begin!");
                lastD342Time = new D342Time();
                deviceMap.put(deviceId, lastD342Time);
                // 产生断点补传通知
                try {
                    beidouClient.onGnssUpload(deviceId, d342Message.getTenantId(), msgTime, "session begin");
                }
                catch (Exception e){

                }
                GnssStatus gnssStatus = dataPersistService.getDeviceState(deviceId);
                if (gnssStatus != null) {
                    gnssStatus.setUpdatetime(LocalDateTime.now());
                    gnssStatus.setState(GnssStatus.STATE_UPLOADING);
                    dataPersistService.updateDeviceState(gnssStatus);
                }
                // 生成推送记录
                createFwdReord(d342Message);
            }

            // 处理d341
            lastD342Time.createTime = msgTime;
            lastD342Time.uploadTime = LocalDateTime.now();

            for(BaseMessage message: d342Message.getMessageList()){
                D341LocationMessage d341Message = (D341LocationMessage)message;
                calcService.calcSingle(d341Message, false);
            }
        }
        else if(lastD342Time != null){
            d342SessionDone(deviceId, d342Message.getTenantId(), lastD342Time.createTime);
        }

    }

    void d342SessionDone(String deviceId, Integer tenantId, LocalDateTime lastDate){
        //补传结束指示
        logger.info(deviceId + " d342 session done! "+lastDate);
        try {
            beidouClient.onGnssUploadComplete(deviceId, tenantId, lastDate);
        }
        catch (Exception e){

        }
        // 计算上轮结果
        Device device = deviceService.findByDeviceId(deviceId);
        GnssGroupCalc groupCalc = getGroupCalc(device.getCalcGroupId());
        calcService.calSingleDone(device, groupCalc, lastDate);
        // 重算最近的
        lastDate = gnssCalcFilterService.updateRpos(device,groupCalc,lastDate);
        // 记录转发表更新为upload done
        ResendRecord fwdRecord = fwdRecordMap.get(deviceId);
        if(fwdRecord != null){
            fwdRecord.setEndtime(lastDate);
            fwdRecord.setState(ResendRecord.STATE_BREAK_POINT);
            resendRecordMapper.insert(fwdRecord);
            fwdRecordMap.remove(deviceId);
        }
        // 移除记录、发完成指示、更新设备状态
        deviceMap.remove(deviceId);
        GnssStatus gnssStatus = dataPersistService.getDeviceState(deviceId);
        if(gnssStatus!=null){
            gnssStatus.setState(GnssStatus.STATE_IDLE);
            dataPersistService.updateDeviceState(gnssStatus);
        }
    }

    void createFwdReord(D342LocationMessage d342Message){
        String deviceId = d342Message.getId();
        // 查找这个设备是否有项目号
        if(d342Message.getFwdId()==null ||
                d342Message.getFwdId().length() ==0 ||
                d342Message.getFwdId().equals(GnssGroupFwd.FWD_TYPE_NONE)) return;

        ResendRecord fwdRecord = new ResendRecord();
        fwdRecord.setDeviceid(deviceId);
        fwdRecord.setTenantid(d342Message.getTenantId());
        fwdRecord.setProjectid(d342Message.getProjectId());
        fwdRecord.setCreatetime(LocalDateTime.now());
        fwdRecord.setStarttime(d342Message.getOriginalTime());
        fwdRecord.setFwd_group_id(d342Message.getFwdId());
        fwdRecordMap.put(deviceId, fwdRecord);
    }

    /**
     * 进入休眠周期，检查正在上传的终端是否长时间没有再收到数据
     * @param deviceId 设备id
     */
    public LocalDateTime checkUploadTime(String deviceId, Integer tenantId){
        D342Time lastD342Time = deviceMap.get(deviceId);
        if(lastD342Time != null){
            LocalDateTime nowTime = LocalDateTime.now();
            if(lastD342Time.uploadTime.isBefore(nowTime.minusMinutes(30))){
                d342SessionDone(deviceId,tenantId,lastD342Time.createTime);
                logger.info("upload broken for half hour, end session");
                return null;
            }
            return lastD342Time.createTime;
        }
        else return null;
    }

    public void refreshGroupCalc(){
        if(groupCalcList!=null) groupCalcList.clear();
        groupCalcList = groupCalcMapper.selectList(null);
        logger.info("group paras changed");
    }
}
