package com.imdroid.beidou_fwd.task;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.imdroid.common.util.ThreadManager;
import com.imdroid.secapi.dto.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

public class Forwarder {
    final Logger logger = LoggerFactory.getLogger(Forwarder.class);

    String fwdGroupId;
    String description;
    Integer tenantId;
    boolean useFwdId;
    int totalSendNum = 0;

    int fwdCycleMinutes = 30;
    static boolean isFwdTableInit = false;

    @Autowired
    private GnssDeviceMapper deviceMapper;

    @Autowired
    private GnssCalcDataMapper gnssDataMapper;

    @Autowired
    private FwdRecordMapper fwdRecordsMapper;
    @Autowired
    private ResendRecordMapper resendRecordMapper;
    @Autowired
    private GnssStatusMapper gnssStatusMapper;

    @Autowired
    GnssGroupFwdMapper fwdMapper;

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /***
     *
     * @param fwdGroupId,推送组名
     * @param desc，推送组描述
     * @param tenantId，租户Id
     * @param useFwdId，是否使用转发名，如果不使用，则用deviceId
     * @param cycle，发送周期
     */
    void init(String fwdGroupId, String desc, Integer tenantId, boolean useFwdId, int cycle){
        this.fwdGroupId = fwdGroupId;
        this.description = desc;
        this.tenantId = tenantId;
        this.useFwdId = useFwdId;
        this.fwdCycleMinutes = cycle;

        if(!isFwdTableInit){
            isFwdTableInit = true;
            fwdMapper.delete(null);
        }
        QueryWrapper<GnssGroupFwd> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name",fwdGroupId);
        GnssGroupFwd gnssGroupFwd = fwdMapper.selectOne(queryWrapper);
        if(gnssGroupFwd == null){
            gnssGroupFwd = new GnssGroupFwd();
            gnssGroupFwd.setName(fwdGroupId);
            gnssGroupFwd.setDescription(description);
            gnssGroupFwd.setDevice_num(0);
            fwdMapper.insert(gnssGroupFwd);
        }
        else{
            gnssGroupFwd.setDescription(description);
            fwdMapper.updateById(gnssGroupFwd);
        }
    }

