// MemoryMonitor.swift — NE 进程内存用量周期打点
//
// 职责：
//   1. 周期调用 os_proc_available_memory()（iOS 13+）取 NE 进程剩余可分配内存。
//   2. 通过 task_info(MACH_TASK_BASIC_INFO) 取当前 resident size（兼容 iOS 12）。
//   3. 若 availableMemory < warningThreshold，输出 ⚠️ 警告日志。
//   4. 10 分钟持续运行打点，为 M3 内存上限验收提供数据。
//
// 使用：
//   let monitor = MemoryMonitor()
//   monitor.start()          // 开始打点（启动隧道后调用）
//   monitor.stop()           // 停止打点（隧道停止后调用）
//   monitor.peakResidentBytes // 读取峰值
//
// 参考阈值（NE 进程 jetsam 限制）：
//   旧设备（≤ A9）：~15 MB residual limit
//   新设备（≥ A12）：~50 MB residual limit
//   保守警告线：availableMemory < 5 MB 时认为高风险

import Darwin
import Foundation
import os.log

// ── os_proc_available_memory 声明（iOS 13+ libSystem 符号，低版本回退到 mach）──
// Swift 无法直接引用 os/proc.h 中的符号，用 @_silgen_name 桥接。
@_silgen_name("os_proc_available_memory")
private func _os_proc_available_memory() -> UInt64

// MARK: – MemoryMonitor

final class MemoryMonitor {

    // ── 配置 ────────────────────────────────────────────────────
    /// 打点间隔（默认 10 秒，可在单测中缩短）
    let interval: TimeInterval
    /// 剩余内存警告阈值（默认 5 MB）
    let warningThreshold: UInt64
    /// os.log 子系统
    private let log: OSLog

    // ── 状态 ────────────────────────────────────────────────────
    private var timer: DispatchSourceTimer?
    private let queue = DispatchQueue(label: "com.pangolin.memory-monitor", qos: .utility)
    private(set) var peakResidentBytes: UInt64 = 0
    private(set) var minAvailableBytes: UInt64 = UInt64.max
    private(set) var sampleCount: Int = 0

    init(
        interval: TimeInterval = 10,
        warningThreshold: UInt64 = 5 * 1024 * 1024,
        subsystem: String = "com.pangolin.pangolinVpn.PacketTunnel"
    ) {
        self.interval = interval
        self.warningThreshold = warningThreshold
        self.log = OSLog(subsystem: subsystem, category: "MemoryMonitor")
    }

    // MARK: – 控制

    func start() {
        stop()
        let t = DispatchSource.makeTimerSource(queue: queue)
        t.schedule(deadline: .now(), repeating: interval, leeway: .seconds(1))
        t.setEventHandler { [weak self] in self?.tick() }
        timer = t
        t.resume()
        os_log("MemoryMonitor: 开始打点，间隔=%.0fs", log: log, type: .info, interval)
    }

    func stop() {
        timer?.cancel()
        timer = nil
        os_log(
            "MemoryMonitor: 停止打点。总采样 %d 次 | 峰值 RSS=%.1f MB | 最小可用=%.1f MB",
            log: log, type: .info,
            sampleCount,
            Double(peakResidentBytes) / 1_048_576,
            minAvailableBytes == UInt64.max ? -1.0 : Double(minAvailableBytes) / 1_048_576
        )
    }

    // MARK: – 采样

    private func tick() {
        let resident = residentBytes()
        let available = availableBytes()

        sampleCount += 1
        if resident > peakResidentBytes { peakResidentBytes = resident }
        if available < minAvailableBytes { minAvailableBytes = available }

        let level: OSLogType = available < warningThreshold ? .error : .info
        os_log(
            "MemoryMonitor [#%d] RSS=%.1f MB | 可用=%.1f MB%{public}@",
            log: log, type: level,
            sampleCount,
            Double(resident) / 1_048_576,
            Double(available) / 1_048_576,
            available < warningThreshold ? " ⚠️ 接近上限，建议裁剪 build tags" : ""
        )
    }

    // MARK: – 底层读取

    /// 当前进程 resident size（RSS），iOS 12+ 兼容。
    func residentBytes() -> UInt64 {
        var info = mach_task_basic_info()
        var count = mach_msg_type_number_t(MemoryLayout<mach_task_basic_info>.size / MemoryLayout<integer_t>.size)
        let result: kern_return_t = withUnsafeMutablePointer(to: &info) {
            $0.withMemoryRebound(to: integer_t.self, capacity: Int(count)) {
                task_info(mach_task_self_, task_flavor_t(MACH_TASK_BASIC_INFO), $0, &count)
            }
        }
        return result == KERN_SUCCESS ? UInt64(info.resident_size) : 0
    }

    /// NE 进程剩余可分配内存。
    /// iOS 13+：调用 os_proc_available_memory()。
    /// iOS 12：退而估算 MAX_RSS - resident（不精确，仅供参考）。
    func availableBytes() -> UInt64 {
        if #available(iOS 13.0, *) {
            return _os_proc_available_memory()
        } else {
            // iOS 12 回退：用 15 MB 保守上限 - 当前 RSS
            let conservativeLimit: UInt64 = 15 * 1024 * 1024
            let resident = residentBytes()
            return resident < conservativeLimit ? conservativeLimit - resident : 0
        }
    }

    /// 生成一行摘要字符串（供 handleAppMessage/getStats 返回）。
    func summaryString() -> String {
        let rss = Double(residentBytes()) / 1_048_576
        let avail = Double(availableBytes()) / 1_048_576
        return String(format: "RSS=%.1fMB avail=%.1fMB peak=%.1fMB samples=%d",
                      rss, avail,
                      Double(peakResidentBytes) / 1_048_576,
                      sampleCount)
    }
}
