/**
 * @file GroundReceiver.h
 * @brief SkyLink Qt 地面站 - UDP 接收和数据重组头文件
 * 
 * 在单独的线程中运行，负责：
 * 1. 监听 UDP 广播
 * 2. 接收分片数据包
 * 3. 重组完整帧
 * 4. 解码 JPEG 图像
 * 
 * @author flowzl
 * @date 2026-01-19
 */

#pragma once

#include <QObject>
#include <QUdpSocket>
#include <QThread>
#include <QImage>
#include <QMap>
#include <QDebug>
#include <QString>
#include <map>
#include <vector>
#include <memory>
#include <cstdint>
#include <mutex>

// OpenCV for YUYV conversion
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>

#include "protocol.h"

/**
 * @struct FrameBuffer
 * @brief 帧缓冲区，用于重组分片数据
 */
struct FrameBuffer {
    uint32_t frame_id;
    uint16_t total_chunks;
    std::map<uint16_t, std::vector<uint8_t>> chunks;  // chunk_index -> 数据
    double timestamp;
    double lat, lon, alt;
    uint64_t receive_time_ms;
    
    /**
     * @brief 检查是否所有分片都已接收
     */
    bool is_complete() const {
        if (total_chunks == 0) return false;
        for (uint16_t i = 0; i < total_chunks; i++) {
            if (chunks.find(i) == chunks.end()) {
                return false;
            }
        }
        return true;
    }
    
    /**
     * @brief 将所有分片合并为一个字节数组
     * @return 合并后的数据，如果分片不完整返回空vector
     */
    std::vector<uint8_t> merge() const {
        std::vector<uint8_t> result;
        // 预分配空间以提高性能
        size_t estimated_size = chunks.size() * 500; // 估算每个分片约500字节
        result.reserve(estimated_size);
        
        // 调试：检查分片顺序
        QString chunk_indices;
        for (const auto& pair : chunks) {
            chunk_indices += QString::number(pair.first) + " ";
        }
        qDebug() << "帧" << frame_id << "合并前，分片索引:" << chunk_indices;
        
        for (uint16_t i = 0; i < total_chunks; i++) {
            auto it = chunks.find(i);
            if (it != chunks.end()) {
                // 调试：如果是第一个分片，打印前几个字节
                if (i == 0 && !it->second.empty()) {
                    QString hex_preview;
                    for (size_t j = 0; j < std::min((size_t)8, it->second.size()); j++) {
                        hex_preview += QString::number(it->second[j], 16).rightJustified(2, '0') + " ";
                    }
                    qDebug() << "帧" << frame_id << "合并时，分片0前8字节:" << hex_preview;
                }
                result.insert(result.end(), it->second.begin(), it->second.end());
            } else {
                // 如果缺少分片，返回空vector表示不完整
                qWarning() << "帧" << frame_id << "合并时缺少分片" << i;
                return std::vector<uint8_t>();
            }
        }
        return result;
    }
};

/**
 * @class GroundReceiver
 * @brief UDP 接收和数据重组引擎
 */
class GroundReceiver : public QObject {
    Q_OBJECT

public:
    /**
     * @brief 构造函数
     * @param parent 父对象
     * @param port UDP 监听端口 (默认 9999)
     */
    explicit GroundReceiver(QObject* parent = nullptr, uint16_t port = 9999);
    
    /**
     * @brief 析构函数
     */
    ~GroundReceiver();
    
    /**
     * @brief 启动接收器
     */
    void start();
    
    /**
     * @brief 停止接收器
     */
    void stop();
    
    /**
     * @brief 获取是否正在运行
     */
    bool is_running() const;

signals:
    /**
     * @brief 完整帧解码完成信号
     * @param img 解码后的 QImage
     * @param lat 纬度
     * @param lon 经度
     * @param alt 海拔
     */
    void frameDecoded(const QImage& img, double lat, double lon, double alt);
    
    /**
     * @brief 统计信息更新信号
     * @param fps 每秒帧数
     * @param kbs 每秒 KB 数
     */
    void statsUpdated(int fps, int kbs);
    
    /**
     * @brief 错误信号
     * @param error_msg 错误信息
     */
    void error(const QString& error_msg);

private slots:
    /**
     * @brief UDP 有数据可读时的槽函数
     */
    void on_udp_read_ready();
    
    /**
     * @brief 处理 UDP 错误
     */
    void on_udp_error();
    
    /**
     * @brief 定期清理超时的帧
     */
    void on_cleanup_timeout();

private:
    // ========================================================================
    // UDP 套接字和网络
    // ========================================================================
    
    uint16_t listen_port_;
    std::unique_ptr<QUdpSocket> udp_socket_;
    QThread worker_thread_;
    
    // ========================================================================
    // 帧缓冲区管理
    // ========================================================================
    
    std::map<uint32_t, FrameBuffer> frame_buffers_;  // frame_id -> FrameBuffer
    std::mutex frame_buffers_mutex_;
    
    uint32_t last_complete_frame_id_;
    
    // ========================================================================
    // 统计信息
    // ========================================================================
    
    struct {
        uint32_t total_packets = 0;      ///< 总接收包数
        uint32_t total_bytes = 0;        ///< 总接收字节数
        uint32_t total_frames = 0;       ///< 完整帧数
        uint32_t dropped_frames = 0;     ///< 丢弃的帧数
        uint32_t frames_this_second = 0; ///< 本秒帧数
        uint32_t bytes_this_second = 0;  ///< 本秒字节数
        uint64_t last_stats_time = 0;    ///< 上次统计时刻
    } stats_;
    
    std::mutex stats_mutex_;
    
    // ========================================================================
    // 私有方法
    // ========================================================================
    
    /**
     * @brief 处理接收到的 UDP 数据包
     */
    void process_packet(const uint8_t* data, size_t len);
    
    /**
     * @brief 处理完整的帧
     */
    void handle_complete_frame(const FrameBuffer& frame);
    
    /**
     * @brief 从 JPEG 数据解码为 QImage
     */
    QImage decode_jpeg(const std::vector<uint8_t>& data);
    
    /**
     * @brief 从 YUYV 数据转换为 QImage
     * @param yuyv_data YUYV格式的原始数据
     * @param width 图像宽度
     * @param height 图像高度
     * @return 转换后的QImage
     */
    QImage decode_yuyv(const std::vector<uint8_t>& yuyv_data, int width, int height);
    
    /**
     * @brief 清理超时的帧缓冲区
     */
    void cleanup_timeout_frames();
    
    /**
     * @brief 更新和报告统计信息
     */
    void update_stats(uint32_t packet_size);
};
