package com.imdroid.sideslope.executor;

import com.imdroid.common.util.DataTypeUtil;
import com.imdroid.common.util.ThreadManager;
import com.imdroid.secapi.client.BeidouClient;
import com.imdroid.secapi.dto.GnssDevice;
import com.imdroid.common.util.ByteUtil;
import com.imdroid.sideslope.bd.Gga;
import com.imdroid.sideslope.bd.Rtcm1005;
import com.imdroid.sideslope.message.D331RtcmMessage;
import com.imdroid.sideslope.ntrip.UdpNtripServer;
import com.imdroid.sideslope.service.Device;
import com.imdroid.sideslope.service.DeviceService;
import com.imdroid.sideslope.server.DeviceChannel;
import com.imdroid.sideslope.server.OnlineChannels;
import com.imdroid.sideslope.service.DataPersistService;
import com.imdroid.sideslope.bd.RtcmGgaUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;


/**
 * @author Layton
 * @date 2023/2/2 20:49
 */
@Component
public class D331RtcmMessageExecutor implements Executor<D331RtcmMessage, Void> {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private static final Map<String ,Boolean> deviceBackupStatus = new ConcurrentHashMap<>();

    @Autowired
    private DeviceService deviceService;
    @Autowired
    private BeidouClient beidouClient;
    @Autowired
    private DataPersistService dataPersistService;
    @Autowired
    UdpNtripServer ntripServer;

    // 添加一个成员变量用于追踪每个测站最后一次转发D300数据的时间
    private final Map<String, Long> lastD300ForwardTimeMap = new ConcurrentHashMap<>();
    private static final long D300_FORWARD_INTERVAL = 5000; // 5秒，单位毫秒