    /***
     * 推送指定企业、设备ID、时间的GNSS记录，查找指定时间前cycle分钟的有效数据推送
     * @param sendTime：要推送的记录的时间
     * @param deviceId：设备ID，如果没有指定，则推送全部
     */
    private boolean forwardGnssRecords(LocalDateTime sendTime, String deviceId, ResendRecord resendRecord) {
        String endTime = sendTime.format(formatter);
        String beginTime = sendTime.minusMinutes(fwdCycleMinutes).format(formatter);

        // 查找属于指定推送组的设备列表
        QueryWrapper<GnssDevice> queryWrapper = new QueryWrapper<>();
        if(deviceId != null){
            queryWrapper.eq("deviceid", deviceId);
        }
        queryWrapper.eq("fwd_group_id", fwdGroupId)
                .or()
                .eq("fwd_group_id2", fwdGroupId);
        List<GnssDevice> gnssDeviceList = deviceMapper.selectList(queryWrapper);

        // 查询最近半小时的GNSS记录
        QueryWrapper<GnssCalcData> gnssQueryWrapper = new QueryWrapper<>();
        gnssQueryWrapper.ge("createtime",beginTime);
        gnssQueryWrapper.le("createtime",endTime);
        gnssQueryWrapper.orderByDesc("createtime");
        gnssQueryWrapper.eq("enabled",true);
        gnssQueryWrapper.isNotNull("rpose");
        if(deviceId != null){
            gnssQueryWrapper.eq("deviceid", deviceId);
        }
        List<GnssCalcData> locationRecords = gnssDataMapper.selectList(gnssQueryWrapper);
        if(locationRecords.size() == 0) return false;

        // 构造按项目id分类的GNSS记录
        ConcurrentHashMap<String, List<GnssCalcData>> projects = new ConcurrentHashMap<>();
        for(GnssDevice device:gnssDeviceList){
            if(device.getOpmode() != GnssDevice.OP_MODE_USE) continue;
            String projectId = device.getProject_id();
            if(device.getProject2_id()!=null && !device.getProject2_id().isBlank()) {
                // 推送组2用项目2的id号
                String fwdGroupId2 = device.getFwd_group_id2();
                if (fwdGroupId2 != null && fwdGroupId2.equals(fwdGroupId)) {
                    projectId = device.getProject2_id();
                }
            }
            if(projectId == null) continue;

            List<GnssCalcData> recordsToSend = projects.get(projectId);
            if(recordsToSend == null){
                recordsToSend = new ArrayList<>();
                projects.put(projectId,recordsToSend);
            }
            for(GnssCalcData record:locationRecords){
                if(record.getDeviceid().equals(device.getDeviceid())) {
                    // 替换成推送用的名字和数值
                    if (device.getIpose() != null &&
                            device.getIposn() != null &&
                            device.getIposd() != null) {
                        record.setRpose(record.getRpose() - device.getIpose());
                        record.setRposn(record.getRposn() - device.getIposn());
                        record.setRposd(record.getRposd() - device.getIposd());
                    }
                    if (useFwdId && device.getFwddeviceid() != null && !device.getFwddeviceid().isBlank()) {
                        record.setDeviceid(device.getFwddeviceid());
                    }
                    recordsToSend.add(record);
                    break;
                }
            }
        }

        // 按项目打包推送
        totalSendNum = 0;
        boolean fwdResult = true;
        for (Map.Entry<String, List<GnssCalcData>> entry: projects.entrySet()){
            String projectId = entry.getKey();
            List<GnssCalcData> records = entry.getValue();
            if(records.size() == 0) continue;

            int sendNum = send(projectId, records, sendTime);

            // 记录推送
            FwdRecord fwdRecord = new FwdRecord();
            fwdRecord.setProjectid(projectId);
            fwdRecord.setTenantid(tenantId);
            fwdRecord.setDevicenum((short) records.size());
            fwdRecord.setRecordtime(sendTime);
            fwdRecord.setCreatetime(LocalDateTime.now());
            fwdRecord.setFwd_group_id(fwdGroupId);
            if(sendNum > 0) {
                totalSendNum += sendNum;
                fwdRecord.setResult(FwdRecord.RESULT_OK);
                if(resendRecord != null){
                    resendRecord.setState(ResendRecord.STATE_FWD_OK);
                    resendRecordMapper.updateById(resendRecord);
                }
            }
            else{
                fwdResult = false;
                fwdRecord.setResult(FwdRecord.RESULT_FAILED);
                // 新增重发记录
                if(resendRecord == null) {
                    resendRecord = new ResendRecord();
                    resendRecord.setProjectid(projectId);
                    resendRecord.setTenantid(tenantId);
                    resendRecord.setCreatetime(LocalDateTime.now());
                    resendRecord.setStarttime(sendTime);
                    resendRecord.setEndtime(sendTime);
                    resendRecord.setFwd_group_id(fwdGroupId);
                    resendRecord.setState(ResendRecord.STATE_FWD_FAILED);
                    resendRecordMapper.insert(resendRecord);
                }
                else{
                    resendRecord.setState(ResendRecord.STATE_FWD_FAILED);
                    resendRecordMapper.updateById(resendRecord);
                }
            }
            fwdRecordsMapper.insert(fwdRecord);
        }

        // 更新推送记录
        if(totalSendNum>0) updateFwd(totalSendNum, true);
        else if(!fwdResult) updateFwd(totalSendNum, false);

        return fwdResult;
    }

    void forwardCurrentGnss() {
        if(forwardGnssRecords(LocalDateTime.now(),null,null)) {
            // 推送失败记录、补发记录
            ThreadManager.getScheduledThreadPool().schedule(() -> {
                this.forwardHistoryGnss();
            },100, TimeUnit.SECONDS);
        }
    }

    void forwardHistoryGnss() {
        // 1.从转发记录表里检索待补传记录时间表，含设备Id，时间段
        QueryWrapper<ResendRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("fwd_group_id",fwdGroupId);
        queryWrapper.ne("state",ResendRecord.STATE_FWD_OK);
        List<ResendRecord> resendRecordsList = resendRecordMapper.selectList(queryWrapper);
        // 2.检索这个这个时间段的解算结果，如果有数据则单个终端转发，标志记录为已补传
        for(ResendRecord record:resendRecordsList){
            forwardBatchGnssRecords(record);
        }
    }

    void forwardBatchGnssRecords(ResendRecord record) {
        LocalDateTime sendTime = record.getStarttime();
        while(sendTime.isBefore(record.getEndtime()) || sendTime.isEqual(record.getEndtime())){
            forwardGnssRecords(sendTime,record.getDeviceid(),record);
            sendTime = sendTime.plusMinutes(fwdCycleMinutes);
        }
    }

    int send(String projectId, List<GnssCalcData> records, LocalDateTime sentTime) {
        return 0;
    }

