/**
 * UdpReceiver.kt
 * SkyLink Android 端 - UDP 接收和数据重组
 *
 * 在单独的协程中运行，负责接收 UDP 数据包、重组分片、解码图像
 *
 * @author flowzl
 * @date 2026-01-19
 */

package com.skylink.app.network

import android.util.Log
import kotlinx.coroutines.*
import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress

/**
 * UDP 接收器回调接口
 */
interface UdpReceiverListener {
    /** 完整帧接收完成 */
    fun onFrameDecoded(frame: DecodedFrame)

    /** 统计信息更新 */
    fun onStatsUpdated(fps: Int, kbps: Int, packetLoss: Double)

    /** 错误发生 */
    fun onError(message: String, exception: Exception? = null)
}

/**
 * UDP 接收器
 */
class UdpReceiver(
    private val listenPort: Int = 9999,
    private val listener: UdpReceiverListener
) {
    companion object {
        private const val TAG = "UdpReceiver"
    }

    private var socket: DatagramSocket? = null
    private var receiverScope: CoroutineScope? = null
    private var isRunning = false

    // UDP 接收缓冲区大小 (2MB) - 增加缓冲区可以有效防止 UDP 丢包
    private val SO_RCVBUF_SIZE = 2 * 1024 * 1024

    // ========================================================================
    // 帧缓冲区管理
    // ========================================================================

    private val frameBuffers = mutableMapOf<Int, FrameBuffer>()
    private var lastCompleteFrameId = 0

    // ========================================================================
    // 统计信息
    // ========================================================================

    private var totalPackets = 0
    private var totalBytes = 0
    private var totalFrames = 0
    private var droppedFrames = 0
    private var packetsThisSecond = 0
    private var bytesThisSecond = 0
    private var lastStatsTime = System.currentTimeMillis()

    /**
     * 启动接收器
     */
    fun start() {
        if (isRunning) {
            return
        }

        isRunning = true
        receiverScope = CoroutineScope(Dispatchers.IO + Job())

        receiverScope?.launch {
            try {
                socket = DatagramSocket(listenPort)
                socket!!.soTimeout = 5000
                
                // 关键优化：增加 Socket 接收缓冲区
                if (socket!!.receiveBufferSize < SO_RCVBUF_SIZE) {
                    socket!!.receiveBufferSize = SO_RCVBUF_SIZE
                    Log.i(TAG, "UDP 接收缓冲区大小已设置为: ${socket!!.receiveBufferSize}")
                }

                Log.i(TAG, "✓ UDP 接收器启动，监听端口 $listenPort")

                startReceiving()
            } catch (e: Exception) {
                Log.e(TAG, "UDP 套接字创建失败", e)
                listener.onError("UDP 套接字创建失败: ${e.message}", e)
                isRunning = false
            }
        }
    }

    /**
     * 停止接收器
     */
    fun stop() {
        isRunning = false
        socket?.close()
        receiverScope?.cancel()
        Log.i(TAG, "UDP 接收器已停止")
    }

    /**
     * 主接收循环
     */
    private suspend fun startReceiving() {
        val buffer = ByteArray(MAX_UDP_PACKET_SIZE)
        val packet = DatagramPacket(buffer, buffer.size)

        while (isRunning) {
            try {
                // 重置 packet 长度，以便接收下一个包
                packet.length = buffer.size
                socket?.receive(packet)

                // 直接处理，避免创建新的 ByteArray 副本
                processPacket(buffer, packet.length)

                // 定期清理和报告统计
                val currentTime = System.currentTimeMillis()
                if (currentTime - lastStatsTime >= 1000) {
                    reportStats()
                    cleanupOldFrames() // 移到定时任务中执行，避免每包检查
                    lastStatsTime = currentTime
                }
            } catch (e: Exception) {
                if (isRunning) {
                    Log.w(TAG, "接收数据异常: ${e.message}")
                }
            }
        }
    }

    /**
     * 处理接收到的 UDP 数据包
     */
    private fun processPacket(buffer: ByteArray, length: Int) {
        if (length < PACKET_HEADER_SIZE) {
            return
        }

        // 解析包头
        // 注意：这里传入的是复用的 buffer，fromByteArray 只读取前 50 字节
        val header = SkyLinkPacketHeader.fromByteArray(buffer) ?: return

        // 验证
        if (!header.isValid()) {
            return
        }
        
        // 计算载荷大小
        val payloadSize = length - PACKET_HEADER_SIZE
        // 简单校验：实际载荷大小应与包头声明一致（或至少不小于）
        if (payloadSize != header.dataLen.toInt()) {
            return
        }

        // 提取载荷
        // 必须拷贝，因为 buffer 会在下一次接收时被覆盖
        val payload = ByteArray(payloadSize)
        System.arraycopy(buffer, PACKET_HEADER_SIZE, payload, 0, payloadSize)

        // 更新统计
        totalPackets++
        totalBytes += length
        bytesThisSecond += length
        packetsThisSecond++

        // 处理分片
        synchronized(frameBuffers) {
            val buffer = frameBuffers.getOrPut(header.frameId.toInt()) {
                FrameBuffer(
                    frameId = header.frameId,
                    totalChunks = header.totalChunks,
                    timestamp = header.timestamp,
                    lat = header.lat,
                    lon = header.lon,
                    alt = header.alt
                )
            }

            // 添加分片
            buffer.chunks[header.chunkIndex.toInt()] = payload

            // 检查是否完整
            if (buffer.isComplete()) {
                handleCompleteFrame(buffer)
                frameBuffers.remove(header.frameId.toInt())
            }
        }
    }

    /**
     * 清理超时的帧
     */
    private fun cleanupOldFrames() {
        synchronized(frameBuffers) {
            frameBuffers.entries.removeIf { (_, fb) ->
                if (fb.isTimeout()) {
                    droppedFrames++
                    true
                } else {
                    false
                }
            }
        }
    }

    /**
     * 处理完整的帧
     */
    private fun handleCompleteFrame(frame: FrameBuffer) {
        try {
            val jpegData = frame.merge()
            val decodedFrame = DecodedFrame(
                frameId = frame.frameId,
                imageData = jpegData,
                timestamp = frame.timestamp,
                lat = frame.lat,
                lon = frame.lon,
                alt = frame.alt
            )

            totalFrames++
            lastCompleteFrameId = frame.frameId

            // 在主线程上回调
            MainScope().launch {
                listener.onFrameDecoded(decodedFrame)
            }
        } catch (e: Exception) {
            Log.e(TAG, "处理完整帧失败", e)
        }
    }

    /**
     * 报告统计信息
     */
    private fun reportStats() {
        val fps = packetsThisSecond / 30  // 粗略估计
        val kbps = bytesThisSecond / 1024
        val packetLoss = if (totalPackets > 0) {
            (droppedFrames.toDouble() / totalFrames.coerceAtLeast(1)) * 100
        } else {
            0.0
        }

        Log.d(TAG, "FPS: $fps, KB/s: $kbps, 总帧: $totalFrames, 丢弃: $droppedFrames")

        MainScope().launch {
            listener.onStatsUpdated(fps, kbps, packetLoss)
        }

        // 重置计数器
        packetsThisSecond = 0
        bytesThisSecond = 0
    }

    /**
     * 获取是否正在运行
     */
    fun isRunning(): Boolean = isRunning
}