    @Override
    public Void execute(D331RtcmMessage message) {
        String id = message.getId();
        // 补齐tenantId
        Device deviceBs = deviceService.findByDeviceId(id);
        if(deviceBs == null || deviceBs.getOpMode() == GnssDevice.OP_MODE_UNUSE || deviceBs.getOpMode() == GnssDevice.OP_MODE_CHECK) {
            logger.warn("基站 {} 不存在或未启用 (opMode: {})", 
                id, deviceBs != null ? deviceBs.getOpMode() : "null");
            return null;
        }

        // 推送基站数据
        if(deviceBs.getOpMode() == GnssDevice.OP_MODE_USE || deviceBs.getOpMode() == null) {
            byte[] forwardBytes = message.getSrcData();
            // 获取使用该基站(包括作为主基站和备选基站)的所有测站
            List<Device> primaryDevices = deviceService.findByParentId(id);
            List<Device> backupDevices = deviceService.findByParentId1(id);

            // 添加调试日志
            logger.info("基站 {} 状态: opMode={}, lastRxTime={}, d3xxCount={}", 
                id, deviceBs.getOpMode(), deviceBs.getLastRxTime(), deviceBs.getD3xxCount());

            if (!primaryDevices.isEmpty() || !backupDevices.isEmpty()) {
                logger.debug("基站 {} 关联的主站设备数: {}, 备站设备数: {}", 
                    id, primaryDevices.size(), backupDevices.size());
            }

            // 合并两个列表
            List<Device> allDevices = new ArrayList<>();
            allDevices.addAll(primaryDevices);
            allDevices.addAll(backupDevices);

            DeviceChannel deviceChannel = null;
            for (Device device : allDevices) {
                if (device.getOpMode() != GnssDevice.OP_MODE_USE) continue;
                if ((device.getModel()==GnssDevice.MODEL_G510) &&
                        (device.getFixedNum()>100) && (device.getGnssSampleRate()>1)
                        && (deviceBs.getD3xxCount()%device.getGnssSampleRate()) != 0) {
                    //if(!UBXUtil.has1005(forwardBytes)) continue; //1005必推
                    continue;
                }
                String deviceId = device.getDeviceId();

                // 检查该设备是否应该接收此基站的数据
                String primaryBaseId = device.getParentId();
                String backupBaseId = device.getParentId1();

                // 添加调试日志
                logger.info("测站 {} 配置信息: 主基站={}, 备用基站={}, 当前数据来自基站={}", 
                    deviceId, primaryBaseId, backupBaseId, id);

                // 如果当前基站是该设备的备选基站，需要检查主基站是否离线
                if (id.equals(backupBaseId)) {
                    Device primaryBase = deviceService.findByDeviceId(primaryBaseId);
                    // 添加调试日志
                    if (primaryBase != null) {
                        logger.info("测站 {} 的主基站 {} 状态: lastRxTime={}, opMode={}", 
                            deviceId, primaryBaseId, 
                            primaryBase.getLastRxTime(), 
                            primaryBase.getOpMode());
                    } else {
                        logger.warn("测站 {} 的主基站 {} 未找到或已删除", deviceId, primaryBaseId);
                    }

                    // 如果主基站仍然在线，则跳过备选基站的数据
                    if (primaryBase != null && isBaseStationOnline(primaryBase)) {
                        if(deviceBackupStatus.remove(deviceId) != null){
                            logger.info("设备 {} 从备用基站 {} 切换回主基站 {}",
                                    deviceId, id, primaryBaseId);
                        }
                        logger.debug("主基站在线，跳过备用基站数据");
                        continue;
                    } else {
                        String hexPrimaryBase = String.format("%06x",Integer.parseInt(primaryBaseId));
                        if(deviceBackupStatus.putIfAbsent(deviceId,true) == null){
                            logger.info("设备 {} 从主基站 {} 切换到备用基站 {} (原因: {})",
                                    deviceId, primaryBaseId, id, 
                                    primaryBase == null ? "主基站不存在" : "主基站离线");
                        }
                        
                        byte[] modifyData = forwardBytes.clone();
                        modifyData[5] = (byte) Integer.parseInt(hexPrimaryBase.substring(0,2),16);
                        modifyData[6] = (byte) Integer.parseInt(hexPrimaryBase.substring(2,4),16);
                        modifyData[7] = (byte) Integer.parseInt(hexPrimaryBase.substring(4,6),16);

                        forwardBytes = modifyData;
                        logger.debug("使用备用基站数据，但保持主基站ID: {}", primaryBaseId);
                    }
                } else if (id.equals(primaryBaseId)) {
                    // 如果是主基站，确保清除备用状态
                    if(deviceBackupStatus.remove(deviceId) != null) {
                        logger.info("设备 {} 恢复使用主基站 {}", deviceId, id);
                    }
                }

                // 添加日志显示当前测站使用的基站
                logger.info("测站 {} 当前使用的基站: {}", deviceId, id);

                // 获取设备通道并发送数据
                if(device.getDataChannelType() == Device.CHANNEL_TYPE_UDP) {
                    deviceChannel = OnlineChannels.INSTANCE.getDataChannel(deviceId);
                } else {
                    deviceChannel = OnlineChannels.INSTANCE.getConfigChannel(deviceId);
                }

                // 读取数据库中model字段，判断基站类型
                Short baseStationModel = deviceBs.getModel();
                // 如果model为null，使用默认值0
                if (baseStationModel == null) {
                    baseStationModel = 0;
                    logger.warn("Base station model is null for device: {}, using default value 0", id);
                }

                if (baseStationModel == 1) {
                    // 基站类型为1，正常执行
                    if(deviceChannel != null && deviceChannel.isOnline()) {
                        if (logger.isDebugEnabled()) {
                            logger.debug("forward d331 rtcm from {} to device {}", id, deviceId);
                        }
                        ByteBuf buf = Unpooled.buffer();
                        buf.writeBytes(forwardBytes);
                        deviceChannel.writeAndFlush(buf);
                    }
                } else if (baseStationModel == 0) {
                    //logger.info("Base station model is 0 for device: {}", deviceId);

                    Short deviceModel = device.getModel();
                    // 如果model为null，使用默认值0
                    if (deviceModel == null) {
                        deviceModel = 0;
                        //logger.warn("Device model is null for device: {}, using default value 0", deviceId);
                    }

                    if(deviceModel == 0){
                        // 测站类型为0，正常执行
                        if(deviceId.startsWith("2307")){
                            // 处理2307型号的测站
                            forwardBytes[2] = (byte) (forwardBytes[2] & 0x07);//兼容不带序号的测站
                        }
                        // 对所有测站类型为0的设备执行转发
                        if(deviceChannel != null && deviceChannel.isOnline()) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("forward d331 rtcm from {} to device {}", id, deviceId);
                            }
                            ByteBuf buf = Unpooled.buffer();
                            buf.writeBytes(forwardBytes);
                            deviceChannel.writeAndFlush(buf);
                        }
                    }
                    else if(deviceModel == 1){
                        //logger.info("Device model is 1 for device: {}", deviceId);

                        if(deviceChannel != null && deviceChannel.isOnline()) {
                            //logger.info("Device channel is online for device: {}", deviceId);

                            ByteBuf buf = Unpooled.buffer();
                            buf.writeBytes(forwardBytes);

                            // 检查是否满足10秒转发间隔，只有满足条件时才添加D300字符串
                            long currentTime = System.currentTimeMillis();
                            Long lastForwardTime = lastD300ForwardTimeMap.getOrDefault(deviceId, 0L);

                            if(currentTime - lastForwardTime >= D300_FORWARD_INTERVAL) {
                                //logger.info("Adding D300 string for device: {}", deviceId);

                                // 获取当前buf中的数据
                                byte[] originalData = buf.array();
                                String originalHex = ByteUtil.bytesToHexString(originalData);

                                // 找到D300和D301的位置
                                int d300Index = originalHex.indexOf("d300");
                                int d301Index = originalHex.indexOf("d301");

                                // 确定插入位置：如果两个都存在，取位置靠前的；如果只存在一个，就用那个位置
                                int insertIndex = -1;
                                if (d300Index != -1 && d301Index != -1) {
                                    // 两个都存在，取位置靠前的
                                    insertIndex = (d300Index < d301Index) ? d300Index : d301Index;
                                    //logger.info("Found both D300 and D301, D300 at {}, D301 at {}, will insert before position {}",
                                     ///       d300Index, d301Index, insertIndex);
                                } else if (d300Index != -1) {
                                    insertIndex = d300Index;
                                    //logger.info("Found D300 at position {}", d300Index);
                                } else if (d301Index != -1) {
                                    insertIndex = d301Index;
                                    //logger.info("Found D301 at position {}", d301Index);
                                }


                                if (insertIndex != -1) {
                                    // 创建新的buf
                                    ByteBuf newBuf = Unpooled.buffer();
                                    // 写入D300/D301之前的数据
                                    newBuf.writeBytes(originalData, 0, insertIndex / 2);

                                    // 使用f9p坐标生成1005消息，并插入
                                    double[] ecef =new double[3];
                                    ecef[0] = deviceBs.getEcefx();
                                    ecef[1] = deviceBs.getEcefy();
                                    ecef[2] = deviceBs.getEcefz();
                                    String rtcm1005 = Rtcm1005.generateRtcm1005Hex(ecef, 0);
                                    if (rtcm1005 != null) {
                                        // 写入RTCM 1005消息
                                        byte[] rtcm1005Bytes = ByteUtil.hexStringTobyte(rtcm1005);
                                        newBuf.writeBytes(rtcm1005Bytes);
                                        // logger.info("Generated RTCM 1005 message for base station {}: {}", deviceBs.getDeviceId(), rtcm1005);
                                    } else {
                                        //logger.warn("Failed to generate RTCM 1005 message for base station: {}", deviceBs.getDeviceId());
                                    }

                                    // 写入剩余的数据
                                    newBuf.writeBytes(originalData, insertIndex / 2, originalData.length - insertIndex / 2);

                                    // 更新buf
                                    buf = newBuf;

                                    // 添加日志，记录插入位置和完整数据
//                                    logger.info("Inserted RTCM 1005 message before position {}, complete data: {}",
//                                            insertIndex,
//                                            ByteUtil.bytesToHexString(buf.array()));
                                }

                                // 更新最后转发时间
                                lastD300ForwardTimeMap.put(deviceId, currentTime);

                                // 添加日志，记录测站转发的完整数据
                                //logger.info("Forward data to device: {}, time: {}, complete data: {}",
                                //       deviceId,
                                //        LocalDateTime.now(),
                                //        ByteUtil.bytesToHexString(buf.array()));
                            }

                            deviceChannel.writeAndFlush(buf);
                        }
                    }
                }
            }
        }

        // 如果30分钟内收到不到d3f0和d3f2，则根据UDP最后一个报文触发状态更新和统计
        if(deviceBs.getD3xxbytes()>0){
            LocalDateTime now = LocalDateTime.now();
            if(deviceBs.getLastRxTime().isBefore(now.minusMinutes(1)) &&
                (deviceBs.getLastD3f2Time() == null ||
                    deviceBs.getLastD3f2Time().isBefore(now.minusMinutes(30)))) {
                // new cycle
                logger.info("device {} rx {} d331 in a cycle while not d3f0f2",deviceBs.getDeviceId(),deviceBs.getD3xxCount());

                Device lastCycleDevice = new Device();
                lastCycleDevice.setDeviceId(deviceBs.getDeviceId());
                lastCycleDevice.setDeviceType(deviceBs.getDeviceType());
                lastCycleDevice.setTenantId(deviceBs.getTenantId());
                lastCycleDevice.setD341bytes(deviceBs.getD341bytes());
                lastCycleDevice.setD341Count(deviceBs.getD341Count());
                lastCycleDevice.setFixedNum(deviceBs.getFixedNum());
                lastCycleDevice.setFloatNum(deviceBs.getFloatNum());
                lastCycleDevice.setNoFixedAndFloatResult(deviceBs.getNoFixedAndFloatResult());
                lastCycleDevice.setLastRxTime(deviceBs.getLastRxTime());
                lastCycleDevice.setLastValidCalcDataTime(deviceBs.getLastValidCalcDataTime());
                lastCycleDevice.setSatelitesInUse(deviceBs.getSatelitesInUse());
                deviceBs.clearStat();
                ThreadManager.getFixedThreadPool().submit(() -> {
                    // 通知上线
                    try {
                        beidouClient.onDeviceActive(deviceBs.getDeviceId(), deviceBs.getTenantId());
                    } catch (Exception e) {
                        logger.error(e.toString());
                    }
                    dataPersistService.updateDeviceState(lastCycleDevice);
                });
            }
        }

        // update trx
        deviceBs.updateRx(message.getHeader(),message.getLen(),message.getPacketNum());
        // update gga
        Gga gga = message.getGga();
        if(gga != null) {
            deviceBs.updateSatelitesNum(gga.getSatellitesInUsed());
            deviceBs.setLatitude(gga.getLatitude());
            deviceBs.setLongitude(gga.getLongitude());
            deviceBs.setAltitude(gga.getAltitude());
        }

        // 添加NTRIP处理
        byte[] srcdata = message.getSrcData();
        String rtcm = ByteUtil.bytesToHexString(srcdata);
        sendToNtrip(id, rtcm);

        ThreadManager.getFixedThreadPool().submit(() -> {
            // 原始码流输出到日志文件 -- INFO 级别
            // 只有测站开了日志记录，或者消息来自基站，才将原码记录到日志文件
            if(deviceBs.getLoggingmode() == GnssDevice.LOGGING_MODE_FULL){
                logger.info("receive {} d331 message: {}", message.getId(), DataTypeUtil.getHexString(message.getSrcData()));
            }
        });

        return null;
    }

    @Override
    public Class<?> getMessageType() {
        return D331RtcmMessage.class;
    }

    private void sendToNtrip(String mountpoint, String hexData) {
        try {

            // 将原始字节转换为16进制字符串用于RTCM提取
            //String hexData = ByteUtil.bytesToHexString(rawData);
            //System.out.println(hexData);

            // 提取RTCM数据并发送到NtripServer,使用设备ID作为挂载点
            Optional.ofNullable(RtcmGgaUtil.getRtcms(hexData))
                    .ifPresent(rtcm -> {
                        //System.out.println("挂载点: " + mountpoint);
                        //System.out.println("RTCM数据: " + rtcm);
                        ntripServer.send(mountpoint, rtcm);
                    });
        } catch (Exception e) {
            logger.error("处理NTRIP数据失败, 挂载点: {}, 错误: {}", mountpoint, e.getMessage());
        }
    }


    /**
     * 判断住基站是否在线
     * @param baseStation 基站
     * @return 是否在线
     */

    private boolean isBaseStationOnline(Device baseStation){
        if(baseStation == null) return false;

        LocalDateTime now = LocalDateTime.now();
        return baseStation.getLastRxTime() != null &&
                baseStation.getLastRxTime().isAfter(now.minusMinutes(5));  // 从30分钟改为5分钟
    }

}
