/**
 * PingUtil.kt
 * SkyLink Android - 网络 Ping 工具
 *
 * 用于 Ping 其他网络设备
 *
 * @author flowzl
 * @date 2026-01-19
 */

package com.skylink.app.utils

import kotlinx.coroutines.*
import java.io.BufferedReader
import java.io.InputStreamReader

data class PingResult(
    val host: String,
    val isSuccess: Boolean,
    val minTime: Long = 0,
    val maxTime: Long = 0,
    val avgTime: Long = 0,
    val packetLoss: Double = 0.0,
    val errorMessage: String = ""
)

class PingUtil {
    companion object {
        private const val TAG = "PingUtil"

        /**
         * Ping 单个主机
         * @param host 目标主机 (IP 地址或域名)
         * @param count Ping 次数，默认为 4
         * @param timeout 超时时间（秒），默认为 5
         * @return PingResult 结果对象
         */
        suspend fun ping(
            host: String,
            count: Int = 4,
            timeout: Int = 5
        ): PingResult = withContext(Dispatchers.IO) {
            return@withContext try {
                // 为了在 Android/Linux 上兼容，使用最基础的参数：-c (count)
                // 不强制使用 -W/-w，避免在不同实现上出错
                val command = arrayOf("ping", "-c", count.toString(), host)

                val process = Runtime.getRuntime().exec(command)

                // 同时读取 stdout 和 stderr，避免阻塞
                val stdout = StringBuilder()
                val stderr = StringBuilder()

                val outReader = BufferedReader(InputStreamReader(process.inputStream))
                val errReader = BufferedReader(InputStreamReader(process.errorStream))

                // 读取 stdout 异步
                val outJob = async {
                    var line: String?
                    val times = mutableListOf<Long>()
                    var successCount = 0

                    val timeRegex = Regex("time[=<]+([\\d.]+)\\s*ms")

                    while (outReader.readLine().also { line = it } != null) {
                        line?.let { l ->
                            stdout.append(l).append('\n')
                            // 解析 time 值（支持小数）
                            val m = timeRegex.find(l)
                            if (m != null) {
                                val tStr = m.groupValues[1]
                                val tDouble = tStr.toDoubleOrNull()
                                if (tDouble != null) {
                                    times.add(tDouble.toLong())
                                    successCount++
                                }
                            }
                        }
                    }

                    Pair(times, successCount)
                }

                // 读取 stderr 异步
                val errJob = async {
                    var line: String?
                    while (errReader.readLine().also { line = it } != null) {
                        line?.let { stderr.append(it).append('\n') }
                    }
                }

                val (times, successCount) = outJob.await()
                errJob.await()

                outReader.close()
                errReader.close()

                // 等待进程结束
                process.waitFor()

                if (successCount > 0) {
                    val minTime = times.minOrNull() ?: 0L
                    val maxTime = times.maxOrNull() ?: 0L
                    val avgTime = if (times.isNotEmpty()) times.average().toLong() else 0L
                    val packetLoss = ((count - successCount) * 100.0) / count

                    PingResult(
                        host = host,
                        isSuccess = true,
                        minTime = minTime,
                        maxTime = maxTime,
                        avgTime = avgTime,
                        packetLoss = packetLoss
                    )
                } else {
                    val errMsg = if (stderr.isNotEmpty()) stderr.toString().trim() else stdout.toString().trim()
                    PingResult(
                        host = host,
                        isSuccess = false,
                        errorMessage = if (errMsg.isNotEmpty()) errMsg else "无法连接到 $host"
                    )
                }
            } catch (e: Exception) {
                PingResult(
                    host = host,
                    isSuccess = false,
                    errorMessage = e.message ?: "未知错误"
                )
            }
        }

        /**
         * Ping 多个主机
         * @param hosts 目标主机列表
         * @param count Ping 次数
         * @param timeout 超时时间
         * @return List<PingResult> 结果列表
         */
        suspend fun pingMultiple(
            hosts: List<String>,
            count: Int = 4,
            timeout: Int = 5
        ): List<PingResult> = withContext(Dispatchers.IO) {
            return@withContext hosts.map { host ->
                ping(host, count, timeout)
            }
        }

        /**
         * 使用协程并行 Ping 多个主机
         * @param hosts 目标主机列表
         * @param count Ping 次数
         * @param timeout 超时时间
         * @return List<PingResult> 结果列表
         */
        suspend fun pingMultipleParallel(
            hosts: List<String>,
            count: Int = 4,
            timeout: Int = 5
        ): List<PingResult> = withContext(Dispatchers.IO) {
            return@withContext hosts.map { host ->
                async { ping(host, count, timeout) }
            }.awaitAll()
        }
    }
}