    void updateFwd(int fwd_num, boolean isFwdOK){
        QueryWrapper<GnssGroupFwd> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name",fwdGroupId);
        GnssGroupFwd gnssGroupFwd = fwdMapper.selectOne(queryWrapper);
        if(gnssGroupFwd != null){
            gnssGroupFwd.setFwd_device_num(fwd_num);
            gnssGroupFwd.setResult(isFwdOK);
            gnssGroupFwd.setUpdatetime(LocalDateTime.now());
            fwdMapper.updateById(gnssGroupFwd);
        }
    }

    void checkOfflineDevice(String offDeviceId, String refDeviceId1, String refDeviceId2){
        QueryWrapper<GnssStatus> queryWrapper = new QueryWrapper<>();
        //queryWrapper.eq("tenantid",tenantId);
        queryWrapper.eq("state",0);
        queryWrapper.eq("deviceid",offDeviceId);
        GnssStatus offDevice = gnssStatusMapper.getByDeviceId(offDeviceId);
        if(offDevice == null) return;

        GnssStatus refDevice1 = gnssStatusMapper.getByDeviceId(refDeviceId1);
        if(refDevice1 == null || refDevice1.getState() == GnssStatus.STATE_OFFLINE) return;
        GnssStatus refDevice2 = gnssStatusMapper.getByDeviceId(refDeviceId2);
        if(refDevice2 == null || refDevice2.getState() == GnssStatus.STATE_OFFLINE) return;

        // 插入数据
        LocalDateTime now = LocalDateTime.now();
        int day = now.getDayOfYear();
        insertData(offDevice, ((day%4)>1)?refDevice1:refDevice2);
    }

    void insertData(GnssStatus offDevice,GnssStatus refDevice){
        logger.info("insertData based on {}",refDevice.getDeviceid());
        QueryWrapper<GnssCalcData> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("deviceid",refDevice.getDeviceid());
        queryWrapper.eq("enabled",true);
        queryWrapper.isNotNull("rpose");
        queryWrapper.orderByDesc("createtime");
        queryWrapper.last("limit 2");
        List<GnssCalcData> refGnssCalcDataList = gnssDataMapper.selectList(queryWrapper);
        if(refGnssCalcDataList.size()>=2){
            double deltaE = refGnssCalcDataList.get(0).getRpose() - refGnssCalcDataList.get(1).getRpose();
            double deltaN = refGnssCalcDataList.get(0).getRposn() - refGnssCalcDataList.get(1).getRposn();
            double deltaD = refGnssCalcDataList.get(0).getRposd() - refGnssCalcDataList.get(1).getRposd();
            logger.info("delta {},{},{}",deltaE,deltaN,deltaD);
            if(Math.abs(deltaE)>1) deltaE = Math.random()*0.2 - 0.1;
            if(Math.abs(deltaN)>1) deltaN = Math.random()*0.2 - 0.1;
            if(Math.abs(deltaD)>2) deltaD = Math.random()*0.4 - 0.2;

            QueryWrapper<GnssCalcData> queryWrapper2 = new QueryWrapper<>();
            queryWrapper2.eq("deviceid",offDevice.getDeviceid());
            queryWrapper2.eq("enabled",true);
            queryWrapper2.isNotNull("rpose");
            queryWrapper2.orderByDesc("createtime");
            queryWrapper2.last("limit 1");
            GnssCalcData offGnssCalcData = gnssDataMapper.selectOne(queryWrapper2);

            GnssCalcData locationRecord = new GnssCalcData();
            locationRecord.setDeviceid(offDevice.getDeviceid());
            locationRecord.setTenantid(tenantId);
            locationRecord.setEnabled(true);
            locationRecord.setCreatetime(LocalDateTime.now());
            locationRecord.setUpdatetime(LocalDateTime.now()); //通过这里可以区分补传记录

            // 调用这个函数之前已判断是否为null
            locationRecord.setB562e(offGnssCalcData.getB562e()+Math.random()*4-2); //mm
            locationRecord.setB562n(offGnssCalcData.getB562n()+Math.random()*4-2);
            locationRecord.setB562d(offGnssCalcData.getB562d()+Math.random()*8-4);

            locationRecord.setRpose(offGnssCalcData.getRpose()+deltaE);
            locationRecord.setRposn(offGnssCalcData.getRposn()+deltaN);
            locationRecord.setRposd(offGnssCalcData.getRposd()+deltaD);
            locationRecord.setPps(-1);//标记为虚拟数据
            gnssDataMapper.insert(locationRecord);
        }
    }
}